linux/drivers/net/wireless/ath/ath6kl/wmi.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2004-2011 Atheros Communications Inc.
   3 * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
   4 *
   5 * Permission to use, copy, modify, and/or distribute this software for any
   6 * purpose with or without fee is hereby granted, provided that the above
   7 * copyright notice and this permission notice appear in all copies.
   8 *
   9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16 */
  17
  18#include <linux/ip.h>
  19#include <linux/in.h>
  20#include "core.h"
  21#include "debug.h"
  22#include "testmode.h"
  23#include "trace.h"
  24#include "../regd.h"
  25#include "../regd_common.h"
  26
  27static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx);
  28
  29static const s32 wmi_rate_tbl[][2] = {
  30        /* {W/O SGI, with SGI} */
  31        {1000, 1000},
  32        {2000, 2000},
  33        {5500, 5500},
  34        {11000, 11000},
  35        {6000, 6000},
  36        {9000, 9000},
  37        {12000, 12000},
  38        {18000, 18000},
  39        {24000, 24000},
  40        {36000, 36000},
  41        {48000, 48000},
  42        {54000, 54000},
  43        {6500, 7200},
  44        {13000, 14400},
  45        {19500, 21700},
  46        {26000, 28900},
  47        {39000, 43300},
  48        {52000, 57800},
  49        {58500, 65000},
  50        {65000, 72200},
  51        {13500, 15000},
  52        {27000, 30000},
  53        {40500, 45000},
  54        {54000, 60000},
  55        {81000, 90000},
  56        {108000, 120000},
  57        {121500, 135000},
  58        {135000, 150000},
  59        {0, 0}
  60};
  61
  62/* 802.1d to AC mapping. Refer pg 57 of WMM-test-plan-v1.2 */
  63static const u8 up_to_ac[] = {
  64        WMM_AC_BE,
  65        WMM_AC_BK,
  66        WMM_AC_BK,
  67        WMM_AC_BE,
  68        WMM_AC_VI,
  69        WMM_AC_VI,
  70        WMM_AC_VO,
  71        WMM_AC_VO,
  72};
  73
  74void ath6kl_wmi_set_control_ep(struct wmi *wmi, enum htc_endpoint_id ep_id)
  75{
  76        if (WARN_ON(ep_id == ENDPOINT_UNUSED || ep_id >= ENDPOINT_MAX))
  77                return;
  78
  79        wmi->ep_id = ep_id;
  80}
  81
  82enum htc_endpoint_id ath6kl_wmi_get_control_ep(struct wmi *wmi)
  83{
  84        return wmi->ep_id;
  85}
  86
  87struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx)
  88{
  89        struct ath6kl_vif *vif, *found = NULL;
  90
  91        if (WARN_ON(if_idx > (ar->vif_max - 1)))
  92                return NULL;
  93
  94        /* FIXME: Locking */
  95        spin_lock_bh(&ar->list_lock);
  96        list_for_each_entry(vif, &ar->vif_list, list) {
  97                if (vif->fw_vif_idx == if_idx) {
  98                        found = vif;
  99                        break;
 100                }
 101        }
 102        spin_unlock_bh(&ar->list_lock);
 103
 104        return found;
 105}
 106
 107/*  Performs DIX to 802.3 encapsulation for transmit packets.
 108 *  Assumes the entire DIX header is contigous and that there is
 109 *  enough room in the buffer for a 802.3 mac header and LLC+SNAP headers.
 110 */
 111int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb)
 112{
 113        struct ath6kl_llc_snap_hdr *llc_hdr;
 114        struct ethhdr *eth_hdr;
 115        size_t new_len;
 116        __be16 type;
 117        u8 *datap;
 118        u16 size;
 119
 120        if (WARN_ON(skb == NULL))
 121                return -EINVAL;
 122
 123        size = sizeof(struct ath6kl_llc_snap_hdr) + sizeof(struct wmi_data_hdr);
 124        if (skb_headroom(skb) < size)
 125                return -ENOMEM;
 126
 127        eth_hdr = (struct ethhdr *) skb->data;
 128        type = eth_hdr->h_proto;
 129
 130        if (!is_ethertype(be16_to_cpu(type))) {
 131                ath6kl_dbg(ATH6KL_DBG_WMI,
 132                           "%s: pkt is already in 802.3 format\n", __func__);
 133                return 0;
 134        }
 135
 136        new_len = skb->len - sizeof(*eth_hdr) + sizeof(*llc_hdr);
 137
 138        skb_push(skb, sizeof(struct ath6kl_llc_snap_hdr));
 139        datap = skb->data;
 140
 141        eth_hdr->h_proto = cpu_to_be16(new_len);
 142
 143        memcpy(datap, eth_hdr, sizeof(*eth_hdr));
 144
 145        llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap + sizeof(*eth_hdr));
 146        llc_hdr->dsap = 0xAA;
 147        llc_hdr->ssap = 0xAA;
 148        llc_hdr->cntl = 0x03;
 149        llc_hdr->org_code[0] = 0x0;
 150        llc_hdr->org_code[1] = 0x0;
 151        llc_hdr->org_code[2] = 0x0;
 152        llc_hdr->eth_type = type;
 153
 154        return 0;
 155}
 156
 157static int ath6kl_wmi_meta_add(struct wmi *wmi, struct sk_buff *skb,
 158                               u8 *version, void *tx_meta_info)
 159{
 160        struct wmi_tx_meta_v1 *v1;
 161        struct wmi_tx_meta_v2 *v2;
 162
 163        if (WARN_ON(skb == NULL || version == NULL))
 164                return -EINVAL;
 165
 166        switch (*version) {
 167        case WMI_META_VERSION_1:
 168                skb_push(skb, WMI_MAX_TX_META_SZ);
 169                v1 = (struct wmi_tx_meta_v1 *) skb->data;
 170                v1->pkt_id = 0;
 171                v1->rate_plcy_id = 0;
 172                *version = WMI_META_VERSION_1;
 173                break;
 174        case WMI_META_VERSION_2:
 175                skb_push(skb, WMI_MAX_TX_META_SZ);
 176                v2 = (struct wmi_tx_meta_v2 *) skb->data;
 177                memcpy(v2, (struct wmi_tx_meta_v2 *) tx_meta_info,
 178                       sizeof(struct wmi_tx_meta_v2));
 179                break;
 180        }
 181
 182        return 0;
 183}
 184
 185int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,
 186                            u8 msg_type, u32 flags,
 187                            enum wmi_data_hdr_data_type data_type,
 188                            u8 meta_ver, void *tx_meta_info, u8 if_idx)
 189{
 190        struct wmi_data_hdr *data_hdr;
 191        int ret;
 192
 193        if (WARN_ON(skb == NULL || (if_idx > wmi->parent_dev->vif_max - 1)))
 194                return -EINVAL;
 195
 196        if (tx_meta_info) {
 197                ret = ath6kl_wmi_meta_add(wmi, skb, &meta_ver, tx_meta_info);
 198                if (ret)
 199                        return ret;
 200        }
 201
 202        skb_push(skb, sizeof(struct wmi_data_hdr));
 203
 204        data_hdr = (struct wmi_data_hdr *)skb->data;
 205        memset(data_hdr, 0, sizeof(struct wmi_data_hdr));
 206
 207        data_hdr->info = msg_type << WMI_DATA_HDR_MSG_TYPE_SHIFT;
 208        data_hdr->info |= data_type << WMI_DATA_HDR_DATA_TYPE_SHIFT;
 209
 210        if (flags & WMI_DATA_HDR_FLAGS_MORE)
 211                data_hdr->info |= WMI_DATA_HDR_MORE;
 212
 213        if (flags & WMI_DATA_HDR_FLAGS_EOSP)
 214                data_hdr->info3 |= cpu_to_le16(WMI_DATA_HDR_EOSP);
 215
 216        data_hdr->info2 |= cpu_to_le16(meta_ver << WMI_DATA_HDR_META_SHIFT);
 217        data_hdr->info3 |= cpu_to_le16(if_idx & WMI_DATA_HDR_IF_IDX_MASK);
 218
 219        return 0;
 220}
 221
 222u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri)
 223{
 224        struct iphdr *ip_hdr = (struct iphdr *) pkt;
 225        u8 ip_pri;
 226
 227        /*
 228         * Determine IPTOS priority
 229         *
 230         * IP-TOS - 8bits
 231         *          : DSCP(6-bits) ECN(2-bits)
 232         *          : DSCP - P2 P1 P0 X X X
 233         * where (P2 P1 P0) form 802.1D
 234         */
 235        ip_pri = ip_hdr->tos >> 5;
 236        ip_pri &= 0x7;
 237
 238        if ((layer2_pri & 0x7) > ip_pri)
 239                return (u8) layer2_pri & 0x7;
 240        else
 241                return ip_pri;
 242}
 243
 244u8 ath6kl_wmi_get_traffic_class(u8 user_priority)
 245{
 246        return  up_to_ac[user_priority & 0x7];
 247}
 248
 249int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, u8 if_idx,
 250                                       struct sk_buff *skb,
 251                                       u32 layer2_priority, bool wmm_enabled,
 252                                       u8 *ac)
 253{
 254        struct wmi_data_hdr *data_hdr;
 255        struct ath6kl_llc_snap_hdr *llc_hdr;
 256        struct wmi_create_pstream_cmd cmd;
 257        u32 meta_size, hdr_size;
 258        u16 ip_type = IP_ETHERTYPE;
 259        u8 stream_exist, usr_pri;
 260        u8 traffic_class = WMM_AC_BE;
 261        u8 *datap;
 262
 263        if (WARN_ON(skb == NULL))
 264                return -EINVAL;
 265
 266        datap = skb->data;
 267        data_hdr = (struct wmi_data_hdr *) datap;
 268
 269        meta_size = ((le16_to_cpu(data_hdr->info2) >> WMI_DATA_HDR_META_SHIFT) &
 270                     WMI_DATA_HDR_META_MASK) ? WMI_MAX_TX_META_SZ : 0;
 271
 272        if (!wmm_enabled) {
 273                /* If WMM is disabled all traffic goes as BE traffic */
 274                usr_pri = 0;
 275        } else {
 276                hdr_size = sizeof(struct ethhdr);
 277
 278                llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap +
 279                                                         sizeof(struct
 280                                                                wmi_data_hdr) +
 281                                                         meta_size + hdr_size);
 282
 283                if (llc_hdr->eth_type == htons(ip_type)) {
 284                        /*
 285                         * Extract the endpoint info from the TOS field
 286                         * in the IP header.
 287                         */
 288                        usr_pri =
 289                           ath6kl_wmi_determine_user_priority(((u8 *) llc_hdr) +
 290                                        sizeof(struct ath6kl_llc_snap_hdr),
 291                                        layer2_priority);
 292                } else
 293                        usr_pri = layer2_priority & 0x7;
 294
 295                /*
 296                 * Queue the EAPOL frames in the same WMM_AC_VO queue
 297                 * as that of management frames.
 298                 */
 299                if (skb->protocol == cpu_to_be16(ETH_P_PAE))
 300                        usr_pri = WMI_VOICE_USER_PRIORITY;
 301        }
 302
 303        /*
 304         * workaround for WMM S5
 305         *
 306         * FIXME: wmi->traffic_class is always 100 so this test doesn't
 307         * make sense
 308         */
 309        if ((wmi->traffic_class == WMM_AC_VI) &&
 310            ((usr_pri == 5) || (usr_pri == 4)))
 311                usr_pri = 1;
 312
 313        /* Convert user priority to traffic class */
 314        traffic_class = up_to_ac[usr_pri & 0x7];
 315
 316        wmi_data_hdr_set_up(data_hdr, usr_pri);
 317
 318        spin_lock_bh(&wmi->lock);
 319        stream_exist = wmi->fat_pipe_exist;
 320        spin_unlock_bh(&wmi->lock);
 321
 322        if (!(stream_exist & (1 << traffic_class))) {
 323                memset(&cmd, 0, sizeof(cmd));
 324                cmd.traffic_class = traffic_class;
 325                cmd.user_pri = usr_pri;
 326                cmd.inactivity_int =
 327                        cpu_to_le32(WMI_IMPLICIT_PSTREAM_INACTIVITY_INT);
 328                /* Implicit streams are created with TSID 0xFF */
 329                cmd.tsid = WMI_IMPLICIT_PSTREAM;
 330                ath6kl_wmi_create_pstream_cmd(wmi, if_idx, &cmd);
 331        }
 332
 333        *ac = traffic_class;
 334
 335        return 0;
 336}
 337
 338int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb)
 339{
 340        struct ieee80211_hdr_3addr *pwh, wh;
 341        struct ath6kl_llc_snap_hdr *llc_hdr;
 342        struct ethhdr eth_hdr;
 343        u32 hdr_size;
 344        u8 *datap;
 345        __le16 sub_type;
 346
 347        if (WARN_ON(skb == NULL))
 348                return -EINVAL;
 349
 350        datap = skb->data;
 351        pwh = (struct ieee80211_hdr_3addr *) datap;
 352
 353        sub_type = pwh->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE);
 354
 355        memcpy((u8 *) &wh, datap, sizeof(struct ieee80211_hdr_3addr));
 356
 357        /* Strip off the 802.11 header */
 358        if (sub_type == cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
 359                hdr_size = roundup(sizeof(struct ieee80211_qos_hdr),
 360                                   sizeof(u32));
 361                skb_pull(skb, hdr_size);
 362        } else if (sub_type == cpu_to_le16(IEEE80211_STYPE_DATA))
 363                skb_pull(skb, sizeof(struct ieee80211_hdr_3addr));
 364
 365        datap = skb->data;
 366        llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap);
 367
 368        memset(&eth_hdr, 0, sizeof(eth_hdr));
 369        eth_hdr.h_proto = llc_hdr->eth_type;
 370
 371        switch ((le16_to_cpu(wh.frame_control)) &
 372                (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
 373        case 0:
 374                memcpy(eth_hdr.h_dest, wh.addr1, ETH_ALEN);
 375                memcpy(eth_hdr.h_source, wh.addr2, ETH_ALEN);
 376                break;
 377        case IEEE80211_FCTL_TODS:
 378                memcpy(eth_hdr.h_dest, wh.addr3, ETH_ALEN);
 379                memcpy(eth_hdr.h_source, wh.addr2, ETH_ALEN);
 380                break;
 381        case IEEE80211_FCTL_FROMDS:
 382                memcpy(eth_hdr.h_dest, wh.addr1, ETH_ALEN);
 383                memcpy(eth_hdr.h_source, wh.addr3, ETH_ALEN);
 384                break;
 385        case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
 386                break;
 387        }
 388
 389        skb_pull(skb, sizeof(struct ath6kl_llc_snap_hdr));
 390        skb_push(skb, sizeof(eth_hdr));
 391
 392        datap = skb->data;
 393
 394        memcpy(datap, &eth_hdr, sizeof(eth_hdr));
 395
 396        return 0;
 397}
 398
 399/*
 400 * Performs 802.3 to DIX encapsulation for received packets.
 401 * Assumes the entire 802.3 header is contigous.
 402 */
 403int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb)
 404{
 405        struct ath6kl_llc_snap_hdr *llc_hdr;
 406        struct ethhdr eth_hdr;
 407        u8 *datap;
 408
 409        if (WARN_ON(skb == NULL))
 410                return -EINVAL;
 411
 412        datap = skb->data;
 413
 414        memcpy(&eth_hdr, datap, sizeof(eth_hdr));
 415
 416        llc_hdr = (struct ath6kl_llc_snap_hdr *) (datap + sizeof(eth_hdr));
 417        eth_hdr.h_proto = llc_hdr->eth_type;
 418
 419        skb_pull(skb, sizeof(struct ath6kl_llc_snap_hdr));
 420        datap = skb->data;
 421
 422        memcpy(datap, &eth_hdr, sizeof(eth_hdr));
 423
 424        return 0;
 425}
 426
 427static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len)
 428{
 429        struct tx_complete_msg_v1 *msg_v1;
 430        struct wmi_tx_complete_event *evt;
 431        int index;
 432        u16 size;
 433
 434        evt = (struct wmi_tx_complete_event *) datap;
 435
 436        ath6kl_dbg(ATH6KL_DBG_WMI, "comp: %d %d %d\n",
 437                   evt->num_msg, evt->msg_len, evt->msg_type);
 438
 439        for (index = 0; index < evt->num_msg; index++) {
 440                size = sizeof(struct wmi_tx_complete_event) +
 441                    (index * sizeof(struct tx_complete_msg_v1));
 442                msg_v1 = (struct tx_complete_msg_v1 *)(datap + size);
 443
 444                ath6kl_dbg(ATH6KL_DBG_WMI, "msg: %d %d %d %d\n",
 445                           msg_v1->status, msg_v1->pkt_id,
 446                           msg_v1->rate_idx, msg_v1->ack_failures);
 447        }
 448
 449        return 0;
 450}
 451
 452static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap,
 453                                              int len, struct ath6kl_vif *vif)
 454{
 455        struct wmi_remain_on_chnl_event *ev;
 456        u32 freq;
 457        u32 dur;
 458        struct ieee80211_channel *chan;
 459        struct ath6kl *ar = wmi->parent_dev;
 460        u32 id;
 461
 462        if (len < sizeof(*ev))
 463                return -EINVAL;
 464
 465        ev = (struct wmi_remain_on_chnl_event *) datap;
 466        freq = le32_to_cpu(ev->freq);
 467        dur = le32_to_cpu(ev->duration);
 468        ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl: freq=%u dur=%u\n",
 469                   freq, dur);
 470        chan = ieee80211_get_channel(ar->wiphy, freq);
 471        if (!chan) {
 472                ath6kl_dbg(ATH6KL_DBG_WMI,
 473                           "remain_on_chnl: Unknown channel (freq=%u)\n",
 474                           freq);
 475                return -EINVAL;
 476        }
 477        id = vif->last_roc_id;
 478        cfg80211_ready_on_channel(&vif->wdev, id, chan,
 479                                  dur, GFP_ATOMIC);
 480
 481        return 0;
 482}
 483
 484static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi,
 485                                                     u8 *datap, int len,
 486                                                     struct ath6kl_vif *vif)
 487{
 488        struct wmi_cancel_remain_on_chnl_event *ev;
 489        u32 freq;
 490        u32 dur;
 491        struct ieee80211_channel *chan;
 492        struct ath6kl *ar = wmi->parent_dev;
 493        u32 id;
 494
 495        if (len < sizeof(*ev))
 496                return -EINVAL;
 497
 498        ev = (struct wmi_cancel_remain_on_chnl_event *) datap;
 499        freq = le32_to_cpu(ev->freq);
 500        dur = le32_to_cpu(ev->duration);
 501        ath6kl_dbg(ATH6KL_DBG_WMI,
 502                   "cancel_remain_on_chnl: freq=%u dur=%u status=%u\n",
 503                   freq, dur, ev->status);
 504        chan = ieee80211_get_channel(ar->wiphy, freq);
 505        if (!chan) {
 506                ath6kl_dbg(ATH6KL_DBG_WMI,
 507                           "cancel_remain_on_chnl: Unknown channel (freq=%u)\n",
 508                           freq);
 509                return -EINVAL;
 510        }
 511        if (vif->last_cancel_roc_id &&
 512            vif->last_cancel_roc_id + 1 == vif->last_roc_id)
 513                id = vif->last_cancel_roc_id; /* event for cancel command */
 514        else
 515                id = vif->last_roc_id; /* timeout on uncanceled r-o-c */
 516        vif->last_cancel_roc_id = 0;
 517        cfg80211_remain_on_channel_expired(&vif->wdev, id, chan, GFP_ATOMIC);
 518
 519        return 0;
 520}
 521
 522static int ath6kl_wmi_tx_status_event_rx(struct wmi *wmi, u8 *datap, int len,
 523                                         struct ath6kl_vif *vif)
 524{
 525        struct wmi_tx_status_event *ev;
 526        u32 id;
 527
 528        if (len < sizeof(*ev))
 529                return -EINVAL;
 530
 531        ev = (struct wmi_tx_status_event *) datap;
 532        id = le32_to_cpu(ev->id);
 533        ath6kl_dbg(ATH6KL_DBG_WMI, "tx_status: id=%x ack_status=%u\n",
 534                   id, ev->ack_status);
 535        if (wmi->last_mgmt_tx_frame) {
 536                cfg80211_mgmt_tx_status(&vif->wdev, id,
 537                                        wmi->last_mgmt_tx_frame,
 538                                        wmi->last_mgmt_tx_frame_len,
 539                                        !!ev->ack_status, GFP_ATOMIC);
 540                kfree(wmi->last_mgmt_tx_frame);
 541                wmi->last_mgmt_tx_frame = NULL;
 542                wmi->last_mgmt_tx_frame_len = 0;
 543        }
 544
 545        return 0;
 546}
 547
 548static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len,
 549                                            struct ath6kl_vif *vif)
 550{
 551        struct wmi_p2p_rx_probe_req_event *ev;
 552        u32 freq;
 553        u16 dlen;
 554
 555        if (len < sizeof(*ev))
 556                return -EINVAL;
 557
 558        ev = (struct wmi_p2p_rx_probe_req_event *) datap;
 559        freq = le32_to_cpu(ev->freq);
 560        dlen = le16_to_cpu(ev->len);
 561        if (datap + len < ev->data + dlen) {
 562                ath6kl_err("invalid wmi_p2p_rx_probe_req_event: len=%d dlen=%u\n",
 563                           len, dlen);
 564                return -EINVAL;
 565        }
 566        ath6kl_dbg(ATH6KL_DBG_WMI,
 567                   "rx_probe_req: len=%u freq=%u probe_req_report=%d\n",
 568                   dlen, freq, vif->probe_req_report);
 569
 570        if (vif->probe_req_report || vif->nw_type == AP_NETWORK)
 571                cfg80211_rx_mgmt(&vif->wdev, freq, 0,
 572                                 ev->data, dlen, GFP_ATOMIC);
 573
 574        return 0;
 575}
 576
 577static int ath6kl_wmi_p2p_capabilities_event_rx(u8 *datap, int len)
 578{
 579        struct wmi_p2p_capabilities_event *ev;
 580        u16 dlen;
 581
 582        if (len < sizeof(*ev))
 583                return -EINVAL;
 584
 585        ev = (struct wmi_p2p_capabilities_event *) datap;
 586        dlen = le16_to_cpu(ev->len);
 587        ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_capab: len=%u\n", dlen);
 588
 589        return 0;
 590}
 591
 592static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len,
 593                                         struct ath6kl_vif *vif)
 594{
 595        struct wmi_rx_action_event *ev;
 596        u32 freq;
 597        u16 dlen;
 598
 599        if (len < sizeof(*ev))
 600                return -EINVAL;
 601
 602        ev = (struct wmi_rx_action_event *) datap;
 603        freq = le32_to_cpu(ev->freq);
 604        dlen = le16_to_cpu(ev->len);
 605        if (datap + len < ev->data + dlen) {
 606                ath6kl_err("invalid wmi_rx_action_event: len=%d dlen=%u\n",
 607                           len, dlen);
 608                return -EINVAL;
 609        }
 610        ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq);
 611        cfg80211_rx_mgmt(&vif->wdev, freq, 0,
 612                         ev->data, dlen, GFP_ATOMIC);
 613
 614        return 0;
 615}
 616
 617static int ath6kl_wmi_p2p_info_event_rx(u8 *datap, int len)
 618{
 619        struct wmi_p2p_info_event *ev;
 620        u32 flags;
 621        u16 dlen;
 622
 623        if (len < sizeof(*ev))
 624                return -EINVAL;
 625
 626        ev = (struct wmi_p2p_info_event *) datap;
 627        flags = le32_to_cpu(ev->info_req_flags);
 628        dlen = le16_to_cpu(ev->len);
 629        ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: flags=%x len=%d\n", flags, dlen);
 630
 631        if (flags & P2P_FLAG_CAPABILITIES_REQ) {
 632                struct wmi_p2p_capabilities *cap;
 633                if (dlen < sizeof(*cap))
 634                        return -EINVAL;
 635                cap = (struct wmi_p2p_capabilities *) ev->data;
 636                ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: GO Power Save = %d\n",
 637                           cap->go_power_save);
 638        }
 639
 640        if (flags & P2P_FLAG_MACADDR_REQ) {
 641                struct wmi_p2p_macaddr *mac;
 642                if (dlen < sizeof(*mac))
 643                        return -EINVAL;
 644                mac = (struct wmi_p2p_macaddr *) ev->data;
 645                ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: MAC Address = %pM\n",
 646                           mac->mac_addr);
 647        }
 648
 649        if (flags & P2P_FLAG_HMODEL_REQ) {
 650                struct wmi_p2p_hmodel *mod;
 651                if (dlen < sizeof(*mod))
 652                        return -EINVAL;
 653                mod = (struct wmi_p2p_hmodel *) ev->data;
 654                ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: P2P Model = %d (%s)\n",
 655                           mod->p2p_model,
 656                           mod->p2p_model ? "host" : "firmware");
 657        }
 658        return 0;
 659}
 660
 661static inline struct sk_buff *ath6kl_wmi_get_new_buf(u32 size)
 662{
 663        struct sk_buff *skb;
 664
 665        skb = ath6kl_buf_alloc(size);
 666        if (!skb)
 667                return NULL;
 668
 669        skb_put(skb, size);
 670        if (size)
 671                memset(skb->data, 0, size);
 672
 673        return skb;
 674}
 675
 676/* Send a "simple" wmi command -- one with no arguments */
 677static int ath6kl_wmi_simple_cmd(struct wmi *wmi, u8 if_idx,
 678                                 enum wmi_cmd_id cmd_id)
 679{
 680        struct sk_buff *skb;
 681        int ret;
 682
 683        skb = ath6kl_wmi_get_new_buf(0);
 684        if (!skb)
 685                return -ENOMEM;
 686
 687        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, cmd_id, NO_SYNC_WMIFLAG);
 688
 689        return ret;
 690}
 691
 692static int ath6kl_wmi_ready_event_rx(struct wmi *wmi, u8 *datap, int len)
 693{
 694        struct wmi_ready_event_2 *ev = (struct wmi_ready_event_2 *) datap;
 695
 696        if (len < sizeof(struct wmi_ready_event_2))
 697                return -EINVAL;
 698
 699        ath6kl_ready_event(wmi->parent_dev, ev->mac_addr,
 700                           le32_to_cpu(ev->sw_version),
 701                           le32_to_cpu(ev->abi_version), ev->phy_cap);
 702
 703        return 0;
 704}
 705
 706/*
 707 * Mechanism to modify the roaming behavior in the firmware. The lower rssi
 708 * at which the station has to roam can be passed with
 709 * WMI_SET_LRSSI_SCAN_PARAMS. Subtract 96 from RSSI to get the signal level
 710 * in dBm.
 711 */
 712int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi)
 713{
 714        struct sk_buff *skb;
 715        struct roam_ctrl_cmd *cmd;
 716
 717        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
 718        if (!skb)
 719                return -ENOMEM;
 720
 721        cmd = (struct roam_ctrl_cmd *) skb->data;
 722
 723        cmd->info.params.lrssi_scan_period = cpu_to_le16(DEF_LRSSI_SCAN_PERIOD);
 724        cmd->info.params.lrssi_scan_threshold = a_cpu_to_sle16(lrssi +
 725                                                       DEF_SCAN_FOR_ROAM_INTVL);
 726        cmd->info.params.lrssi_roam_threshold = a_cpu_to_sle16(lrssi);
 727        cmd->info.params.roam_rssi_floor = DEF_LRSSI_ROAM_FLOOR;
 728        cmd->roam_ctrl = WMI_SET_LRSSI_SCAN_PARAMS;
 729
 730        ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_ROAM_CTRL_CMDID,
 731                            NO_SYNC_WMIFLAG);
 732
 733        return 0;
 734}
 735
 736int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid)
 737{
 738        struct sk_buff *skb;
 739        struct roam_ctrl_cmd *cmd;
 740
 741        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
 742        if (!skb)
 743                return -ENOMEM;
 744
 745        cmd = (struct roam_ctrl_cmd *) skb->data;
 746
 747        memcpy(cmd->info.bssid, bssid, ETH_ALEN);
 748        cmd->roam_ctrl = WMI_FORCE_ROAM;
 749
 750        ath6kl_dbg(ATH6KL_DBG_WMI, "force roam to %pM\n", bssid);
 751        return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_ROAM_CTRL_CMDID,
 752                                   NO_SYNC_WMIFLAG);
 753}
 754
 755int ath6kl_wmi_ap_set_beacon_intvl_cmd(struct wmi *wmi, u8 if_idx,
 756                                       u32 beacon_intvl)
 757{
 758        struct sk_buff *skb;
 759        struct set_beacon_int_cmd *cmd;
 760
 761        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
 762        if (!skb)
 763                return -ENOMEM;
 764
 765        cmd = (struct set_beacon_int_cmd *) skb->data;
 766
 767        cmd->beacon_intvl = cpu_to_le32(beacon_intvl);
 768        return ath6kl_wmi_cmd_send(wmi, if_idx, skb,
 769                                   WMI_SET_BEACON_INT_CMDID, NO_SYNC_WMIFLAG);
 770}
 771
 772int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period)
 773{
 774        struct sk_buff *skb;
 775        struct set_dtim_cmd *cmd;
 776
 777        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
 778        if (!skb)
 779                return -ENOMEM;
 780
 781        cmd = (struct set_dtim_cmd *) skb->data;
 782
 783        cmd->dtim_period = cpu_to_le32(dtim_period);
 784        return ath6kl_wmi_cmd_send(wmi, if_idx, skb,
 785                                   WMI_AP_SET_DTIM_CMDID, NO_SYNC_WMIFLAG);
 786}
 787
 788int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode)
 789{
 790        struct sk_buff *skb;
 791        struct roam_ctrl_cmd *cmd;
 792
 793        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
 794        if (!skb)
 795                return -ENOMEM;
 796
 797        cmd = (struct roam_ctrl_cmd *) skb->data;
 798
 799        cmd->info.roam_mode = mode;
 800        cmd->roam_ctrl = WMI_SET_ROAM_MODE;
 801
 802        ath6kl_dbg(ATH6KL_DBG_WMI, "set roam mode %d\n", mode);
 803        return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_ROAM_CTRL_CMDID,
 804                                   NO_SYNC_WMIFLAG);
 805}
 806
 807static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len,
 808                                       struct ath6kl_vif *vif)
 809{
 810        struct wmi_connect_event *ev;
 811        u8 *pie, *peie;
 812
 813        if (len < sizeof(struct wmi_connect_event))
 814                return -EINVAL;
 815
 816        ev = (struct wmi_connect_event *) datap;
 817
 818        if (vif->nw_type == AP_NETWORK) {
 819                /* AP mode start/STA connected event */
 820                struct net_device *dev = vif->ndev;
 821                if (memcmp(dev->dev_addr, ev->u.ap_bss.bssid, ETH_ALEN) == 0) {
 822                        ath6kl_dbg(ATH6KL_DBG_WMI,
 823                                   "%s: freq %d bssid %pM (AP started)\n",
 824                                   __func__, le16_to_cpu(ev->u.ap_bss.ch),
 825                                   ev->u.ap_bss.bssid);
 826                        ath6kl_connect_ap_mode_bss(
 827                                vif, le16_to_cpu(ev->u.ap_bss.ch));
 828                } else {
 829                        ath6kl_dbg(ATH6KL_DBG_WMI,
 830                                   "%s: aid %u mac_addr %pM auth=%u keymgmt=%u cipher=%u apsd_info=%u (STA connected)\n",
 831                                   __func__, ev->u.ap_sta.aid,
 832                                   ev->u.ap_sta.mac_addr,
 833                                   ev->u.ap_sta.auth,
 834                                   ev->u.ap_sta.keymgmt,
 835                                   le16_to_cpu(ev->u.ap_sta.cipher),
 836                                   ev->u.ap_sta.apsd_info);
 837
 838                        ath6kl_connect_ap_mode_sta(
 839                                vif, ev->u.ap_sta.aid, ev->u.ap_sta.mac_addr,
 840                                ev->u.ap_sta.keymgmt,
 841                                le16_to_cpu(ev->u.ap_sta.cipher),
 842                                ev->u.ap_sta.auth, ev->assoc_req_len,
 843                                ev->assoc_info + ev->beacon_ie_len,
 844                                ev->u.ap_sta.apsd_info);
 845                }
 846                return 0;
 847        }
 848
 849        /* STA/IBSS mode connection event */
 850
 851        ath6kl_dbg(ATH6KL_DBG_WMI,
 852                   "wmi event connect freq %d bssid %pM listen_intvl %d beacon_intvl %d type %d\n",
 853                   le16_to_cpu(ev->u.sta.ch), ev->u.sta.bssid,
 854                   le16_to_cpu(ev->u.sta.listen_intvl),
 855                   le16_to_cpu(ev->u.sta.beacon_intvl),
 856                   le32_to_cpu(ev->u.sta.nw_type));
 857
 858        /* Start of assoc rsp IEs */
 859        pie = ev->assoc_info + ev->beacon_ie_len +
 860              ev->assoc_req_len + (sizeof(u16) * 3); /* capinfo, status, aid */
 861
 862        /* End of assoc rsp IEs */
 863        peie = ev->assoc_info + ev->beacon_ie_len + ev->assoc_req_len +
 864            ev->assoc_resp_len;
 865
 866        while (pie < peie) {
 867                switch (*pie) {
 868                case WLAN_EID_VENDOR_SPECIFIC:
 869                        if (pie[1] > 3 && pie[2] == 0x00 && pie[3] == 0x50 &&
 870                            pie[4] == 0xf2 && pie[5] == WMM_OUI_TYPE) {
 871                                /* WMM OUT (00:50:F2) */
 872                                if (pie[1] > 5 &&
 873                                    pie[6] == WMM_PARAM_OUI_SUBTYPE)
 874                                        wmi->is_wmm_enabled = true;
 875                        }
 876                        break;
 877                }
 878
 879                if (wmi->is_wmm_enabled)
 880                        break;
 881
 882                pie += pie[1] + 2;
 883        }
 884
 885        ath6kl_connect_event(vif, le16_to_cpu(ev->u.sta.ch),
 886                             ev->u.sta.bssid,
 887                             le16_to_cpu(ev->u.sta.listen_intvl),
 888                             le16_to_cpu(ev->u.sta.beacon_intvl),
 889                             le32_to_cpu(ev->u.sta.nw_type),
 890                             ev->beacon_ie_len, ev->assoc_req_len,
 891                             ev->assoc_resp_len, ev->assoc_info);
 892
 893        return 0;
 894}
 895
 896static struct country_code_to_enum_rd *
 897ath6kl_regd_find_country(u16 countryCode)
 898{
 899        int i;
 900
 901        for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
 902                if (allCountries[i].countryCode == countryCode)
 903                        return &allCountries[i];
 904        }
 905
 906        return NULL;
 907}
 908
 909static struct reg_dmn_pair_mapping *
 910ath6kl_get_regpair(u16 regdmn)
 911{
 912        int i;
 913
 914        if (regdmn == NO_ENUMRD)
 915                return NULL;
 916
 917        for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
 918                if (regDomainPairs[i].regDmnEnum == regdmn)
 919                        return &regDomainPairs[i];
 920        }
 921
 922        return NULL;
 923}
 924
 925static struct country_code_to_enum_rd *
 926ath6kl_regd_find_country_by_rd(u16 regdmn)
 927{
 928        int i;
 929
 930        for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
 931                if (allCountries[i].regDmnEnum == regdmn)
 932                        return &allCountries[i];
 933        }
 934
 935        return NULL;
 936}
 937
 938static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len)
 939{
 940
 941        struct ath6kl_wmi_regdomain *ev;
 942        struct country_code_to_enum_rd *country = NULL;
 943        struct reg_dmn_pair_mapping *regpair = NULL;
 944        char alpha2[2];
 945        u32 reg_code;
 946
 947        ev = (struct ath6kl_wmi_regdomain *) datap;
 948        reg_code = le32_to_cpu(ev->reg_code);
 949
 950        if ((reg_code >> ATH6KL_COUNTRY_RD_SHIFT) & COUNTRY_ERD_FLAG)
 951                country = ath6kl_regd_find_country((u16) reg_code);
 952        else if (!(((u16) reg_code & WORLD_SKU_MASK) == WORLD_SKU_PREFIX)) {
 953
 954                regpair = ath6kl_get_regpair((u16) reg_code);
 955                country = ath6kl_regd_find_country_by_rd((u16) reg_code);
 956                if (regpair)
 957                        ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n",
 958                                   regpair->regDmnEnum);
 959                else
 960                        ath6kl_warn("Regpair not found reg_code 0x%0x\n",
 961                                    reg_code);
 962        }
 963
 964        if (country && wmi->parent_dev->wiphy_registered) {
 965                alpha2[0] = country->isoName[0];
 966                alpha2[1] = country->isoName[1];
 967
 968                regulatory_hint(wmi->parent_dev->wiphy, alpha2);
 969
 970                ath6kl_dbg(ATH6KL_DBG_WMI, "Country alpha2 being used: %c%c\n",
 971                           alpha2[0], alpha2[1]);
 972        }
 973}
 974
 975static int ath6kl_wmi_disconnect_event_rx(struct wmi *wmi, u8 *datap, int len,
 976                                          struct ath6kl_vif *vif)
 977{
 978        struct wmi_disconnect_event *ev;
 979        wmi->traffic_class = 100;
 980
 981        if (len < sizeof(struct wmi_disconnect_event))
 982                return -EINVAL;
 983
 984        ev = (struct wmi_disconnect_event *) datap;
 985
 986        ath6kl_dbg(ATH6KL_DBG_WMI,
 987                   "wmi event disconnect proto_reason %d bssid %pM wmi_reason %d assoc_resp_len %d\n",
 988                   le16_to_cpu(ev->proto_reason_status), ev->bssid,
 989                   ev->disconn_reason, ev->assoc_resp_len);
 990
 991        wmi->is_wmm_enabled = false;
 992
 993        ath6kl_disconnect_event(vif, ev->disconn_reason,
 994                                ev->bssid, ev->assoc_resp_len, ev->assoc_info,
 995                                le16_to_cpu(ev->proto_reason_status));
 996
 997        return 0;
 998}
 999
1000static int ath6kl_wmi_peer_node_event_rx(struct wmi *wmi, u8 *datap, int len)
1001{
1002        struct wmi_peer_node_event *ev;
1003
1004        if (len < sizeof(struct wmi_peer_node_event))
1005                return -EINVAL;
1006
1007        ev = (struct wmi_peer_node_event *) datap;
1008
1009        if (ev->event_code == PEER_NODE_JOIN_EVENT)
1010                ath6kl_dbg(ATH6KL_DBG_WMI, "joined node with mac addr: %pM\n",
1011                           ev->peer_mac_addr);
1012        else if (ev->event_code == PEER_NODE_LEAVE_EVENT)
1013                ath6kl_dbg(ATH6KL_DBG_WMI, "left node with mac addr: %pM\n",
1014                           ev->peer_mac_addr);
1015
1016        return 0;
1017}
1018
1019static int ath6kl_wmi_tkip_micerr_event_rx(struct wmi *wmi, u8 *datap, int len,
1020                                           struct ath6kl_vif *vif)
1021{
1022        struct wmi_tkip_micerr_event *ev;
1023
1024        if (len < sizeof(struct wmi_tkip_micerr_event))
1025                return -EINVAL;
1026
1027        ev = (struct wmi_tkip_micerr_event *) datap;
1028
1029        ath6kl_tkip_micerr_event(vif, ev->key_id, ev->is_mcast);
1030
1031        return 0;
1032}
1033
1034void ath6kl_wmi_sscan_timer(unsigned long ptr)
1035{
1036        struct ath6kl_vif *vif = (struct ath6kl_vif *) ptr;
1037
1038        cfg80211_sched_scan_results(vif->ar->wiphy);
1039}
1040
1041static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
1042                                       struct ath6kl_vif *vif)
1043{
1044        struct wmi_bss_info_hdr2 *bih;
1045        u8 *buf;
1046        struct ieee80211_channel *channel;
1047        struct ath6kl *ar = wmi->parent_dev;
1048        struct ieee80211_mgmt *mgmt;
1049        struct cfg80211_bss *bss;
1050
1051        if (len <= sizeof(struct wmi_bss_info_hdr2))
1052                return -EINVAL;
1053
1054        bih = (struct wmi_bss_info_hdr2 *) datap;
1055        buf = datap + sizeof(struct wmi_bss_info_hdr2);
1056        len -= sizeof(struct wmi_bss_info_hdr2);
1057
1058        ath6kl_dbg(ATH6KL_DBG_WMI,
1059                   "bss info evt - ch %u, snr %d, rssi %d, bssid \"%pM\" "
1060                   "frame_type=%d\n",
1061                   bih->ch, bih->snr, bih->snr - 95, bih->bssid,
1062                   bih->frame_type);
1063
1064        if (bih->frame_type != BEACON_FTYPE &&
1065            bih->frame_type != PROBERESP_FTYPE)
1066                return 0; /* Only update BSS table for now */
1067
1068        if (bih->frame_type == BEACON_FTYPE &&
1069            test_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags)) {
1070                clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
1071                ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
1072                                         NONE_BSS_FILTER, 0);
1073        }
1074
1075        channel = ieee80211_get_channel(ar->wiphy, le16_to_cpu(bih->ch));
1076        if (channel == NULL)
1077                return -EINVAL;
1078
1079        if (len < 8 + 2 + 2)
1080                return -EINVAL;
1081
1082        if (bih->frame_type == BEACON_FTYPE &&
1083            test_bit(CONNECTED, &vif->flags) &&
1084            memcmp(bih->bssid, vif->bssid, ETH_ALEN) == 0) {
1085                const u8 *tim;
1086                tim = cfg80211_find_ie(WLAN_EID_TIM, buf + 8 + 2 + 2,
1087                                       len - 8 - 2 - 2);
1088                if (tim && tim[1] >= 2) {
1089                        vif->assoc_bss_dtim_period = tim[3];
1090                        set_bit(DTIM_PERIOD_AVAIL, &vif->flags);
1091                }
1092        }
1093
1094        /*
1095         * In theory, use of cfg80211_inform_bss() would be more natural here
1096         * since we do not have the full frame. However, at least for now,
1097         * cfg80211 can only distinguish Beacon and Probe Response frames from
1098         * each other when using cfg80211_inform_bss_frame(), so let's build a
1099         * fake IEEE 802.11 header to be able to take benefit of this.
1100         */
1101        mgmt = kmalloc(24 + len, GFP_ATOMIC);
1102        if (mgmt == NULL)
1103                return -EINVAL;
1104
1105        if (bih->frame_type == BEACON_FTYPE) {
1106                mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
1107                                                  IEEE80211_STYPE_BEACON);
1108                memset(mgmt->da, 0xff, ETH_ALEN);
1109        } else {
1110                struct net_device *dev = vif->ndev;
1111
1112                mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
1113                                                  IEEE80211_STYPE_PROBE_RESP);
1114                memcpy(mgmt->da, dev->dev_addr, ETH_ALEN);
1115        }
1116        mgmt->duration = cpu_to_le16(0);
1117        memcpy(mgmt->sa, bih->bssid, ETH_ALEN);
1118        memcpy(mgmt->bssid, bih->bssid, ETH_ALEN);
1119        mgmt->seq_ctrl = cpu_to_le16(0);
1120
1121        memcpy(&mgmt->u.beacon, buf, len);
1122
1123        bss = cfg80211_inform_bss_frame(ar->wiphy, channel, mgmt,
1124                                        24 + len, (bih->snr - 95) * 100,
1125                                        GFP_ATOMIC);
1126        kfree(mgmt);
1127        if (bss == NULL)
1128                return -ENOMEM;
1129        cfg80211_put_bss(ar->wiphy, bss);
1130
1131        /*
1132         * Firmware doesn't return any event when scheduled scan has
1133         * finished, so we need to use a timer to find out when there are
1134         * no more results.
1135         *
1136         * The timer is started from the first bss info received, otherwise
1137         * the timer would not ever fire if the scan interval is short
1138         * enough.
1139         */
1140        if (test_bit(SCHED_SCANNING, &vif->flags) &&
1141            !timer_pending(&vif->sched_scan_timer)) {
1142                mod_timer(&vif->sched_scan_timer, jiffies +
1143                          msecs_to_jiffies(ATH6KL_SCHED_SCAN_RESULT_DELAY));
1144        }
1145
1146        return 0;
1147}
1148
1149/* Inactivity timeout of a fatpipe(pstream) at the target */
1150static int ath6kl_wmi_pstream_timeout_event_rx(struct wmi *wmi, u8 *datap,
1151                                               int len)
1152{
1153        struct wmi_pstream_timeout_event *ev;
1154
1155        if (len < sizeof(struct wmi_pstream_timeout_event))
1156                return -EINVAL;
1157
1158        ev = (struct wmi_pstream_timeout_event *) datap;
1159
1160        /*
1161         * When the pstream (fat pipe == AC) timesout, it means there were
1162         * no thinStreams within this pstream & it got implicitly created
1163         * due to data flow on this AC. We start the inactivity timer only
1164         * for implicitly created pstream. Just reset the host state.
1165         */
1166        spin_lock_bh(&wmi->lock);
1167        wmi->stream_exist_for_ac[ev->traffic_class] = 0;
1168        wmi->fat_pipe_exist &= ~(1 << ev->traffic_class);
1169        spin_unlock_bh(&wmi->lock);
1170
1171        /* Indicate inactivity to driver layer for this fatpipe (pstream) */
1172        ath6kl_indicate_tx_activity(wmi->parent_dev, ev->traffic_class, false);
1173
1174        return 0;
1175}
1176
1177static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len)
1178{
1179        struct wmi_bit_rate_reply *reply;
1180        s32 rate;
1181        u32 sgi, index;
1182
1183        if (len < sizeof(struct wmi_bit_rate_reply))
1184                return -EINVAL;
1185
1186        reply = (struct wmi_bit_rate_reply *) datap;
1187
1188        ath6kl_dbg(ATH6KL_DBG_WMI, "rateindex %d\n", reply->rate_index);
1189
1190        if (reply->rate_index == (s8) RATE_AUTO) {
1191                rate = RATE_AUTO;
1192        } else {
1193                index = reply->rate_index & 0x7f;
1194                if (WARN_ON_ONCE(index > (RATE_MCS_7_40 + 1)))
1195                        return -EINVAL;
1196
1197                sgi = (reply->rate_index & 0x80) ? 1 : 0;
1198                rate = wmi_rate_tbl[index][sgi];
1199        }
1200
1201        ath6kl_wakeup_event(wmi->parent_dev);
1202
1203        return 0;
1204}
1205
1206static int ath6kl_wmi_test_rx(struct wmi *wmi, u8 *datap, int len)
1207{
1208        ath6kl_tm_rx_event(wmi->parent_dev, datap, len);
1209
1210        return 0;
1211}
1212
1213static int ath6kl_wmi_ratemask_reply_rx(struct wmi *wmi, u8 *datap, int len)
1214{
1215        if (len < sizeof(struct wmi_fix_rates_reply))
1216                return -EINVAL;
1217
1218        ath6kl_wakeup_event(wmi->parent_dev);
1219
1220        return 0;
1221}
1222
1223static int ath6kl_wmi_ch_list_reply_rx(struct wmi *wmi, u8 *datap, int len)
1224{
1225        if (len < sizeof(struct wmi_channel_list_reply))
1226                return -EINVAL;
1227
1228        ath6kl_wakeup_event(wmi->parent_dev);
1229
1230        return 0;
1231}
1232
1233static int ath6kl_wmi_tx_pwr_reply_rx(struct wmi *wmi, u8 *datap, int len)
1234{
1235        struct wmi_tx_pwr_reply *reply;
1236
1237        if (len < sizeof(struct wmi_tx_pwr_reply))
1238                return -EINVAL;
1239
1240        reply = (struct wmi_tx_pwr_reply *) datap;
1241        ath6kl_txpwr_rx_evt(wmi->parent_dev, reply->dbM);
1242
1243        return 0;
1244}
1245
1246static int ath6kl_wmi_keepalive_reply_rx(struct wmi *wmi, u8 *datap, int len)
1247{
1248        if (len < sizeof(struct wmi_get_keepalive_cmd))
1249                return -EINVAL;
1250
1251        ath6kl_wakeup_event(wmi->parent_dev);
1252
1253        return 0;
1254}
1255
1256static int ath6kl_wmi_scan_complete_rx(struct wmi *wmi, u8 *datap, int len,
1257                                       struct ath6kl_vif *vif)
1258{
1259        struct wmi_scan_complete_event *ev;
1260
1261        ev = (struct wmi_scan_complete_event *) datap;
1262
1263        ath6kl_scan_complete_evt(vif, a_sle32_to_cpu(ev->status));
1264        wmi->is_probe_ssid = false;
1265
1266        return 0;
1267}
1268
1269static int ath6kl_wmi_neighbor_report_event_rx(struct wmi *wmi, u8 *datap,
1270                                               int len, struct ath6kl_vif *vif)
1271{
1272        struct wmi_neighbor_report_event *ev;
1273        u8 i;
1274
1275        if (len < sizeof(*ev))
1276                return -EINVAL;
1277        ev = (struct wmi_neighbor_report_event *) datap;
1278        if (sizeof(*ev) + ev->num_neighbors * sizeof(struct wmi_neighbor_info)
1279            > len) {
1280                ath6kl_dbg(ATH6KL_DBG_WMI,
1281                           "truncated neighbor event (num=%d len=%d)\n",
1282                           ev->num_neighbors, len);
1283                return -EINVAL;
1284        }
1285        for (i = 0; i < ev->num_neighbors; i++) {
1286                ath6kl_dbg(ATH6KL_DBG_WMI, "neighbor %d/%d - %pM 0x%x\n",
1287                           i + 1, ev->num_neighbors, ev->neighbor[i].bssid,
1288                           ev->neighbor[i].bss_flags);
1289                cfg80211_pmksa_candidate_notify(vif->ndev, i,
1290                                                ev->neighbor[i].bssid,
1291                                                !!(ev->neighbor[i].bss_flags &
1292                                                   WMI_PREAUTH_CAPABLE_BSS),
1293                                                GFP_ATOMIC);
1294        }
1295
1296        return 0;
1297}
1298
1299/*
1300 * Target is reporting a programming error.  This is for
1301 * developer aid only.  Target only checks a few common violations
1302 * and it is responsibility of host to do all error checking.
1303 * Behavior of target after wmi error event is undefined.
1304 * A reset is recommended.
1305 */
1306static int ath6kl_wmi_error_event_rx(struct wmi *wmi, u8 *datap, int len)
1307{
1308        const char *type = "unknown error";
1309        struct wmi_cmd_error_event *ev;
1310        ev = (struct wmi_cmd_error_event *) datap;
1311
1312        switch (ev->err_code) {
1313        case INVALID_PARAM:
1314                type = "invalid parameter";
1315                break;
1316        case ILLEGAL_STATE:
1317                type = "invalid state";
1318                break;
1319        case INTERNAL_ERROR:
1320                type = "internal error";
1321                break;
1322        }
1323
1324        ath6kl_dbg(ATH6KL_DBG_WMI, "programming error, cmd=%d %s\n",
1325                   ev->cmd_id, type);
1326
1327        return 0;
1328}
1329
1330static int ath6kl_wmi_stats_event_rx(struct wmi *wmi, u8 *datap, int len,
1331                                     struct ath6kl_vif *vif)
1332{
1333        ath6kl_tgt_stats_event(vif, datap, len);
1334
1335        return 0;
1336}
1337
1338static u8 ath6kl_wmi_get_upper_threshold(s16 rssi,
1339                                         struct sq_threshold_params *sq_thresh,
1340                                         u32 size)
1341{
1342        u32 index;
1343        u8 threshold = (u8) sq_thresh->upper_threshold[size - 1];
1344
1345        /* The list is already in sorted order. Get the next lower value */
1346        for (index = 0; index < size; index++) {
1347                if (rssi < sq_thresh->upper_threshold[index]) {
1348                        threshold = (u8) sq_thresh->upper_threshold[index];
1349                        break;
1350                }
1351        }
1352
1353        return threshold;
1354}
1355
1356static u8 ath6kl_wmi_get_lower_threshold(s16 rssi,
1357                                         struct sq_threshold_params *sq_thresh,
1358                                         u32 size)
1359{
1360        u32 index;
1361        u8 threshold = (u8) sq_thresh->lower_threshold[size - 1];
1362
1363        /* The list is already in sorted order. Get the next lower value */
1364        for (index = 0; index < size; index++) {
1365                if (rssi > sq_thresh->lower_threshold[index]) {
1366                        threshold = (u8) sq_thresh->lower_threshold[index];
1367                        break;
1368                }
1369        }
1370
1371        return threshold;
1372}
1373
1374static int ath6kl_wmi_send_rssi_threshold_params(struct wmi *wmi,
1375                        struct wmi_rssi_threshold_params_cmd *rssi_cmd)
1376{
1377        struct sk_buff *skb;
1378        struct wmi_rssi_threshold_params_cmd *cmd;
1379
1380        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1381        if (!skb)
1382                return -ENOMEM;
1383
1384        cmd = (struct wmi_rssi_threshold_params_cmd *) skb->data;
1385        memcpy(cmd, rssi_cmd, sizeof(struct wmi_rssi_threshold_params_cmd));
1386
1387        return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_RSSI_THRESHOLD_PARAMS_CMDID,
1388                                   NO_SYNC_WMIFLAG);
1389}
1390
1391static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap,
1392                                              int len)
1393{
1394        struct wmi_rssi_threshold_event *reply;
1395        struct wmi_rssi_threshold_params_cmd cmd;
1396        struct sq_threshold_params *sq_thresh;
1397        enum wmi_rssi_threshold_val new_threshold;
1398        u8 upper_rssi_threshold, lower_rssi_threshold;
1399        s16 rssi;
1400        int ret;
1401
1402        if (len < sizeof(struct wmi_rssi_threshold_event))
1403                return -EINVAL;
1404
1405        reply = (struct wmi_rssi_threshold_event *) datap;
1406        new_threshold = (enum wmi_rssi_threshold_val) reply->range;
1407        rssi = a_sle16_to_cpu(reply->rssi);
1408
1409        sq_thresh = &wmi->sq_threshld[SIGNAL_QUALITY_METRICS_RSSI];
1410
1411        /*
1412         * Identify the threshold breached and communicate that to the app.
1413         * After that install a new set of thresholds based on the signal
1414         * quality reported by the target
1415         */
1416        if (new_threshold) {
1417                /* Upper threshold breached */
1418                if (rssi < sq_thresh->upper_threshold[0]) {
1419                        ath6kl_dbg(ATH6KL_DBG_WMI,
1420                                   "spurious upper rssi threshold event: %d\n",
1421                                   rssi);
1422                } else if ((rssi < sq_thresh->upper_threshold[1]) &&
1423                           (rssi >= sq_thresh->upper_threshold[0])) {
1424                        new_threshold = WMI_RSSI_THRESHOLD1_ABOVE;
1425                } else if ((rssi < sq_thresh->upper_threshold[2]) &&
1426                           (rssi >= sq_thresh->upper_threshold[1])) {
1427                        new_threshold = WMI_RSSI_THRESHOLD2_ABOVE;
1428                } else if ((rssi < sq_thresh->upper_threshold[3]) &&
1429                           (rssi >= sq_thresh->upper_threshold[2])) {
1430                        new_threshold = WMI_RSSI_THRESHOLD3_ABOVE;
1431                } else if ((rssi < sq_thresh->upper_threshold[4]) &&
1432                           (rssi >= sq_thresh->upper_threshold[3])) {
1433                        new_threshold = WMI_RSSI_THRESHOLD4_ABOVE;
1434                } else if ((rssi < sq_thresh->upper_threshold[5]) &&
1435                           (rssi >= sq_thresh->upper_threshold[4])) {
1436                        new_threshold = WMI_RSSI_THRESHOLD5_ABOVE;
1437                } else if (rssi >= sq_thresh->upper_threshold[5]) {
1438                        new_threshold = WMI_RSSI_THRESHOLD6_ABOVE;
1439                }
1440        } else {
1441                /* Lower threshold breached */
1442                if (rssi > sq_thresh->lower_threshold[0]) {
1443                        ath6kl_dbg(ATH6KL_DBG_WMI,
1444                                   "spurious lower rssi threshold event: %d %d\n",
1445                                rssi, sq_thresh->lower_threshold[0]);
1446                } else if ((rssi > sq_thresh->lower_threshold[1]) &&
1447                           (rssi <= sq_thresh->lower_threshold[0])) {
1448                        new_threshold = WMI_RSSI_THRESHOLD6_BELOW;
1449                } else if ((rssi > sq_thresh->lower_threshold[2]) &&
1450                           (rssi <= sq_thresh->lower_threshold[1])) {
1451                        new_threshold = WMI_RSSI_THRESHOLD5_BELOW;
1452                } else if ((rssi > sq_thresh->lower_threshold[3]) &&
1453                           (rssi <= sq_thresh->lower_threshold[2])) {
1454                        new_threshold = WMI_RSSI_THRESHOLD4_BELOW;
1455                } else if ((rssi > sq_thresh->lower_threshold[4]) &&
1456                           (rssi <= sq_thresh->lower_threshold[3])) {
1457                        new_threshold = WMI_RSSI_THRESHOLD3_BELOW;
1458                } else if ((rssi > sq_thresh->lower_threshold[5]) &&
1459                           (rssi <= sq_thresh->lower_threshold[4])) {
1460                        new_threshold = WMI_RSSI_THRESHOLD2_BELOW;
1461                } else if (rssi <= sq_thresh->lower_threshold[5]) {
1462                        new_threshold = WMI_RSSI_THRESHOLD1_BELOW;
1463                }
1464        }
1465
1466        /* Calculate and install the next set of thresholds */
1467        lower_rssi_threshold = ath6kl_wmi_get_lower_threshold(rssi, sq_thresh,
1468                                       sq_thresh->lower_threshold_valid_count);
1469        upper_rssi_threshold = ath6kl_wmi_get_upper_threshold(rssi, sq_thresh,
1470                                       sq_thresh->upper_threshold_valid_count);
1471
1472        /* Issue a wmi command to install the thresholds */
1473        cmd.thresh_above1_val = a_cpu_to_sle16(upper_rssi_threshold);
1474        cmd.thresh_below1_val = a_cpu_to_sle16(lower_rssi_threshold);
1475        cmd.weight = sq_thresh->weight;
1476        cmd.poll_time = cpu_to_le32(sq_thresh->polling_interval);
1477
1478        ret = ath6kl_wmi_send_rssi_threshold_params(wmi, &cmd);
1479        if (ret) {
1480                ath6kl_err("unable to configure rssi thresholds\n");
1481                return -EIO;
1482        }
1483
1484        return 0;
1485}
1486
1487static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len,
1488                                   struct ath6kl_vif *vif)
1489{
1490        struct wmi_cac_event *reply;
1491        struct ieee80211_tspec_ie *ts;
1492        u16 active_tsids, tsinfo;
1493        u8 tsid, index;
1494        u8 ts_id;
1495
1496        if (len < sizeof(struct wmi_cac_event))
1497                return -EINVAL;
1498
1499        reply = (struct wmi_cac_event *) datap;
1500
1501        if ((reply->cac_indication == CAC_INDICATION_ADMISSION_RESP) &&
1502            (reply->status_code != IEEE80211_TSPEC_STATUS_ADMISS_ACCEPTED)) {
1503
1504                ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion);
1505                tsinfo = le16_to_cpu(ts->tsinfo);
1506                tsid = (tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) &
1507                        IEEE80211_WMM_IE_TSPEC_TID_MASK;
1508
1509                ath6kl_wmi_delete_pstream_cmd(wmi, vif->fw_vif_idx,
1510                                              reply->ac, tsid);
1511        } else if (reply->cac_indication == CAC_INDICATION_NO_RESP) {
1512                /*
1513                 * Following assumes that there is only one outstanding
1514                 * ADDTS request when this event is received
1515                 */
1516                spin_lock_bh(&wmi->lock);
1517                active_tsids = wmi->stream_exist_for_ac[reply->ac];
1518                spin_unlock_bh(&wmi->lock);
1519
1520                for (index = 0; index < sizeof(active_tsids) * 8; index++) {
1521                        if ((active_tsids >> index) & 1)
1522                                break;
1523                }
1524                if (index < (sizeof(active_tsids) * 8))
1525                        ath6kl_wmi_delete_pstream_cmd(wmi, vif->fw_vif_idx,
1526                                                      reply->ac, index);
1527        }
1528
1529        /*
1530         * Clear active tsids and Add missing handling
1531         * for delete qos stream from AP
1532         */
1533        else if (reply->cac_indication == CAC_INDICATION_DELETE) {
1534
1535                ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion);
1536                tsinfo = le16_to_cpu(ts->tsinfo);
1537                ts_id = ((tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) &
1538                         IEEE80211_WMM_IE_TSPEC_TID_MASK);
1539
1540                spin_lock_bh(&wmi->lock);
1541                wmi->stream_exist_for_ac[reply->ac] &= ~(1 << ts_id);
1542                active_tsids = wmi->stream_exist_for_ac[reply->ac];
1543                spin_unlock_bh(&wmi->lock);
1544
1545                /* Indicate stream inactivity to driver layer only if all tsids
1546                 * within this AC are deleted.
1547                 */
1548                if (!active_tsids) {
1549                        ath6kl_indicate_tx_activity(wmi->parent_dev, reply->ac,
1550                                                    false);
1551                        wmi->fat_pipe_exist &= ~(1 << reply->ac);
1552                }
1553        }
1554
1555        return 0;
1556}
1557
1558static int ath6kl_wmi_txe_notify_event_rx(struct wmi *wmi, u8 *datap, int len,
1559                                          struct ath6kl_vif *vif)
1560{
1561        struct wmi_txe_notify_event *ev;
1562        u32 rate, pkts;
1563
1564        if (len < sizeof(*ev))
1565                return -EINVAL;
1566
1567        if (vif->sme_state != SME_CONNECTED)
1568                return -ENOTCONN;
1569
1570        ev = (struct wmi_txe_notify_event *) datap;
1571        rate = le32_to_cpu(ev->rate);
1572        pkts = le32_to_cpu(ev->pkts);
1573
1574        ath6kl_dbg(ATH6KL_DBG_WMI, "TXE notify event: peer %pM rate %d% pkts %d intvl %ds\n",
1575                   vif->bssid, rate, pkts, vif->txe_intvl);
1576
1577        cfg80211_cqm_txe_notify(vif->ndev, vif->bssid, pkts,
1578                                rate, vif->txe_intvl, GFP_KERNEL);
1579
1580        return 0;
1581}
1582
1583int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx,
1584                              u32 rate, u32 pkts, u32 intvl)
1585{
1586        struct sk_buff *skb;
1587        struct wmi_txe_notify_cmd *cmd;
1588
1589        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1590        if (!skb)
1591                return -ENOMEM;
1592
1593        cmd = (struct wmi_txe_notify_cmd *) skb->data;
1594        cmd->rate = cpu_to_le32(rate);
1595        cmd->pkts = cpu_to_le32(pkts);
1596        cmd->intvl = cpu_to_le32(intvl);
1597
1598        return ath6kl_wmi_cmd_send(wmi, idx, skb, WMI_SET_TXE_NOTIFY_CMDID,
1599                                   NO_SYNC_WMIFLAG);
1600}
1601
1602int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi)
1603{
1604        struct sk_buff *skb;
1605        struct wmi_set_rssi_filter_cmd *cmd;
1606        int ret;
1607
1608        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1609        if (!skb)
1610                return -ENOMEM;
1611
1612        cmd = (struct wmi_set_rssi_filter_cmd *) skb->data;
1613        cmd->rssi = rssi;
1614
1615        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_RSSI_FILTER_CMDID,
1616                                  NO_SYNC_WMIFLAG);
1617        return ret;
1618}
1619
1620static int ath6kl_wmi_send_snr_threshold_params(struct wmi *wmi,
1621                        struct wmi_snr_threshold_params_cmd *snr_cmd)
1622{
1623        struct sk_buff *skb;
1624        struct wmi_snr_threshold_params_cmd *cmd;
1625
1626        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1627        if (!skb)
1628                return -ENOMEM;
1629
1630        cmd = (struct wmi_snr_threshold_params_cmd *) skb->data;
1631        memcpy(cmd, snr_cmd, sizeof(struct wmi_snr_threshold_params_cmd));
1632
1633        return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SNR_THRESHOLD_PARAMS_CMDID,
1634                                   NO_SYNC_WMIFLAG);
1635}
1636
1637static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap,
1638                                             int len)
1639{
1640        struct wmi_snr_threshold_event *reply;
1641        struct sq_threshold_params *sq_thresh;
1642        struct wmi_snr_threshold_params_cmd cmd;
1643        enum wmi_snr_threshold_val new_threshold;
1644        u8 upper_snr_threshold, lower_snr_threshold;
1645        s16 snr;
1646        int ret;
1647
1648        if (len < sizeof(struct wmi_snr_threshold_event))
1649                return -EINVAL;
1650
1651        reply = (struct wmi_snr_threshold_event *) datap;
1652
1653        new_threshold = (enum wmi_snr_threshold_val) reply->range;
1654        snr = reply->snr;
1655
1656        sq_thresh = &wmi->sq_threshld[SIGNAL_QUALITY_METRICS_SNR];
1657
1658        /*
1659         * Identify the threshold breached and communicate that to the app.
1660         * After that install a new set of thresholds based on the signal
1661         * quality reported by the target.
1662         */
1663        if (new_threshold) {
1664                /* Upper threshold breached */
1665                if (snr < sq_thresh->upper_threshold[0]) {
1666                        ath6kl_dbg(ATH6KL_DBG_WMI,
1667                                   "spurious upper snr threshold event: %d\n",
1668                                   snr);
1669                } else if ((snr < sq_thresh->upper_threshold[1]) &&
1670                           (snr >= sq_thresh->upper_threshold[0])) {
1671                        new_threshold = WMI_SNR_THRESHOLD1_ABOVE;
1672                } else if ((snr < sq_thresh->upper_threshold[2]) &&
1673                           (snr >= sq_thresh->upper_threshold[1])) {
1674                        new_threshold = WMI_SNR_THRESHOLD2_ABOVE;
1675                } else if ((snr < sq_thresh->upper_threshold[3]) &&
1676                           (snr >= sq_thresh->upper_threshold[2])) {
1677                        new_threshold = WMI_SNR_THRESHOLD3_ABOVE;
1678                } else if (snr >= sq_thresh->upper_threshold[3]) {
1679                        new_threshold = WMI_SNR_THRESHOLD4_ABOVE;
1680                }
1681        } else {
1682                /* Lower threshold breached */
1683                if (snr > sq_thresh->lower_threshold[0]) {
1684                        ath6kl_dbg(ATH6KL_DBG_WMI,
1685                                   "spurious lower snr threshold event: %d\n",
1686                                   sq_thresh->lower_threshold[0]);
1687                } else if ((snr > sq_thresh->lower_threshold[1]) &&
1688                           (snr <= sq_thresh->lower_threshold[0])) {
1689                        new_threshold = WMI_SNR_THRESHOLD4_BELOW;
1690                } else if ((snr > sq_thresh->lower_threshold[2]) &&
1691                           (snr <= sq_thresh->lower_threshold[1])) {
1692                        new_threshold = WMI_SNR_THRESHOLD3_BELOW;
1693                } else if ((snr > sq_thresh->lower_threshold[3]) &&
1694                           (snr <= sq_thresh->lower_threshold[2])) {
1695                        new_threshold = WMI_SNR_THRESHOLD2_BELOW;
1696                } else if (snr <= sq_thresh->lower_threshold[3]) {
1697                        new_threshold = WMI_SNR_THRESHOLD1_BELOW;
1698                }
1699        }
1700
1701        /* Calculate and install the next set of thresholds */
1702        lower_snr_threshold = ath6kl_wmi_get_lower_threshold(snr, sq_thresh,
1703                                       sq_thresh->lower_threshold_valid_count);
1704        upper_snr_threshold = ath6kl_wmi_get_upper_threshold(snr, sq_thresh,
1705                                       sq_thresh->upper_threshold_valid_count);
1706
1707        /* Issue a wmi command to install the thresholds */
1708        cmd.thresh_above1_val = upper_snr_threshold;
1709        cmd.thresh_below1_val = lower_snr_threshold;
1710        cmd.weight = sq_thresh->weight;
1711        cmd.poll_time = cpu_to_le32(sq_thresh->polling_interval);
1712
1713        ath6kl_dbg(ATH6KL_DBG_WMI,
1714                   "snr: %d, threshold: %d, lower: %d, upper: %d\n",
1715                   snr, new_threshold,
1716                   lower_snr_threshold, upper_snr_threshold);
1717
1718        ret = ath6kl_wmi_send_snr_threshold_params(wmi, &cmd);
1719        if (ret) {
1720                ath6kl_err("unable to configure snr threshold\n");
1721                return -EIO;
1722        }
1723
1724        return 0;
1725}
1726
1727static int ath6kl_wmi_aplist_event_rx(struct wmi *wmi, u8 *datap, int len)
1728{
1729        u16 ap_info_entry_size;
1730        struct wmi_aplist_event *ev = (struct wmi_aplist_event *) datap;
1731        struct wmi_ap_info_v1 *ap_info_v1;
1732        u8 index;
1733
1734        if (len < sizeof(struct wmi_aplist_event) ||
1735            ev->ap_list_ver != APLIST_VER1)
1736                return -EINVAL;
1737
1738        ap_info_entry_size = sizeof(struct wmi_ap_info_v1);
1739        ap_info_v1 = (struct wmi_ap_info_v1 *) ev->ap_list;
1740
1741        ath6kl_dbg(ATH6KL_DBG_WMI,
1742                   "number of APs in aplist event: %d\n", ev->num_ap);
1743
1744        if (len < (int) (sizeof(struct wmi_aplist_event) +
1745                         (ev->num_ap - 1) * ap_info_entry_size))
1746                return -EINVAL;
1747
1748        /* AP list version 1 contents */
1749        for (index = 0; index < ev->num_ap; index++) {
1750                ath6kl_dbg(ATH6KL_DBG_WMI, "AP#%d BSSID %pM Channel %d\n",
1751                           index, ap_info_v1->bssid, ap_info_v1->channel);
1752                ap_info_v1++;
1753        }
1754
1755        return 0;
1756}
1757
1758int ath6kl_wmi_cmd_send(struct wmi *wmi, u8 if_idx, struct sk_buff *skb,
1759                        enum wmi_cmd_id cmd_id, enum wmi_sync_flag sync_flag)
1760{
1761        struct wmi_cmd_hdr *cmd_hdr;
1762        enum htc_endpoint_id ep_id = wmi->ep_id;
1763        int ret;
1764        u16 info1;
1765
1766        if (WARN_ON(skb == NULL ||
1767                    (if_idx > (wmi->parent_dev->vif_max - 1)))) {
1768                dev_kfree_skb(skb);
1769                return -EINVAL;
1770        }
1771
1772        ath6kl_dbg(ATH6KL_DBG_WMI, "wmi tx id %d len %d flag %d\n",
1773                   cmd_id, skb->len, sync_flag);
1774        ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi tx ",
1775                        skb->data, skb->len);
1776
1777        if (sync_flag >= END_WMIFLAG) {
1778                dev_kfree_skb(skb);
1779                return -EINVAL;
1780        }
1781
1782        if ((sync_flag == SYNC_BEFORE_WMIFLAG) ||
1783            (sync_flag == SYNC_BOTH_WMIFLAG)) {
1784                /*
1785                 * Make sure all data currently queued is transmitted before
1786                 * the cmd execution.  Establish a new sync point.
1787                 */
1788                ath6kl_wmi_sync_point(wmi, if_idx);
1789        }
1790
1791        skb_push(skb, sizeof(struct wmi_cmd_hdr));
1792
1793        cmd_hdr = (struct wmi_cmd_hdr *) skb->data;
1794        cmd_hdr->cmd_id = cpu_to_le16(cmd_id);
1795        info1 = if_idx & WMI_CMD_HDR_IF_ID_MASK;
1796        cmd_hdr->info1 = cpu_to_le16(info1);
1797
1798        /* Only for OPT_TX_CMD, use BE endpoint. */
1799        if (cmd_id == WMI_OPT_TX_FRAME_CMDID) {
1800                ret = ath6kl_wmi_data_hdr_add(wmi, skb, OPT_MSGTYPE,
1801                                              false, false, 0, NULL, if_idx);
1802                if (ret) {
1803                        dev_kfree_skb(skb);
1804                        return ret;
1805                }
1806                ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev, WMM_AC_BE);
1807        }
1808
1809        ath6kl_control_tx(wmi->parent_dev, skb, ep_id);
1810
1811        if ((sync_flag == SYNC_AFTER_WMIFLAG) ||
1812            (sync_flag == SYNC_BOTH_WMIFLAG)) {
1813                /*
1814                 * Make sure all new data queued waits for the command to
1815                 * execute. Establish a new sync point.
1816                 */
1817                ath6kl_wmi_sync_point(wmi, if_idx);
1818        }
1819
1820        return 0;
1821}
1822
1823int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx,
1824                           enum network_type nw_type,
1825                           enum dot11_auth_mode dot11_auth_mode,
1826                           enum auth_mode auth_mode,
1827                           enum crypto_type pairwise_crypto,
1828                           u8 pairwise_crypto_len,
1829                           enum crypto_type group_crypto,
1830                           u8 group_crypto_len, int ssid_len, u8 *ssid,
1831                           u8 *bssid, u16 channel, u32 ctrl_flags,
1832                           u8 nw_subtype)
1833{
1834        struct sk_buff *skb;
1835        struct wmi_connect_cmd *cc;
1836        int ret;
1837
1838        ath6kl_dbg(ATH6KL_DBG_WMI,
1839                   "wmi connect bssid %pM freq %d flags 0x%x ssid_len %d "
1840                   "type %d dot11_auth %d auth %d pairwise %d group %d\n",
1841                   bssid, channel, ctrl_flags, ssid_len, nw_type,
1842                   dot11_auth_mode, auth_mode, pairwise_crypto, group_crypto);
1843        ath6kl_dbg_dump(ATH6KL_DBG_WMI, NULL, "ssid ", ssid, ssid_len);
1844
1845        wmi->traffic_class = 100;
1846
1847        if ((pairwise_crypto == NONE_CRYPT) && (group_crypto != NONE_CRYPT))
1848                return -EINVAL;
1849
1850        if ((pairwise_crypto != NONE_CRYPT) && (group_crypto == NONE_CRYPT))
1851                return -EINVAL;
1852
1853        skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_connect_cmd));
1854        if (!skb)
1855                return -ENOMEM;
1856
1857        cc = (struct wmi_connect_cmd *) skb->data;
1858
1859        if (ssid_len)
1860                memcpy(cc->ssid, ssid, ssid_len);
1861
1862        cc->ssid_len = ssid_len;
1863        cc->nw_type = nw_type;
1864        cc->dot11_auth_mode = dot11_auth_mode;
1865        cc->auth_mode = auth_mode;
1866        cc->prwise_crypto_type = pairwise_crypto;
1867        cc->prwise_crypto_len = pairwise_crypto_len;
1868        cc->grp_crypto_type = group_crypto;
1869        cc->grp_crypto_len = group_crypto_len;
1870        cc->ch = cpu_to_le16(channel);
1871        cc->ctrl_flags = cpu_to_le32(ctrl_flags);
1872        cc->nw_subtype = nw_subtype;
1873
1874        if (bssid != NULL)
1875                memcpy(cc->bssid, bssid, ETH_ALEN);
1876
1877        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_CONNECT_CMDID,
1878                                  NO_SYNC_WMIFLAG);
1879
1880        return ret;
1881}
1882
1883int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 if_idx, u8 *bssid,
1884                             u16 channel)
1885{
1886        struct sk_buff *skb;
1887        struct wmi_reconnect_cmd *cc;
1888        int ret;
1889
1890        ath6kl_dbg(ATH6KL_DBG_WMI, "wmi reconnect bssid %pM freq %d\n",
1891                   bssid, channel);
1892
1893        wmi->traffic_class = 100;
1894
1895        skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_reconnect_cmd));
1896        if (!skb)
1897                return -ENOMEM;
1898
1899        cc = (struct wmi_reconnect_cmd *) skb->data;
1900        cc->channel = cpu_to_le16(channel);
1901
1902        if (bssid != NULL)
1903                memcpy(cc->bssid, bssid, ETH_ALEN);
1904
1905        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_RECONNECT_CMDID,
1906                                  NO_SYNC_WMIFLAG);
1907
1908        return ret;
1909}
1910
1911int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx)
1912{
1913        int ret;
1914
1915        ath6kl_dbg(ATH6KL_DBG_WMI, "wmi disconnect\n");
1916
1917        wmi->traffic_class = 100;
1918
1919        /* Disconnect command does not need to do a SYNC before. */
1920        ret = ath6kl_wmi_simple_cmd(wmi, if_idx, WMI_DISCONNECT_CMDID);
1921
1922        return ret;
1923}
1924
1925/* ath6kl_wmi_start_scan_cmd is to be deprecated. Use
1926 * ath6kl_wmi_begin_scan_cmd instead. The new function supports P2P
1927 * mgmt operations using station interface.
1928 */
1929static int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx,
1930                                    enum wmi_scan_type scan_type,
1931                                    u32 force_fgscan, u32 is_legacy,
1932                                    u32 home_dwell_time,
1933                                    u32 force_scan_interval,
1934                                    s8 num_chan, u16 *ch_list)
1935{
1936        struct sk_buff *skb;
1937        struct wmi_start_scan_cmd *sc;
1938        s8 size;
1939        int i, ret;
1940
1941        size = sizeof(struct wmi_start_scan_cmd);
1942
1943        if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN))
1944                return -EINVAL;
1945
1946        if (num_chan > WMI_MAX_CHANNELS)
1947                return -EINVAL;
1948
1949        if (num_chan)
1950                size += sizeof(u16) * (num_chan - 1);
1951
1952        skb = ath6kl_wmi_get_new_buf(size);
1953        if (!skb)
1954                return -ENOMEM;
1955
1956        sc = (struct wmi_start_scan_cmd *) skb->data;
1957        sc->scan_type = scan_type;
1958        sc->force_fg_scan = cpu_to_le32(force_fgscan);
1959        sc->is_legacy = cpu_to_le32(is_legacy);
1960        sc->home_dwell_time = cpu_to_le32(home_dwell_time);
1961        sc->force_scan_intvl = cpu_to_le32(force_scan_interval);
1962        sc->num_ch = num_chan;
1963
1964        for (i = 0; i < num_chan; i++)
1965                sc->ch_list[i] = cpu_to_le16(ch_list[i]);
1966
1967        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_START_SCAN_CMDID,
1968                                  NO_SYNC_WMIFLAG);
1969
1970        return ret;
1971}
1972
1973/*
1974 * beginscan supports (compared to old startscan) P2P mgmt operations using
1975 * station interface, send additional information like supported rates to
1976 * advertise and xmit rates for probe requests
1977 */
1978int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
1979                             enum wmi_scan_type scan_type,
1980                             u32 force_fgscan, u32 is_legacy,
1981                             u32 home_dwell_time, u32 force_scan_interval,
1982                             s8 num_chan, u16 *ch_list, u32 no_cck, u32 *rates)
1983{
1984        struct ieee80211_supported_band *sband;
1985        struct sk_buff *skb;
1986        struct wmi_begin_scan_cmd *sc;
1987        s8 size, *supp_rates;
1988        int i, band, ret;
1989        struct ath6kl *ar = wmi->parent_dev;
1990        int num_rates;
1991        u32 ratemask;
1992
1993        if (!test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
1994                      ar->fw_capabilities)) {
1995                return ath6kl_wmi_startscan_cmd(wmi, if_idx,
1996                                                scan_type, force_fgscan,
1997                                                is_legacy, home_dwell_time,
1998                                                force_scan_interval,
1999                                                num_chan, ch_list);
2000        }
2001
2002        size = sizeof(struct wmi_begin_scan_cmd);
2003
2004        if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN))
2005                return -EINVAL;
2006
2007        if (num_chan > WMI_MAX_CHANNELS)
2008                return -EINVAL;
2009
2010        if (num_chan)
2011                size += sizeof(u16) * (num_chan - 1);
2012
2013        skb = ath6kl_wmi_get_new_buf(size);
2014        if (!skb)
2015                return -ENOMEM;
2016
2017        sc = (struct wmi_begin_scan_cmd *) skb->data;
2018        sc->scan_type = scan_type;
2019        sc->force_fg_scan = cpu_to_le32(force_fgscan);
2020        sc->is_legacy = cpu_to_le32(is_legacy);
2021        sc->home_dwell_time = cpu_to_le32(home_dwell_time);
2022        sc->force_scan_intvl = cpu_to_le32(force_scan_interval);
2023        sc->no_cck = cpu_to_le32(no_cck);
2024        sc->num_ch = num_chan;
2025
2026        for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
2027                sband = ar->wiphy->bands[band];
2028
2029                if (!sband)
2030                        continue;
2031
2032                if (WARN_ON(band >= ATH6KL_NUM_BANDS))
2033                        break;
2034
2035                ratemask = rates[band];
2036                supp_rates = sc->supp_rates[band].rates;
2037                num_rates = 0;
2038
2039                for (i = 0; i < sband->n_bitrates; i++) {
2040                        if ((BIT(i) & ratemask) == 0)
2041                                continue; /* skip rate */
2042                        supp_rates[num_rates++] =
2043                            (u8) (sband->bitrates[i].bitrate / 5);
2044                }
2045                sc->supp_rates[band].nrates = num_rates;
2046        }
2047
2048        for (i = 0; i < num_chan; i++)
2049                sc->ch_list[i] = cpu_to_le16(ch_list[i]);
2050
2051        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_BEGIN_SCAN_CMDID,
2052                                  NO_SYNC_WMIFLAG);
2053
2054        return ret;
2055}
2056
2057int ath6kl_wmi_enable_sched_scan_cmd(struct wmi *wmi, u8 if_idx, bool enable)
2058{
2059        struct sk_buff *skb;
2060        struct wmi_enable_sched_scan_cmd *sc;
2061        int ret;
2062
2063        skb = ath6kl_wmi_get_new_buf(sizeof(*sc));
2064        if (!skb)
2065                return -ENOMEM;
2066
2067        ath6kl_dbg(ATH6KL_DBG_WMI, "%s scheduled scan on vif %d\n",
2068                   enable ? "enabling" : "disabling", if_idx);
2069        sc = (struct wmi_enable_sched_scan_cmd *) skb->data;
2070        sc->enable = enable ? 1 : 0;
2071
2072        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
2073                                  WMI_ENABLE_SCHED_SCAN_CMDID,
2074                                  NO_SYNC_WMIFLAG);
2075        return ret;
2076}
2077
2078int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u8 if_idx,
2079                              u16 fg_start_sec,
2080                              u16 fg_end_sec, u16 bg_sec,
2081                              u16 minact_chdw_msec, u16 maxact_chdw_msec,
2082                              u16 pas_chdw_msec, u8 short_scan_ratio,
2083                              u8 scan_ctrl_flag, u32 max_dfsch_act_time,
2084                              u16 maxact_scan_per_ssid)
2085{
2086        struct sk_buff *skb;
2087        struct wmi_scan_params_cmd *sc;
2088        int ret;
2089
2090        skb = ath6kl_wmi_get_new_buf(sizeof(*sc));
2091        if (!skb)
2092                return -ENOMEM;
2093
2094        sc = (struct wmi_scan_params_cmd *) skb->data;
2095        sc->fg_start_period = cpu_to_le16(fg_start_sec);
2096        sc->fg_end_period = cpu_to_le16(fg_end_sec);
2097        sc->bg_period = cpu_to_le16(bg_sec);
2098        sc->minact_chdwell_time = cpu_to_le16(minact_chdw_msec);
2099        sc->maxact_chdwell_time = cpu_to_le16(maxact_chdw_msec);
2100        sc->pas_chdwell_time = cpu_to_le16(pas_chdw_msec);
2101        sc->short_scan_ratio = short_scan_ratio;
2102        sc->scan_ctrl_flags = scan_ctrl_flag;
2103        sc->max_dfsch_act_time = cpu_to_le32(max_dfsch_act_time);
2104        sc->maxact_scan_per_ssid = cpu_to_le16(maxact_scan_per_ssid);
2105
2106        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_SCAN_PARAMS_CMDID,
2107                                  NO_SYNC_WMIFLAG);
2108        return ret;
2109}
2110
2111int ath6kl_wmi_bssfilter_cmd(struct wmi *wmi, u8 if_idx, u8 filter, u32 ie_mask)
2112{
2113        struct sk_buff *skb;
2114        struct wmi_bss_filter_cmd *cmd;
2115        int ret;
2116
2117        if (filter >= LAST_BSS_FILTER)
2118                return -EINVAL;
2119
2120        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2121        if (!skb)
2122                return -ENOMEM;
2123
2124        cmd = (struct wmi_bss_filter_cmd *) skb->data;
2125        cmd->bss_filter = filter;
2126        cmd->ie_mask = cpu_to_le32(ie_mask);
2127
2128        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_BSS_FILTER_CMDID,
2129                                  NO_SYNC_WMIFLAG);
2130        return ret;
2131}
2132
2133int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 if_idx, u8 index, u8 flag,
2134                              u8 ssid_len, u8 *ssid)
2135{
2136        struct sk_buff *skb;
2137        struct wmi_probed_ssid_cmd *cmd;
2138        int ret;
2139
2140        if (index >= MAX_PROBED_SSIDS)
2141                return -EINVAL;
2142
2143        if (ssid_len > sizeof(cmd->ssid))
2144                return -EINVAL;
2145
2146        if ((flag & (DISABLE_SSID_FLAG | ANY_SSID_FLAG)) && (ssid_len > 0))
2147                return -EINVAL;
2148
2149        if ((flag & SPECIFIC_SSID_FLAG) && !ssid_len)
2150                return -EINVAL;
2151
2152        if (flag & SPECIFIC_SSID_FLAG)
2153                wmi->is_probe_ssid = true;
2154
2155        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2156        if (!skb)
2157                return -ENOMEM;
2158
2159        cmd = (struct wmi_probed_ssid_cmd *) skb->data;
2160        cmd->entry_index = index;
2161        cmd->flag = flag;
2162        cmd->ssid_len = ssid_len;
2163        memcpy(cmd->ssid, ssid, ssid_len);
2164
2165        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_PROBED_SSID_CMDID,
2166                                  NO_SYNC_WMIFLAG);
2167        return ret;
2168}
2169
2170int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u8 if_idx,
2171                                  u16 listen_interval,
2172                                  u16 listen_beacons)
2173{
2174        struct sk_buff *skb;
2175        struct wmi_listen_int_cmd *cmd;
2176        int ret;
2177
2178        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2179        if (!skb)
2180                return -ENOMEM;
2181
2182        cmd = (struct wmi_listen_int_cmd *) skb->data;
2183        cmd->listen_intvl = cpu_to_le16(listen_interval);
2184        cmd->num_beacons = cpu_to_le16(listen_beacons);
2185
2186        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_LISTEN_INT_CMDID,
2187                                  NO_SYNC_WMIFLAG);
2188        return ret;
2189}
2190
2191int ath6kl_wmi_bmisstime_cmd(struct wmi *wmi, u8 if_idx,
2192                             u16 bmiss_time, u16 num_beacons)
2193{
2194        struct sk_buff *skb;
2195        struct wmi_bmiss_time_cmd *cmd;
2196        int ret;
2197
2198        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2199        if (!skb)
2200                return -ENOMEM;
2201
2202        cmd = (struct wmi_bmiss_time_cmd *) skb->data;
2203        cmd->bmiss_time = cpu_to_le16(bmiss_time);
2204        cmd->num_beacons = cpu_to_le16(num_beacons);
2205
2206        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_BMISS_TIME_CMDID,
2207                                  NO_SYNC_WMIFLAG);
2208        return ret;
2209}
2210
2211int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 if_idx, u8 pwr_mode)
2212{
2213        struct sk_buff *skb;
2214        struct wmi_power_mode_cmd *cmd;
2215        int ret;
2216
2217        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2218        if (!skb)
2219                return -ENOMEM;
2220
2221        cmd = (struct wmi_power_mode_cmd *) skb->data;
2222        cmd->pwr_mode = pwr_mode;
2223        wmi->pwr_mode = pwr_mode;
2224
2225        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_POWER_MODE_CMDID,
2226                                  NO_SYNC_WMIFLAG);
2227        return ret;
2228}
2229
2230int ath6kl_wmi_pmparams_cmd(struct wmi *wmi, u8 if_idx, u16 idle_period,
2231                            u16 ps_poll_num, u16 dtim_policy,
2232                            u16 tx_wakeup_policy, u16 num_tx_to_wakeup,
2233                            u16 ps_fail_event_policy)
2234{
2235        struct sk_buff *skb;
2236        struct wmi_power_params_cmd *pm;
2237        int ret;
2238
2239        skb = ath6kl_wmi_get_new_buf(sizeof(*pm));
2240        if (!skb)
2241                return -ENOMEM;
2242
2243        pm = (struct wmi_power_params_cmd *)skb->data;
2244        pm->idle_period = cpu_to_le16(idle_period);
2245        pm->pspoll_number = cpu_to_le16(ps_poll_num);
2246        pm->dtim_policy = cpu_to_le16(dtim_policy);
2247        pm->tx_wakeup_policy = cpu_to_le16(tx_wakeup_policy);
2248        pm->num_tx_to_wakeup = cpu_to_le16(num_tx_to_wakeup);
2249        pm->ps_fail_event_policy = cpu_to_le16(ps_fail_event_policy);
2250
2251        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_POWER_PARAMS_CMDID,
2252                                  NO_SYNC_WMIFLAG);
2253        return ret;
2254}
2255
2256int ath6kl_wmi_disctimeout_cmd(struct wmi *wmi, u8 if_idx, u8 timeout)
2257{
2258        struct sk_buff *skb;
2259        struct wmi_disc_timeout_cmd *cmd;
2260        int ret;
2261
2262        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2263        if (!skb)
2264                return -ENOMEM;
2265
2266        cmd = (struct wmi_disc_timeout_cmd *) skb->data;
2267        cmd->discon_timeout = timeout;
2268
2269        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_DISC_TIMEOUT_CMDID,
2270                                  NO_SYNC_WMIFLAG);
2271
2272        if (ret == 0)
2273                ath6kl_debug_set_disconnect_timeout(wmi->parent_dev, timeout);
2274
2275        return ret;
2276}
2277
2278int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 if_idx, u8 key_index,
2279                          enum crypto_type key_type,
2280                          u8 key_usage, u8 key_len,
2281                          u8 *key_rsc, unsigned int key_rsc_len,
2282                          u8 *key_material,
2283                          u8 key_op_ctrl, u8 *mac_addr,
2284                          enum wmi_sync_flag sync_flag)
2285{
2286        struct sk_buff *skb;
2287        struct wmi_add_cipher_key_cmd *cmd;
2288        int ret;
2289
2290        ath6kl_dbg(ATH6KL_DBG_WMI,
2291                   "addkey cmd: key_index=%u key_type=%d key_usage=%d key_len=%d key_op_ctrl=%d\n",
2292                   key_index, key_type, key_usage, key_len, key_op_ctrl);
2293
2294        if ((key_index > WMI_MAX_KEY_INDEX) || (key_len > WMI_MAX_KEY_LEN) ||
2295            (key_material == NULL) || key_rsc_len > 8)
2296                return -EINVAL;
2297
2298        if ((WEP_CRYPT != key_type) && (NULL == key_rsc))
2299                return -EINVAL;
2300
2301        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2302        if (!skb)
2303                return -ENOMEM;
2304
2305        cmd = (struct wmi_add_cipher_key_cmd *) skb->data;
2306        cmd->key_index = key_index;
2307        cmd->key_type = key_type;
2308        cmd->key_usage = key_usage;
2309        cmd->key_len = key_len;
2310        memcpy(cmd->key, key_material, key_len);
2311
2312        if (key_rsc != NULL)
2313                memcpy(cmd->key_rsc, key_rsc, key_rsc_len);
2314
2315        cmd->key_op_ctrl = key_op_ctrl;
2316
2317        if (mac_addr)
2318                memcpy(cmd->key_mac_addr, mac_addr, ETH_ALEN);
2319
2320        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_ADD_CIPHER_KEY_CMDID,
2321                                  sync_flag);
2322
2323        return ret;
2324}
2325
2326int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 if_idx, u8 *krk)
2327{
2328        struct sk_buff *skb;
2329        struct wmi_add_krk_cmd *cmd;
2330        int ret;
2331
2332        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2333        if (!skb)
2334                return -ENOMEM;
2335
2336        cmd = (struct wmi_add_krk_cmd *) skb->data;
2337        memcpy(cmd->krk, krk, WMI_KRK_LEN);
2338
2339        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_ADD_KRK_CMDID,
2340                                  NO_SYNC_WMIFLAG);
2341
2342        return ret;
2343}
2344
2345int ath6kl_wmi_deletekey_cmd(struct wmi *wmi, u8 if_idx, u8 key_index)
2346{
2347        struct sk_buff *skb;
2348        struct wmi_delete_cipher_key_cmd *cmd;
2349        int ret;
2350
2351        if (key_index > WMI_MAX_KEY_INDEX)
2352                return -EINVAL;
2353
2354        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2355        if (!skb)
2356                return -ENOMEM;
2357
2358        cmd = (struct wmi_delete_cipher_key_cmd *) skb->data;
2359        cmd->key_index = key_index;
2360
2361        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_DELETE_CIPHER_KEY_CMDID,
2362                                  NO_SYNC_WMIFLAG);
2363
2364        return ret;
2365}
2366
2367int ath6kl_wmi_setpmkid_cmd(struct wmi *wmi, u8 if_idx, const u8 *bssid,
2368                            const u8 *pmkid, bool set)
2369{
2370        struct sk_buff *skb;
2371        struct wmi_setpmkid_cmd *cmd;
2372        int ret;
2373
2374        if (bssid == NULL)
2375                return -EINVAL;
2376
2377        if (set && pmkid == NULL)
2378                return -EINVAL;
2379
2380        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2381        if (!skb)
2382                return -ENOMEM;
2383
2384        cmd = (struct wmi_setpmkid_cmd *) skb->data;
2385        memcpy(cmd->bssid, bssid, ETH_ALEN);
2386        if (set) {
2387                memcpy(cmd->pmkid, pmkid, sizeof(cmd->pmkid));
2388                cmd->enable = PMKID_ENABLE;
2389        } else {
2390                memset(cmd->pmkid, 0, sizeof(cmd->pmkid));
2391                cmd->enable = PMKID_DISABLE;
2392        }
2393
2394        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_PMKID_CMDID,
2395                                  NO_SYNC_WMIFLAG);
2396
2397        return ret;
2398}
2399
2400static int ath6kl_wmi_data_sync_send(struct wmi *wmi, struct sk_buff *skb,
2401                              enum htc_endpoint_id ep_id, u8 if_idx)
2402{
2403        struct wmi_data_hdr *data_hdr;
2404        int ret;
2405
2406        if (WARN_ON(skb == NULL || ep_id == wmi->ep_id)) {
2407                dev_kfree_skb(skb);
2408                return -EINVAL;
2409        }
2410
2411        skb_push(skb, sizeof(struct wmi_data_hdr));
2412
2413        data_hdr = (struct wmi_data_hdr *) skb->data;
2414        data_hdr->info = SYNC_MSGTYPE << WMI_DATA_HDR_MSG_TYPE_SHIFT;
2415        data_hdr->info3 = cpu_to_le16(if_idx & WMI_DATA_HDR_IF_IDX_MASK);
2416
2417        ret = ath6kl_control_tx(wmi->parent_dev, skb, ep_id);
2418
2419        return ret;
2420}
2421
2422static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)
2423{
2424        struct sk_buff *skb;
2425        struct wmi_sync_cmd *cmd;
2426        struct wmi_data_sync_bufs data_sync_bufs[WMM_NUM_AC];
2427        enum htc_endpoint_id ep_id;
2428        u8 index, num_pri_streams = 0;
2429        int ret = 0;
2430
2431        memset(data_sync_bufs, 0, sizeof(data_sync_bufs));
2432
2433        spin_lock_bh(&wmi->lock);
2434
2435        for (index = 0; index < WMM_NUM_AC; index++) {
2436                if (wmi->fat_pipe_exist & (1 << index)) {
2437                        num_pri_streams++;
2438                        data_sync_bufs[num_pri_streams - 1].traffic_class =
2439                            index;
2440                }
2441        }
2442
2443        spin_unlock_bh(&wmi->lock);
2444
2445        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2446        if (!skb)
2447                return -ENOMEM;
2448
2449        cmd = (struct wmi_sync_cmd *) skb->data;
2450
2451        /*
2452         * In the SYNC cmd sent on the control Ep, send a bitmap
2453         * of the data eps on which the Data Sync will be sent
2454         */
2455        cmd->data_sync_map = wmi->fat_pipe_exist;
2456
2457        for (index = 0; index < num_pri_streams; index++) {
2458                data_sync_bufs[index].skb = ath6kl_buf_alloc(0);
2459                if (data_sync_bufs[index].skb == NULL) {
2460                        ret = -ENOMEM;
2461                        break;
2462                }
2463        }
2464
2465        /*
2466         * If buffer allocation for any of the dataSync fails,
2467         * then do not send the Synchronize cmd on the control ep
2468         */
2469        if (ret)
2470                goto free_cmd_skb;
2471
2472        /*
2473         * Send sync cmd followed by sync data messages on all
2474         * endpoints being used
2475         */
2476        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SYNCHRONIZE_CMDID,
2477                                  NO_SYNC_WMIFLAG);
2478
2479        if (ret)
2480                goto free_data_skb;
2481
2482        for (index = 0; index < num_pri_streams; index++) {
2483
2484                if (WARN_ON(!data_sync_bufs[index].skb))
2485                        goto free_data_skb;
2486
2487                ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev,
2488                                               data_sync_bufs[index].
2489                                               traffic_class);
2490                ret =
2491                    ath6kl_wmi_data_sync_send(wmi, data_sync_bufs[index].skb,
2492                                              ep_id, if_idx);
2493
2494                data_sync_bufs[index].skb = NULL;
2495
2496                if (ret)
2497                        goto free_data_skb;
2498        }
2499
2500        return 0;
2501
2502free_cmd_skb:
2503        /* free up any resources left over (possibly due to an error) */
2504        dev_kfree_skb(skb);
2505
2506free_data_skb:
2507        for (index = 0; index < num_pri_streams; index++)
2508                dev_kfree_skb((struct sk_buff *)data_sync_bufs[index].skb);
2509
2510        return ret;
2511}
2512
2513int ath6kl_wmi_create_pstream_cmd(struct wmi *wmi, u8 if_idx,
2514                                  struct wmi_create_pstream_cmd *params)
2515{
2516        struct sk_buff *skb;
2517        struct wmi_create_pstream_cmd *cmd;
2518        u8 fatpipe_exist_for_ac = 0;
2519        s32 min_phy = 0;
2520        s32 nominal_phy = 0;
2521        int ret;
2522
2523        if (!((params->user_pri < 8) &&
2524              (params->user_pri <= 0x7) &&
2525              (up_to_ac[params->user_pri & 0x7] == params->traffic_class) &&
2526              (params->traffic_direc == UPLINK_TRAFFIC ||
2527               params->traffic_direc == DNLINK_TRAFFIC ||
2528               params->traffic_direc == BIDIR_TRAFFIC) &&
2529              (params->traffic_type == TRAFFIC_TYPE_APERIODIC ||
2530               params->traffic_type == TRAFFIC_TYPE_PERIODIC) &&
2531              (params->voice_psc_cap == DISABLE_FOR_THIS_AC ||
2532               params->voice_psc_cap == ENABLE_FOR_THIS_AC ||
2533               params->voice_psc_cap == ENABLE_FOR_ALL_AC) &&
2534              (params->tsid == WMI_IMPLICIT_PSTREAM ||
2535               params->tsid <= WMI_MAX_THINSTREAM))) {
2536                return -EINVAL;
2537        }
2538
2539        /*
2540         * Check nominal PHY rate is >= minimalPHY,
2541         * so that DUT can allow TSRS IE
2542         */
2543
2544        /* Get the physical rate (units of bps) */
2545        min_phy = ((le32_to_cpu(params->min_phy_rate) / 1000) / 1000);
2546
2547        /* Check minimal phy < nominal phy rate */
2548        if (params->nominal_phy >= min_phy) {
2549                /* unit of 500 kbps */
2550                nominal_phy = (params->nominal_phy * 1000) / 500;
2551                ath6kl_dbg(ATH6KL_DBG_WMI,
2552                           "TSRS IE enabled::MinPhy %x->NominalPhy ===> %x\n",
2553                           min_phy, nominal_phy);
2554
2555                params->nominal_phy = nominal_phy;
2556        } else {
2557                params->nominal_phy = 0;
2558        }
2559
2560        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2561        if (!skb)
2562                return -ENOMEM;
2563
2564        ath6kl_dbg(ATH6KL_DBG_WMI,
2565                   "sending create_pstream_cmd: ac=%d  tsid:%d\n",
2566                   params->traffic_class, params->tsid);
2567
2568        cmd = (struct wmi_create_pstream_cmd *) skb->data;
2569        memcpy(cmd, params, sizeof(*cmd));
2570
2571        /* This is an implicitly created Fat pipe */
2572        if ((u32) params->tsid == (u32) WMI_IMPLICIT_PSTREAM) {
2573                spin_lock_bh(&wmi->lock);
2574                fatpipe_exist_for_ac = (wmi->fat_pipe_exist &
2575                                        (1 << params->traffic_class));
2576                wmi->fat_pipe_exist |= (1 << params->traffic_class);
2577                spin_unlock_bh(&wmi->lock);
2578        } else {
2579                /* explicitly created thin stream within a fat pipe */
2580                spin_lock_bh(&wmi->lock);
2581                fatpipe_exist_for_ac = (wmi->fat_pipe_exist &
2582                                        (1 << params->traffic_class));
2583                wmi->stream_exist_for_ac[params->traffic_class] |=
2584                    (1 << params->tsid);
2585                /*
2586                 * If a thinstream becomes active, the fat pipe automatically
2587                 * becomes active
2588                 */
2589                wmi->fat_pipe_exist |= (1 << params->traffic_class);
2590                spin_unlock_bh(&wmi->lock);
2591        }
2592
2593        /*
2594         * Indicate activty change to driver layer only if this is the
2595         * first TSID to get created in this AC explicitly or an implicit
2596         * fat pipe is getting created.
2597         */
2598        if (!fatpipe_exist_for_ac)
2599                ath6kl_indicate_tx_activity(wmi->parent_dev,
2600                                            params->traffic_class, true);
2601
2602        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_CREATE_PSTREAM_CMDID,
2603                                  NO_SYNC_WMIFLAG);
2604        return ret;
2605}
2606
2607int ath6kl_wmi_delete_pstream_cmd(struct wmi *wmi, u8 if_idx, u8 traffic_class,
2608                                  u8 tsid)
2609{
2610        struct sk_buff *skb;
2611        struct wmi_delete_pstream_cmd *cmd;
2612        u16 active_tsids = 0;
2613        int ret;
2614
2615        if (traffic_class > 3) {
2616                ath6kl_err("invalid traffic class: %d\n", traffic_class);
2617                return -EINVAL;
2618        }
2619
2620        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2621        if (!skb)
2622                return -ENOMEM;
2623
2624        cmd = (struct wmi_delete_pstream_cmd *) skb->data;
2625        cmd->traffic_class = traffic_class;
2626        cmd->tsid = tsid;
2627
2628        spin_lock_bh(&wmi->lock);
2629        active_tsids = wmi->stream_exist_for_ac[traffic_class];
2630        spin_unlock_bh(&wmi->lock);
2631
2632        if (!(active_tsids & (1 << tsid))) {
2633                dev_kfree_skb(skb);
2634                ath6kl_dbg(ATH6KL_DBG_WMI,
2635                           "TSID %d doesn't exist for traffic class: %d\n",
2636                           tsid, traffic_class);
2637                return -ENODATA;
2638        }
2639
2640        ath6kl_dbg(ATH6KL_DBG_WMI,
2641                   "sending delete_pstream_cmd: traffic class: %d tsid=%d\n",
2642                   traffic_class, tsid);
2643
2644        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_DELETE_PSTREAM_CMDID,
2645                                  SYNC_BEFORE_WMIFLAG);
2646
2647        spin_lock_bh(&wmi->lock);
2648        wmi->stream_exist_for_ac[traffic_class] &= ~(1 << tsid);
2649        active_tsids = wmi->stream_exist_for_ac[traffic_class];
2650        spin_unlock_bh(&wmi->lock);
2651
2652        /*
2653         * Indicate stream inactivity to driver layer only if all tsids
2654         * within this AC are deleted.
2655         */
2656        if (!active_tsids) {
2657                ath6kl_indicate_tx_activity(wmi->parent_dev,
2658                                            traffic_class, false);
2659                wmi->fat_pipe_exist &= ~(1 << traffic_class);
2660        }
2661
2662        return ret;
2663}
2664
2665int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, u8 if_idx,
2666                          __be32 ips0, __be32 ips1)
2667{
2668        struct sk_buff *skb;
2669        struct wmi_set_ip_cmd *cmd;
2670        int ret;
2671
2672        /* Multicast address are not valid */
2673        if (ipv4_is_multicast(ips0) ||
2674            ipv4_is_multicast(ips1))
2675                return -EINVAL;
2676
2677        skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_ip_cmd));
2678        if (!skb)
2679                return -ENOMEM;
2680
2681        cmd = (struct wmi_set_ip_cmd *) skb->data;
2682        cmd->ips[0] = ips0;
2683        cmd->ips[1] = ips1;
2684
2685        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_IP_CMDID,
2686                                  NO_SYNC_WMIFLAG);
2687        return ret;
2688}
2689
2690static void ath6kl_wmi_relinquish_implicit_pstream_credits(struct wmi *wmi)
2691{
2692        u16 active_tsids;
2693        u8 stream_exist;
2694        int i;
2695
2696        /*
2697         * Relinquish credits from all implicitly created pstreams
2698         * since when we go to sleep. If user created explicit
2699         * thinstreams exists with in a fatpipe leave them intact
2700         * for the user to delete.
2701         */
2702        spin_lock_bh(&wmi->lock);
2703        stream_exist = wmi->fat_pipe_exist;
2704        spin_unlock_bh(&wmi->lock);
2705
2706        for (i = 0; i < WMM_NUM_AC; i++) {
2707                if (stream_exist & (1 << i)) {
2708
2709                        /*
2710                         * FIXME: Is this lock & unlock inside
2711                         * for loop correct? may need rework.
2712                         */
2713                        spin_lock_bh(&wmi->lock);
2714                        active_tsids = wmi->stream_exist_for_ac[i];
2715                        spin_unlock_bh(&wmi->lock);
2716
2717                        /*
2718                         * If there are no user created thin streams
2719                         * delete the fatpipe
2720                         */
2721                        if (!active_tsids) {
2722                                stream_exist &= ~(1 << i);
2723                                /*
2724                                 * Indicate inactivity to driver layer for
2725                                 * this fatpipe (pstream)
2726                                 */
2727                                ath6kl_indicate_tx_activity(wmi->parent_dev,
2728                                                            i, false);
2729                        }
2730                }
2731        }
2732
2733        /* FIXME: Can we do this assignment without locking ? */
2734        spin_lock_bh(&wmi->lock);
2735        wmi->fat_pipe_exist = stream_exist;
2736        spin_unlock_bh(&wmi->lock);
2737}
2738
2739static int ath6kl_set_bitrate_mask64(struct wmi *wmi, u8 if_idx,
2740                                     const struct cfg80211_bitrate_mask *mask)
2741{
2742        struct sk_buff *skb;
2743        int ret, mode, band;
2744        u64 mcsrate, ratemask[ATH6KL_NUM_BANDS];
2745        struct wmi_set_tx_select_rates64_cmd *cmd;
2746
2747        memset(&ratemask, 0, sizeof(ratemask));
2748
2749        /* only check 2.4 and 5 GHz bands, skip the rest */
2750        for (band = 0; band <= IEEE80211_BAND_5GHZ; band++) {
2751                /* copy legacy rate mask */
2752                ratemask[band] = mask->control[band].legacy;
2753                if (band == IEEE80211_BAND_5GHZ)
2754                        ratemask[band] =
2755                                mask->control[band].legacy << 4;
2756
2757                /* copy mcs rate mask */
2758                mcsrate = mask->control[band].mcs[1];
2759                mcsrate <<= 8;
2760                mcsrate |= mask->control[band].mcs[0];
2761                ratemask[band] |= mcsrate << 12;
2762                ratemask[band] |= mcsrate << 28;
2763        }
2764
2765        ath6kl_dbg(ATH6KL_DBG_WMI,
2766                   "Ratemask 64 bit: 2.4:%llx 5:%llx\n",
2767                   ratemask[0], ratemask[1]);
2768
2769        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd) * WMI_RATES_MODE_MAX);
2770        if (!skb)
2771                return -ENOMEM;
2772
2773        cmd = (struct wmi_set_tx_select_rates64_cmd *) skb->data;
2774        for (mode = 0; mode < WMI_RATES_MODE_MAX; mode++) {
2775                /* A mode operate in 5GHZ band */
2776                if (mode == WMI_RATES_MODE_11A ||
2777                    mode == WMI_RATES_MODE_11A_HT20 ||
2778                    mode == WMI_RATES_MODE_11A_HT40)
2779                        band = IEEE80211_BAND_5GHZ;
2780                else
2781                        band = IEEE80211_BAND_2GHZ;
2782                cmd->ratemask[mode] = cpu_to_le64(ratemask[band]);
2783        }
2784
2785        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
2786                                  WMI_SET_TX_SELECT_RATES_CMDID,
2787                                  NO_SYNC_WMIFLAG);
2788        return ret;
2789}
2790
2791static int ath6kl_set_bitrate_mask32(struct wmi *wmi, u8 if_idx,
2792                                     const struct cfg80211_bitrate_mask *mask)
2793{
2794        struct sk_buff *skb;
2795        int ret, mode, band;
2796        u32 mcsrate, ratemask[ATH6KL_NUM_BANDS];
2797        struct wmi_set_tx_select_rates32_cmd *cmd;
2798
2799        memset(&ratemask, 0, sizeof(ratemask));
2800
2801        /* only check 2.4 and 5 GHz bands, skip the rest */
2802        for (band = 0; band <= IEEE80211_BAND_5GHZ; band++) {
2803                /* copy legacy rate mask */
2804                ratemask[band] = mask->control[band].legacy;
2805                if (band == IEEE80211_BAND_5GHZ)
2806                        ratemask[band] =
2807                                mask->control[band].legacy << 4;
2808
2809                /* copy mcs rate mask */
2810                mcsrate = mask->control[band].mcs[0];
2811                ratemask[band] |= mcsrate << 12;
2812                ratemask[band] |= mcsrate << 20;
2813        }
2814
2815        ath6kl_dbg(ATH6KL_DBG_WMI,
2816                   "Ratemask 32 bit: 2.4:%x 5:%x\n",
2817                   ratemask[0], ratemask[1]);
2818
2819        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd) * WMI_RATES_MODE_MAX);
2820        if (!skb)
2821                return -ENOMEM;
2822
2823        cmd = (struct wmi_set_tx_select_rates32_cmd *) skb->data;
2824        for (mode = 0; mode < WMI_RATES_MODE_MAX; mode++) {
2825                /* A mode operate in 5GHZ band */
2826                if (mode == WMI_RATES_MODE_11A ||
2827                    mode == WMI_RATES_MODE_11A_HT20 ||
2828                    mode == WMI_RATES_MODE_11A_HT40)
2829                        band = IEEE80211_BAND_5GHZ;
2830                else
2831                        band = IEEE80211_BAND_2GHZ;
2832                cmd->ratemask[mode] = cpu_to_le32(ratemask[band]);
2833        }
2834
2835        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
2836                                  WMI_SET_TX_SELECT_RATES_CMDID,
2837                                  NO_SYNC_WMIFLAG);
2838        return ret;
2839}
2840
2841int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx,
2842                                const struct cfg80211_bitrate_mask *mask)
2843{
2844        struct ath6kl *ar = wmi->parent_dev;
2845
2846        if (ar->hw.flags & ATH6KL_HW_64BIT_RATES)
2847                return ath6kl_set_bitrate_mask64(wmi, if_idx, mask);
2848        else
2849                return ath6kl_set_bitrate_mask32(wmi, if_idx, mask);
2850}
2851
2852int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx,
2853                                       enum ath6kl_host_mode host_mode)
2854{
2855        struct sk_buff *skb;
2856        struct wmi_set_host_sleep_mode_cmd *cmd;
2857        int ret;
2858
2859        if ((host_mode != ATH6KL_HOST_MODE_ASLEEP) &&
2860            (host_mode != ATH6KL_HOST_MODE_AWAKE)) {
2861                ath6kl_err("invalid host sleep mode: %d\n", host_mode);
2862                return -EINVAL;
2863        }
2864
2865        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2866        if (!skb)
2867                return -ENOMEM;
2868
2869        cmd = (struct wmi_set_host_sleep_mode_cmd *) skb->data;
2870
2871        if (host_mode == ATH6KL_HOST_MODE_ASLEEP) {
2872                ath6kl_wmi_relinquish_implicit_pstream_credits(wmi);
2873                cmd->asleep = cpu_to_le32(1);
2874        } else
2875                cmd->awake = cpu_to_le32(1);
2876
2877        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
2878                                  WMI_SET_HOST_SLEEP_MODE_CMDID,
2879                                  NO_SYNC_WMIFLAG);
2880        return ret;
2881}
2882
2883/* This command has zero length payload */
2884static int ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx(struct wmi *wmi,
2885                                                      struct ath6kl_vif *vif)
2886{
2887        struct ath6kl *ar = wmi->parent_dev;
2888
2889        set_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags);
2890        wake_up(&ar->event_wq);
2891
2892        return 0;
2893}
2894
2895int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx,
2896                                enum ath6kl_wow_mode wow_mode,
2897                                u32 filter, u16 host_req_delay)
2898{
2899        struct sk_buff *skb;
2900        struct wmi_set_wow_mode_cmd *cmd;
2901        int ret;
2902
2903        if ((wow_mode != ATH6KL_WOW_MODE_ENABLE) &&
2904            wow_mode != ATH6KL_WOW_MODE_DISABLE) {
2905                ath6kl_err("invalid wow mode: %d\n", wow_mode);
2906                return -EINVAL;
2907        }
2908
2909        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2910        if (!skb)
2911                return -ENOMEM;
2912
2913        cmd = (struct wmi_set_wow_mode_cmd *) skb->data;
2914        cmd->enable_wow = cpu_to_le32(wow_mode);
2915        cmd->filter = cpu_to_le32(filter);
2916        cmd->host_req_delay = cpu_to_le16(host_req_delay);
2917
2918        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_WOW_MODE_CMDID,
2919                                  NO_SYNC_WMIFLAG);
2920        return ret;
2921}
2922
2923int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
2924                                   u8 list_id, u8 filter_size,
2925                                   u8 filter_offset, const u8 *filter,
2926                                   const u8 *mask)
2927{
2928        struct sk_buff *skb;
2929        struct wmi_add_wow_pattern_cmd *cmd;
2930        u16 size;
2931        u8 *filter_mask;
2932        int ret;
2933
2934        /*
2935         * Allocate additional memory in the buffer to hold
2936         * filter and mask value, which is twice of filter_size.
2937         */
2938        size = sizeof(*cmd) + (2 * filter_size);
2939
2940        skb = ath6kl_wmi_get_new_buf(size);
2941        if (!skb)
2942                return -ENOMEM;
2943
2944        cmd = (struct wmi_add_wow_pattern_cmd *) skb->data;
2945        cmd->filter_list_id = list_id;
2946        cmd->filter_size = filter_size;
2947        cmd->filter_offset = filter_offset;
2948
2949        memcpy(cmd->filter, filter, filter_size);
2950
2951        filter_mask = (u8 *) (cmd->filter + filter_size);
2952        memcpy(filter_mask, mask, filter_size);
2953
2954        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_ADD_WOW_PATTERN_CMDID,
2955                                  NO_SYNC_WMIFLAG);
2956
2957        return ret;
2958}
2959
2960int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
2961                                   u16 list_id, u16 filter_id)
2962{
2963        struct sk_buff *skb;
2964        struct wmi_del_wow_pattern_cmd *cmd;
2965        int ret;
2966
2967        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2968        if (!skb)
2969                return -ENOMEM;
2970
2971        cmd = (struct wmi_del_wow_pattern_cmd *) skb->data;
2972        cmd->filter_list_id = cpu_to_le16(list_id);
2973        cmd->filter_id = cpu_to_le16(filter_id);
2974
2975        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_DEL_WOW_PATTERN_CMDID,
2976                                  NO_SYNC_WMIFLAG);
2977        return ret;
2978}
2979
2980static int ath6kl_wmi_cmd_send_xtnd(struct wmi *wmi, struct sk_buff *skb,
2981                                    enum wmix_command_id cmd_id,
2982                                    enum wmi_sync_flag sync_flag)
2983{
2984        struct wmix_cmd_hdr *cmd_hdr;
2985        int ret;
2986
2987        skb_push(skb, sizeof(struct wmix_cmd_hdr));
2988
2989        cmd_hdr = (struct wmix_cmd_hdr *) skb->data;
2990        cmd_hdr->cmd_id = cpu_to_le32(cmd_id);
2991
2992        ret = ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_EXTENSION_CMDID, sync_flag);
2993
2994        return ret;
2995}
2996
2997int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source)
2998{
2999        struct sk_buff *skb;
3000        struct wmix_hb_challenge_resp_cmd *cmd;
3001        int ret;
3002
3003        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3004        if (!skb)
3005                return -ENOMEM;
3006
3007        cmd = (struct wmix_hb_challenge_resp_cmd *) skb->data;
3008        cmd->cookie = cpu_to_le32(cookie);
3009        cmd->source = cpu_to_le32(source);
3010
3011        ret = ath6kl_wmi_cmd_send_xtnd(wmi, skb, WMIX_HB_CHALLENGE_RESP_CMDID,
3012                                       NO_SYNC_WMIFLAG);
3013        return ret;
3014}
3015
3016int ath6kl_wmi_config_debug_module_cmd(struct wmi *wmi, u32 valid, u32 config)
3017{
3018        struct ath6kl_wmix_dbglog_cfg_module_cmd *cmd;
3019        struct sk_buff *skb;
3020        int ret;
3021
3022        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3023        if (!skb)
3024                return -ENOMEM;
3025
3026        cmd = (struct ath6kl_wmix_dbglog_cfg_module_cmd *) skb->data;
3027        cmd->valid = cpu_to_le32(valid);
3028        cmd->config = cpu_to_le32(config);
3029
3030        ret = ath6kl_wmi_cmd_send_xtnd(wmi, skb, WMIX_DBGLOG_CFG_MODULE_CMDID,
3031                                       NO_SYNC_WMIFLAG);
3032        return ret;
3033}
3034
3035int ath6kl_wmi_get_stats_cmd(struct wmi *wmi, u8 if_idx)
3036{
3037        return ath6kl_wmi_simple_cmd(wmi, if_idx, WMI_GET_STATISTICS_CMDID);
3038}
3039
3040int ath6kl_wmi_set_tx_pwr_cmd(struct wmi *wmi, u8 if_idx, u8 dbM)
3041{
3042        struct sk_buff *skb;
3043        struct wmi_set_tx_pwr_cmd *cmd;
3044        int ret;
3045
3046        skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_tx_pwr_cmd));
3047        if (!skb)
3048                return -ENOMEM;
3049
3050        cmd = (struct wmi_set_tx_pwr_cmd *) skb->data;
3051        cmd->dbM = dbM;
3052
3053        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_TX_PWR_CMDID,
3054                                  NO_SYNC_WMIFLAG);
3055
3056        return ret;
3057}
3058
3059int ath6kl_wmi_get_tx_pwr_cmd(struct wmi *wmi, u8 if_idx)
3060{
3061        return ath6kl_wmi_simple_cmd(wmi, if_idx, WMI_GET_TX_PWR_CMDID);
3062}
3063
3064int ath6kl_wmi_get_roam_tbl_cmd(struct wmi *wmi)
3065{
3066        return ath6kl_wmi_simple_cmd(wmi, 0, WMI_GET_ROAM_TBL_CMDID);
3067}
3068
3069int ath6kl_wmi_set_lpreamble_cmd(struct wmi *wmi, u8 if_idx, u8 status,
3070                                 u8 preamble_policy)
3071{
3072        struct sk_buff *skb;
3073        struct wmi_set_lpreamble_cmd *cmd;
3074        int ret;
3075
3076        skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_lpreamble_cmd));
3077        if (!skb)
3078                return -ENOMEM;
3079
3080        cmd = (struct wmi_set_lpreamble_cmd *) skb->data;
3081        cmd->status = status;
3082        cmd->preamble_policy = preamble_policy;
3083
3084        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_LPREAMBLE_CMDID,
3085                                  NO_SYNC_WMIFLAG);
3086        return ret;
3087}
3088
3089int ath6kl_wmi_set_rts_cmd(struct wmi *wmi, u16 threshold)
3090{
3091        struct sk_buff *skb;
3092        struct wmi_set_rts_cmd *cmd;
3093        int ret;
3094
3095        skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_rts_cmd));
3096        if (!skb)
3097                return -ENOMEM;
3098
3099        cmd = (struct wmi_set_rts_cmd *) skb->data;
3100        cmd->threshold = cpu_to_le16(threshold);
3101
3102        ret = ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_RTS_CMDID,
3103                                  NO_SYNC_WMIFLAG);
3104        return ret;
3105}
3106
3107int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, u8 if_idx, enum wmi_txop_cfg cfg)
3108{
3109        struct sk_buff *skb;
3110        struct wmi_set_wmm_txop_cmd *cmd;
3111        int ret;
3112
3113        if (!((cfg == WMI_TXOP_DISABLED) || (cfg == WMI_TXOP_ENABLED)))
3114                return -EINVAL;
3115
3116        skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_wmm_txop_cmd));
3117        if (!skb)
3118                return -ENOMEM;
3119
3120        cmd = (struct wmi_set_wmm_txop_cmd *) skb->data;
3121        cmd->txop_enable = cfg;
3122
3123        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_WMM_TXOP_CMDID,
3124                                  NO_SYNC_WMIFLAG);
3125        return ret;
3126}
3127
3128int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 if_idx,
3129                                 u8 keep_alive_intvl)
3130{
3131        struct sk_buff *skb;
3132        struct wmi_set_keepalive_cmd *cmd;
3133        int ret;
3134
3135        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3136        if (!skb)
3137                return -ENOMEM;
3138
3139        cmd = (struct wmi_set_keepalive_cmd *) skb->data;
3140        cmd->keep_alive_intvl = keep_alive_intvl;
3141
3142        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_KEEPALIVE_CMDID,
3143                                  NO_SYNC_WMIFLAG);
3144
3145        if (ret == 0)
3146                ath6kl_debug_set_keepalive(wmi->parent_dev, keep_alive_intvl);
3147
3148        return ret;
3149}
3150
3151int ath6kl_wmi_set_htcap_cmd(struct wmi *wmi, u8 if_idx,
3152                             enum ieee80211_band band,
3153                             struct ath6kl_htcap *htcap)
3154{
3155        struct sk_buff *skb;
3156        struct wmi_set_htcap_cmd *cmd;
3157
3158        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3159        if (!skb)
3160                return -ENOMEM;
3161
3162        cmd = (struct wmi_set_htcap_cmd *) skb->data;
3163
3164        /*
3165         * NOTE: Band in firmware matches enum ieee80211_band, it is unlikely
3166         * this will be changed in firmware. If at all there is any change in
3167         * band value, the host needs to be fixed.
3168         */
3169        cmd->band = band;
3170        cmd->ht_enable = !!htcap->ht_enable;
3171        cmd->ht20_sgi = !!(htcap->cap_info & IEEE80211_HT_CAP_SGI_20);
3172        cmd->ht40_supported =
3173                !!(htcap->cap_info & IEEE80211_HT_CAP_SUP_WIDTH_20_40);
3174        cmd->ht40_sgi = !!(htcap->cap_info & IEEE80211_HT_CAP_SGI_40);
3175        cmd->intolerant_40mhz =
3176                !!(htcap->cap_info & IEEE80211_HT_CAP_40MHZ_INTOLERANT);
3177        cmd->max_ampdu_len_exp = htcap->ampdu_factor;
3178
3179        ath6kl_dbg(ATH6KL_DBG_WMI,
3180                   "Set htcap: band:%d ht_enable:%d 40mhz:%d sgi_20mhz:%d sgi_40mhz:%d 40mhz_intolerant:%d ampdu_len_exp:%d\n",
3181                   cmd->band, cmd->ht_enable, cmd->ht40_supported,
3182                   cmd->ht20_sgi, cmd->ht40_sgi, cmd->intolerant_40mhz,
3183                   cmd->max_ampdu_len_exp);
3184        return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_HT_CAP_CMDID,
3185                                   NO_SYNC_WMIFLAG);
3186}
3187
3188int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len)
3189{
3190        struct sk_buff *skb;
3191        int ret;
3192
3193        skb = ath6kl_wmi_get_new_buf(len);
3194        if (!skb)
3195                return -ENOMEM;
3196
3197        memcpy(skb->data, buf, len);
3198
3199        ret = ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_TEST_CMDID, NO_SYNC_WMIFLAG);
3200
3201        return ret;
3202}
3203
3204int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on)
3205{
3206        struct sk_buff *skb;
3207        struct wmi_mcast_filter_cmd *cmd;
3208        int ret;
3209
3210        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3211        if (!skb)
3212                return -ENOMEM;
3213
3214        cmd = (struct wmi_mcast_filter_cmd *) skb->data;
3215        cmd->mcast_all_enable = mc_all_on;
3216
3217        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_MCAST_FILTER_CMDID,
3218                                  NO_SYNC_WMIFLAG);
3219        return ret;
3220}
3221
3222int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx,
3223                                        u8 *filter, bool add_filter)
3224{
3225        struct sk_buff *skb;
3226        struct wmi_mcast_filter_add_del_cmd *cmd;
3227        int ret;
3228
3229        if ((filter[0] != 0x33 || filter[1] != 0x33) &&
3230            (filter[0] != 0x01 || filter[1] != 0x00 ||
3231            filter[2] != 0x5e || filter[3] > 0x7f)) {
3232                ath6kl_warn("invalid multicast filter address\n");
3233                return -EINVAL;
3234        }
3235
3236        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3237        if (!skb)
3238                return -ENOMEM;
3239
3240        cmd = (struct wmi_mcast_filter_add_del_cmd *) skb->data;
3241        memcpy(cmd->mcast_mac, filter, ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE);
3242        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
3243                                  add_filter ? WMI_SET_MCAST_FILTER_CMDID :
3244                                  WMI_DEL_MCAST_FILTER_CMDID,
3245                                  NO_SYNC_WMIFLAG);
3246
3247        return ret;
3248}
3249
3250int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enhance)
3251{
3252        struct sk_buff *skb;
3253        struct wmi_sta_bmiss_enhance_cmd *cmd;
3254        int ret;
3255
3256        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3257        if (!skb)
3258                return -ENOMEM;
3259
3260        cmd = (struct wmi_sta_bmiss_enhance_cmd *) skb->data;
3261        cmd->enable = enhance ? 1 : 0;
3262
3263        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
3264                                  WMI_STA_BMISS_ENHANCE_CMDID,
3265                                  NO_SYNC_WMIFLAG);
3266        return ret;
3267}
3268
3269int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2)
3270{
3271        struct sk_buff *skb;
3272        struct wmi_set_regdomain_cmd *cmd;
3273
3274        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3275        if (!skb)
3276                return -ENOMEM;
3277
3278        cmd = (struct wmi_set_regdomain_cmd *) skb->data;
3279        memcpy(cmd->iso_name, alpha2, 2);
3280
3281        return ath6kl_wmi_cmd_send(wmi, 0, skb,
3282                                   WMI_SET_REGDOMAIN_CMDID,
3283                                   NO_SYNC_WMIFLAG);
3284}
3285
3286s32 ath6kl_wmi_get_rate(s8 rate_index)
3287{
3288        u8 sgi = 0;
3289
3290        if (rate_index == RATE_AUTO)
3291                return 0;
3292
3293        /* SGI is stored as the MSB of the rate_index */
3294        if (rate_index & RATE_INDEX_MSB) {
3295                rate_index &= RATE_INDEX_WITHOUT_SGI_MASK;
3296                sgi = 1;
3297        }
3298
3299        if (WARN_ON(rate_index > RATE_MCS_7_40))
3300                rate_index = RATE_MCS_7_40;
3301
3302        return wmi_rate_tbl[(u32) rate_index][sgi];
3303}
3304
3305static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap,
3306                                              u32 len)
3307{
3308        struct wmi_pmkid_list_reply *reply;
3309        u32 expected_len;
3310
3311        if (len < sizeof(struct wmi_pmkid_list_reply))
3312                return -EINVAL;
3313
3314        reply = (struct wmi_pmkid_list_reply *)datap;
3315        expected_len = sizeof(reply->num_pmkid) +
3316                le32_to_cpu(reply->num_pmkid) * WMI_PMKID_LEN;
3317
3318        if (len < expected_len)
3319                return -EINVAL;
3320
3321        return 0;
3322}
3323
3324static int ath6kl_wmi_addba_req_event_rx(struct wmi *wmi, u8 *datap, int len,
3325                                         struct ath6kl_vif *vif)
3326{
3327        struct wmi_addba_req_event *cmd = (struct wmi_addba_req_event *) datap;
3328
3329        aggr_recv_addba_req_evt(vif, cmd->tid,
3330                                le16_to_cpu(cmd->st_seq_no), cmd->win_sz);
3331
3332        return 0;
3333}
3334
3335static int ath6kl_wmi_delba_req_event_rx(struct wmi *wmi, u8 *datap, int len,
3336                                         struct ath6kl_vif *vif)
3337{
3338        struct wmi_delba_event *cmd = (struct wmi_delba_event *) datap;
3339
3340        aggr_recv_delba_req_evt(vif, cmd->tid);
3341
3342        return 0;
3343}
3344
3345/*  AP mode functions */
3346
3347int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, u8 if_idx,
3348                                 struct wmi_connect_cmd *p)
3349{
3350        struct sk_buff *skb;
3351        struct wmi_connect_cmd *cm;
3352        int res;
3353
3354        skb = ath6kl_wmi_get_new_buf(sizeof(*cm));
3355        if (!skb)
3356                return -ENOMEM;
3357
3358        cm = (struct wmi_connect_cmd *) skb->data;
3359        memcpy(cm, p, sizeof(*cm));
3360
3361        res = ath6kl_wmi_cmd_send(wmip, if_idx, skb, WMI_AP_CONFIG_COMMIT_CMDID,
3362                                  NO_SYNC_WMIFLAG);
3363        ath6kl_dbg(ATH6KL_DBG_WMI,
3364                   "%s: nw_type=%u auth_mode=%u ch=%u ctrl_flags=0x%x-> res=%d\n",
3365                   __func__, p->nw_type, p->auth_mode, le16_to_cpu(p->ch),
3366                   le32_to_cpu(p->ctrl_flags), res);
3367        return res;
3368}
3369
3370int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 if_idx, u8 cmd, const u8 *mac,
3371                           u16 reason)
3372{
3373        struct sk_buff *skb;
3374        struct wmi_ap_set_mlme_cmd *cm;
3375
3376        skb = ath6kl_wmi_get_new_buf(sizeof(*cm));
3377        if (!skb)
3378                return -ENOMEM;
3379
3380        cm = (struct wmi_ap_set_mlme_cmd *) skb->data;
3381        memcpy(cm->mac, mac, ETH_ALEN);
3382        cm->reason = cpu_to_le16(reason);
3383        cm->cmd = cmd;
3384
3385        ath6kl_dbg(ATH6KL_DBG_WMI, "ap_set_mlme: cmd=%d reason=%d\n", cm->cmd,
3386                   cm->reason);
3387
3388        return ath6kl_wmi_cmd_send(wmip, if_idx, skb, WMI_AP_SET_MLME_CMDID,
3389                                   NO_SYNC_WMIFLAG);
3390}
3391
3392int ath6kl_wmi_ap_hidden_ssid(struct wmi *wmi, u8 if_idx, bool enable)
3393{
3394        struct sk_buff *skb;
3395        struct wmi_ap_hidden_ssid_cmd *cmd;
3396
3397        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3398        if (!skb)
3399                return -ENOMEM;
3400
3401        cmd = (struct wmi_ap_hidden_ssid_cmd *) skb->data;
3402        cmd->hidden_ssid = enable ? 1 : 0;
3403
3404        return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_HIDDEN_SSID_CMDID,
3405                                   NO_SYNC_WMIFLAG);
3406}
3407
3408/* This command will be used to enable/disable AP uAPSD feature */
3409int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable)
3410{
3411        struct wmi_ap_set_apsd_cmd *cmd;
3412        struct sk_buff *skb;
3413
3414        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3415        if (!skb)
3416                return -ENOMEM;
3417
3418        cmd = (struct wmi_ap_set_apsd_cmd *)skb->data;
3419        cmd->enable = enable;
3420
3421        return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_SET_APSD_CMDID,
3422                                   NO_SYNC_WMIFLAG);
3423}
3424
3425int ath6kl_wmi_set_apsd_bfrd_traf(struct wmi *wmi, u8 if_idx,
3426                                             u16 aid, u16 bitmap, u32 flags)
3427{
3428        struct wmi_ap_apsd_buffered_traffic_cmd *cmd;
3429        struct sk_buff *skb;
3430
3431        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3432        if (!skb)
3433                return -ENOMEM;
3434
3435        cmd = (struct wmi_ap_apsd_buffered_traffic_cmd *)skb->data;
3436        cmd->aid = cpu_to_le16(aid);
3437        cmd->bitmap = cpu_to_le16(bitmap);
3438        cmd->flags = cpu_to_le32(flags);
3439
3440        return ath6kl_wmi_cmd_send(wmi, if_idx, skb,
3441                                   WMI_AP_APSD_BUFFERED_TRAFFIC_CMDID,
3442                                   NO_SYNC_WMIFLAG);
3443}
3444
3445static int ath6kl_wmi_pspoll_event_rx(struct wmi *wmi, u8 *datap, int len,
3446                                      struct ath6kl_vif *vif)
3447{
3448        struct wmi_pspoll_event *ev;
3449
3450        if (len < sizeof(struct wmi_pspoll_event))
3451                return -EINVAL;
3452
3453        ev = (struct wmi_pspoll_event *) datap;
3454
3455        ath6kl_pspoll_event(vif, le16_to_cpu(ev->aid));
3456
3457        return 0;
3458}
3459
3460static int ath6kl_wmi_dtimexpiry_event_rx(struct wmi *wmi, u8 *datap, int len,
3461                                          struct ath6kl_vif *vif)
3462{
3463        ath6kl_dtimexpiry_event(vif);
3464
3465        return 0;
3466}
3467
3468int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u8 if_idx, u16 aid,
3469                           bool flag)
3470{
3471        struct sk_buff *skb;
3472        struct wmi_ap_set_pvb_cmd *cmd;
3473        int ret;
3474
3475        skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_ap_set_pvb_cmd));
3476        if (!skb)
3477                return -ENOMEM;
3478
3479        cmd = (struct wmi_ap_set_pvb_cmd *) skb->data;
3480        cmd->aid = cpu_to_le16(aid);
3481        cmd->rsvd = cpu_to_le16(0);
3482        cmd->flag = cpu_to_le32(flag);
3483
3484        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_SET_PVB_CMDID,
3485                                  NO_SYNC_WMIFLAG);
3486
3487        return 0;
3488}
3489
3490int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 if_idx,
3491                                       u8 rx_meta_ver,
3492                                       bool rx_dot11_hdr, bool defrag_on_host)
3493{
3494        struct sk_buff *skb;
3495        struct wmi_rx_frame_format_cmd *cmd;
3496        int ret;
3497
3498        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3499        if (!skb)
3500                return -ENOMEM;
3501
3502        cmd = (struct wmi_rx_frame_format_cmd *) skb->data;
3503        cmd->dot11_hdr = rx_dot11_hdr ? 1 : 0;
3504        cmd->defrag_on_host = defrag_on_host ? 1 : 0;
3505        cmd->meta_ver = rx_meta_ver;
3506
3507        /* Delete the local aggr state, on host */
3508        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_RX_FRAME_FORMAT_CMDID,
3509                                  NO_SYNC_WMIFLAG);
3510
3511        return ret;
3512}
3513
3514int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
3515                             const u8 *ie, u8 ie_len)
3516{
3517        struct sk_buff *skb;
3518        struct wmi_set_appie_cmd *p;
3519
3520        skb = ath6kl_wmi_get_new_buf(sizeof(*p) + ie_len);
3521        if (!skb)
3522                return -ENOMEM;
3523
3524        ath6kl_dbg(ATH6KL_DBG_WMI,
3525                   "set_appie_cmd: mgmt_frm_type=%u ie_len=%u\n",
3526                   mgmt_frm_type, ie_len);
3527        p = (struct wmi_set_appie_cmd *) skb->data;
3528        p->mgmt_frm_type = mgmt_frm_type;
3529        p->ie_len = ie_len;
3530
3531        if (ie != NULL && ie_len > 0)
3532                memcpy(p->ie_info, ie, ie_len);
3533
3534        return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_APPIE_CMDID,
3535                                   NO_SYNC_WMIFLAG);
3536}
3537
3538int ath6kl_wmi_set_ie_cmd(struct wmi *wmi, u8 if_idx, u8 ie_id, u8 ie_field,
3539                          const u8 *ie_info, u8 ie_len)
3540{
3541        struct sk_buff *skb;
3542        struct wmi_set_ie_cmd *p;
3543
3544        skb = ath6kl_wmi_get_new_buf(sizeof(*p) + ie_len);
3545        if (!skb)
3546                return -ENOMEM;
3547
3548        ath6kl_dbg(ATH6KL_DBG_WMI, "set_ie_cmd: ie_id=%u ie_ie_field=%u ie_len=%u\n",
3549                   ie_id, ie_field, ie_len);
3550        p = (struct wmi_set_ie_cmd *) skb->data;
3551        p->ie_id = ie_id;
3552        p->ie_field = ie_field;
3553        p->ie_len = ie_len;
3554        if (ie_info && ie_len > 0)
3555                memcpy(p->ie_info, ie_info, ie_len);
3556
3557        return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_IE_CMDID,
3558                                   NO_SYNC_WMIFLAG);
3559}
3560
3561int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable)
3562{
3563        struct sk_buff *skb;
3564        struct wmi_disable_11b_rates_cmd *cmd;
3565
3566        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3567        if (!skb)
3568                return -ENOMEM;
3569
3570        ath6kl_dbg(ATH6KL_DBG_WMI, "disable_11b_rates_cmd: disable=%u\n",
3571                   disable);
3572        cmd = (struct wmi_disable_11b_rates_cmd *) skb->data;
3573        cmd->disable = disable ? 1 : 0;
3574
3575        return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_DISABLE_11B_RATES_CMDID,
3576                                   NO_SYNC_WMIFLAG);
3577}
3578
3579int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq, u32 dur)
3580{
3581        struct sk_buff *skb;
3582        struct wmi_remain_on_chnl_cmd *p;
3583
3584        skb = ath6kl_wmi_get_new_buf(sizeof(*p));
3585        if (!skb)
3586                return -ENOMEM;
3587
3588        ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl_cmd: freq=%u dur=%u\n",
3589                   freq, dur);
3590        p = (struct wmi_remain_on_chnl_cmd *) skb->data;
3591        p->freq = cpu_to_le32(freq);
3592        p->duration = cpu_to_le32(dur);
3593        return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_REMAIN_ON_CHNL_CMDID,
3594                                   NO_SYNC_WMIFLAG);
3595}
3596
3597/* ath6kl_wmi_send_action_cmd is to be deprecated. Use
3598 * ath6kl_wmi_send_mgmt_cmd instead. The new function supports P2P
3599 * mgmt operations using station interface.
3600 */
3601static int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id,
3602                                      u32 freq, u32 wait, const u8 *data,
3603                                      u16 data_len)
3604{
3605        struct sk_buff *skb;
3606        struct wmi_send_action_cmd *p;
3607        u8 *buf;
3608
3609        if (wait)
3610                return -EINVAL; /* Offload for wait not supported */
3611
3612        buf = kmalloc(data_len, GFP_KERNEL);
3613        if (!buf)
3614                return -ENOMEM;
3615
3616        skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len);
3617        if (!skb) {
3618                kfree(buf);
3619                return -ENOMEM;
3620        }
3621
3622        kfree(wmi->last_mgmt_tx_frame);
3623        memcpy(buf, data, data_len);
3624        wmi->last_mgmt_tx_frame = buf;
3625        wmi->last_mgmt_tx_frame_len = data_len;
3626
3627        ath6kl_dbg(ATH6KL_DBG_WMI,
3628                   "send_action_cmd: id=%u freq=%u wait=%u len=%u\n",
3629                   id, freq, wait, data_len);
3630        p = (struct wmi_send_action_cmd *) skb->data;
3631        p->id = cpu_to_le32(id);
3632        p->freq = cpu_to_le32(freq);
3633        p->wait = cpu_to_le32(wait);
3634        p->len = cpu_to_le16(data_len);
3635        memcpy(p->data, data, data_len);
3636        return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SEND_ACTION_CMDID,
3637                                   NO_SYNC_WMIFLAG);
3638}
3639
3640static int __ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id,
3641                                      u32 freq, u32 wait, const u8 *data,
3642                                      u16 data_len, u32 no_cck)
3643{
3644        struct sk_buff *skb;
3645        struct wmi_send_mgmt_cmd *p;
3646        u8 *buf;
3647
3648        if (wait)
3649                return -EINVAL; /* Offload for wait not supported */
3650
3651        buf = kmalloc(data_len, GFP_KERNEL);
3652        if (!buf)
3653                return -ENOMEM;
3654
3655        skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len);
3656        if (!skb) {
3657                kfree(buf);
3658                return -ENOMEM;
3659        }
3660
3661        kfree(wmi->last_mgmt_tx_frame);
3662        memcpy(buf, data, data_len);
3663        wmi->last_mgmt_tx_frame = buf;
3664        wmi->last_mgmt_tx_frame_len = data_len;
3665
3666        ath6kl_dbg(ATH6KL_DBG_WMI,
3667                   "send_action_cmd: id=%u freq=%u wait=%u len=%u\n",
3668                   id, freq, wait, data_len);
3669        p = (struct wmi_send_mgmt_cmd *) skb->data;
3670        p->id = cpu_to_le32(id);
3671        p->freq = cpu_to_le32(freq);
3672        p->wait = cpu_to_le32(wait);
3673        p->no_cck = cpu_to_le32(no_cck);
3674        p->len = cpu_to_le16(data_len);
3675        memcpy(p->data, data, data_len);
3676        return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SEND_MGMT_CMDID,
3677                                   NO_SYNC_WMIFLAG);
3678}
3679
3680int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
3681                                u32 wait, const u8 *data, u16 data_len,
3682                                u32 no_cck)
3683{
3684        int status;
3685        struct ath6kl *ar = wmi->parent_dev;
3686
3687        if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
3688                     ar->fw_capabilities)) {
3689                /*
3690                 * If capable of doing P2P mgmt operations using
3691                 * station interface, send additional information like
3692                 * supported rates to advertise and xmit rates for
3693                 * probe requests
3694                 */
3695                status = __ath6kl_wmi_send_mgmt_cmd(ar->wmi, if_idx, id, freq,
3696                                                    wait, data, data_len,
3697                                                    no_cck);
3698        } else {
3699                status = ath6kl_wmi_send_action_cmd(ar->wmi, if_idx, id, freq,
3700                                                    wait, data, data_len);
3701        }
3702
3703        return status;
3704}
3705
3706int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq,
3707                                       const u8 *dst, const u8 *data,
3708                                       u16 data_len)
3709{
3710        struct sk_buff *skb;
3711        struct wmi_p2p_probe_response_cmd *p;
3712        size_t cmd_len = sizeof(*p) + data_len;
3713
3714        if (data_len == 0)
3715                cmd_len++; /* work around target minimum length requirement */
3716
3717        skb = ath6kl_wmi_get_new_buf(cmd_len);
3718        if (!skb)
3719                return -ENOMEM;
3720
3721        ath6kl_dbg(ATH6KL_DBG_WMI,
3722                   "send_probe_response_cmd: freq=%u dst=%pM len=%u\n",
3723                   freq, dst, data_len);
3724        p = (struct wmi_p2p_probe_response_cmd *) skb->data;
3725        p->freq = cpu_to_le32(freq);
3726        memcpy(p->destination_addr, dst, ETH_ALEN);
3727        p->len = cpu_to_le16(data_len);
3728        memcpy(p->data, data, data_len);
3729        return ath6kl_wmi_cmd_send(wmi, if_idx, skb,
3730                                   WMI_SEND_PROBE_RESPONSE_CMDID,
3731                                   NO_SYNC_WMIFLAG);
3732}
3733
3734int ath6kl_wmi_probe_report_req_cmd(struct wmi *wmi, u8 if_idx, bool enable)
3735{
3736        struct sk_buff *skb;
3737        struct wmi_probe_req_report_cmd *p;
3738
3739        skb = ath6kl_wmi_get_new_buf(sizeof(*p));
3740        if (!skb)
3741                return -ENOMEM;
3742
3743        ath6kl_dbg(ATH6KL_DBG_WMI, "probe_report_req_cmd: enable=%u\n",
3744                   enable);
3745        p = (struct wmi_probe_req_report_cmd *) skb->data;
3746        p->enable = enable ? 1 : 0;
3747        return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_PROBE_REQ_REPORT_CMDID,
3748                                   NO_SYNC_WMIFLAG);
3749}
3750
3751int ath6kl_wmi_info_req_cmd(struct wmi *wmi, u8 if_idx, u32 info_req_flags)
3752{
3753        struct sk_buff *skb;
3754        struct wmi_get_p2p_info *p;
3755
3756        skb = ath6kl_wmi_get_new_buf(sizeof(*p));
3757        if (!skb)
3758                return -ENOMEM;
3759
3760        ath6kl_dbg(ATH6KL_DBG_WMI, "info_req_cmd: flags=%x\n",
3761                   info_req_flags);
3762        p = (struct wmi_get_p2p_info *) skb->data;
3763        p->info_req_flags = cpu_to_le32(info_req_flags);
3764        return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_GET_P2P_INFO_CMDID,
3765                                   NO_SYNC_WMIFLAG);
3766}
3767
3768int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx)
3769{
3770        ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl_cmd\n");
3771        return ath6kl_wmi_simple_cmd(wmi, if_idx,
3772                                     WMI_CANCEL_REMAIN_ON_CHNL_CMDID);
3773}
3774
3775int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout)
3776{
3777        struct sk_buff *skb;
3778        struct wmi_set_inact_period_cmd *cmd;
3779
3780        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3781        if (!skb)
3782                return -ENOMEM;
3783
3784        cmd = (struct wmi_set_inact_period_cmd *) skb->data;
3785        cmd->inact_period = cpu_to_le32(inact_timeout);
3786        cmd->num_null_func = 0;
3787
3788        return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_CONN_INACT_CMDID,
3789                                   NO_SYNC_WMIFLAG);
3790}
3791
3792static void ath6kl_wmi_hb_challenge_resp_event(struct wmi *wmi, u8 *datap,
3793                                               int len)
3794{
3795        struct wmix_hb_challenge_resp_cmd *cmd;
3796
3797        if (len < sizeof(struct wmix_hb_challenge_resp_cmd))
3798                return;
3799
3800        cmd = (struct wmix_hb_challenge_resp_cmd *) datap;
3801        ath6kl_recovery_hb_event(wmi->parent_dev,
3802                                 le32_to_cpu(cmd->cookie));
3803}
3804
3805static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)
3806{
3807        struct wmix_cmd_hdr *cmd;
3808        u32 len;
3809        u16 id;
3810        u8 *datap;
3811        int ret = 0;
3812
3813        if (skb->len < sizeof(struct wmix_cmd_hdr)) {
3814                ath6kl_err("bad packet 1\n");
3815                return -EINVAL;
3816        }
3817
3818        cmd = (struct wmix_cmd_hdr *) skb->data;
3819        id = le32_to_cpu(cmd->cmd_id);
3820
3821        skb_pull(skb, sizeof(struct wmix_cmd_hdr));
3822
3823        datap = skb->data;
3824        len = skb->len;
3825
3826        switch (id) {
3827        case WMIX_HB_CHALLENGE_RESP_EVENTID:
3828                ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event hb challenge resp\n");
3829                ath6kl_wmi_hb_challenge_resp_event(wmi, datap, len);
3830                break;
3831        case WMIX_DBGLOG_EVENTID:
3832                ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event dbglog len %d\n", len);
3833                ath6kl_debug_fwlog_event(wmi->parent_dev, datap, len);
3834                break;
3835        default:
3836                ath6kl_warn("unknown cmd id 0x%x\n", id);
3837                ret = -EINVAL;
3838                break;
3839        }
3840
3841        return ret;
3842}
3843
3844static int ath6kl_wmi_roam_tbl_event_rx(struct wmi *wmi, u8 *datap, int len)
3845{
3846        return ath6kl_debug_roam_tbl_event(wmi->parent_dev, datap, len);
3847}
3848
3849/* Process interface specific wmi events, caller would free the datap */
3850static int ath6kl_wmi_proc_events_vif(struct wmi *wmi, u16 if_idx, u16 cmd_id,
3851                                        u8 *datap, u32 len)
3852{
3853        struct ath6kl_vif *vif;
3854
3855        vif = ath6kl_get_vif_by_index(wmi->parent_dev, if_idx);
3856        if (!vif) {
3857                ath6kl_dbg(ATH6KL_DBG_WMI,
3858                           "Wmi event for unavailable vif, vif_index:%d\n",
3859                            if_idx);
3860                return -EINVAL;
3861        }
3862
3863        switch (cmd_id) {
3864        case WMI_CONNECT_EVENTID:
3865                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CONNECT_EVENTID\n");
3866                return ath6kl_wmi_connect_event_rx(wmi, datap, len, vif);
3867        case WMI_DISCONNECT_EVENTID:
3868                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DISCONNECT_EVENTID\n");
3869                return ath6kl_wmi_disconnect_event_rx(wmi, datap, len, vif);
3870        case WMI_TKIP_MICERR_EVENTID:
3871                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TKIP_MICERR_EVENTID\n");
3872                return ath6kl_wmi_tkip_micerr_event_rx(wmi, datap, len, vif);
3873        case WMI_BSSINFO_EVENTID:
3874                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n");
3875                return ath6kl_wmi_bssinfo_event_rx(wmi, datap, len, vif);
3876        case WMI_NEIGHBOR_REPORT_EVENTID:
3877                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n");
3878                return ath6kl_wmi_neighbor_report_event_rx(wmi, datap, len,
3879                                                           vif);
3880        case WMI_SCAN_COMPLETE_EVENTID:
3881                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n");
3882                return ath6kl_wmi_scan_complete_rx(wmi, datap, len, vif);
3883        case WMI_REPORT_STATISTICS_EVENTID:
3884                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_STATISTICS_EVENTID\n");
3885                return ath6kl_wmi_stats_event_rx(wmi, datap, len, vif);
3886        case WMI_CAC_EVENTID:
3887                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CAC_EVENTID\n");
3888                return ath6kl_wmi_cac_event_rx(wmi, datap, len, vif);
3889        case WMI_PSPOLL_EVENTID:
3890                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSPOLL_EVENTID\n");
3891                return ath6kl_wmi_pspoll_event_rx(wmi, datap, len, vif);
3892        case WMI_DTIMEXPIRY_EVENTID:
3893                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DTIMEXPIRY_EVENTID\n");
3894                return ath6kl_wmi_dtimexpiry_event_rx(wmi, datap, len, vif);
3895        case WMI_ADDBA_REQ_EVENTID:
3896                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_REQ_EVENTID\n");
3897                return ath6kl_wmi_addba_req_event_rx(wmi, datap, len, vif);
3898        case WMI_DELBA_REQ_EVENTID:
3899                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DELBA_REQ_EVENTID\n");
3900                return ath6kl_wmi_delba_req_event_rx(wmi, datap, len, vif);
3901        case WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID:
3902                ath6kl_dbg(ATH6KL_DBG_WMI,
3903                           "WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID");
3904                return ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx(wmi, vif);
3905        case WMI_REMAIN_ON_CHNL_EVENTID:
3906                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n");
3907                return ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len, vif);
3908        case WMI_CANCEL_REMAIN_ON_CHNL_EVENTID:
3909                ath6kl_dbg(ATH6KL_DBG_WMI,
3910                           "WMI_CANCEL_REMAIN_ON_CHNL_EVENTID\n");
3911                return ath6kl_wmi_cancel_remain_on_chnl_event_rx(wmi, datap,
3912                                                                 len, vif);
3913        case WMI_TX_STATUS_EVENTID:
3914                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n");
3915                return ath6kl_wmi_tx_status_event_rx(wmi, datap, len, vif);
3916        case WMI_RX_PROBE_REQ_EVENTID:
3917                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n");
3918                return ath6kl_wmi_rx_probe_req_event_rx(wmi, datap, len, vif);
3919        case WMI_RX_ACTION_EVENTID:
3920                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n");
3921                return ath6kl_wmi_rx_action_event_rx(wmi, datap, len, vif);
3922        case WMI_TXE_NOTIFY_EVENTID:
3923                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TXE_NOTIFY_EVENTID\n");
3924                return ath6kl_wmi_txe_notify_event_rx(wmi, datap, len, vif);
3925        default:
3926                ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", cmd_id);
3927                return -EINVAL;
3928        }
3929
3930        return 0;
3931}
3932
3933static int ath6kl_wmi_proc_events(struct wmi *wmi, struct sk_buff *skb)
3934{
3935        struct wmi_cmd_hdr *cmd;
3936        int ret = 0;
3937        u32 len;
3938        u16 id;
3939        u8 if_idx;
3940        u8 *datap;
3941
3942        cmd = (struct wmi_cmd_hdr *) skb->data;
3943        id = le16_to_cpu(cmd->cmd_id);
3944        if_idx = le16_to_cpu(cmd->info1) & WMI_CMD_HDR_IF_ID_MASK;
3945
3946        skb_pull(skb, sizeof(struct wmi_cmd_hdr));
3947        datap = skb->data;
3948        len = skb->len;
3949
3950        ath6kl_dbg(ATH6KL_DBG_WMI, "wmi rx id %d len %d\n", id, len);
3951        ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi rx ",
3952                        datap, len);
3953
3954        switch (id) {
3955        case WMI_GET_BITRATE_CMDID:
3956                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_BITRATE_CMDID\n");
3957                ret = ath6kl_wmi_bitrate_reply_rx(wmi, datap, len);
3958                break;
3959        case WMI_GET_CHANNEL_LIST_CMDID:
3960                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_CHANNEL_LIST_CMDID\n");
3961                ret = ath6kl_wmi_ch_list_reply_rx(wmi, datap, len);
3962                break;
3963        case WMI_GET_TX_PWR_CMDID:
3964                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_TX_PWR_CMDID\n");
3965                ret = ath6kl_wmi_tx_pwr_reply_rx(wmi, datap, len);
3966                break;
3967        case WMI_READY_EVENTID:
3968                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_READY_EVENTID\n");
3969                ret = ath6kl_wmi_ready_event_rx(wmi, datap, len);
3970                break;
3971        case WMI_PEER_NODE_EVENTID:
3972                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PEER_NODE_EVENTID\n");
3973                ret = ath6kl_wmi_peer_node_event_rx(wmi, datap, len);
3974                break;
3975        case WMI_REGDOMAIN_EVENTID:
3976                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REGDOMAIN_EVENTID\n");
3977                ath6kl_wmi_regdomain_event(wmi, datap, len);
3978                break;
3979        case WMI_PSTREAM_TIMEOUT_EVENTID:
3980                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSTREAM_TIMEOUT_EVENTID\n");
3981                ret = ath6kl_wmi_pstream_timeout_event_rx(wmi, datap, len);
3982                break;
3983        case WMI_CMDERROR_EVENTID:
3984                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CMDERROR_EVENTID\n");
3985                ret = ath6kl_wmi_error_event_rx(wmi, datap, len);
3986                break;
3987        case WMI_RSSI_THRESHOLD_EVENTID:
3988                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RSSI_THRESHOLD_EVENTID\n");
3989                ret = ath6kl_wmi_rssi_threshold_event_rx(wmi, datap, len);
3990                break;
3991        case WMI_ERROR_REPORT_EVENTID:
3992                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ERROR_REPORT_EVENTID\n");
3993                break;
3994        case WMI_OPT_RX_FRAME_EVENTID:
3995                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_OPT_RX_FRAME_EVENTID\n");
3996                /* this event has been deprecated */
3997                break;
3998        case WMI_REPORT_ROAM_TBL_EVENTID:
3999                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_TBL_EVENTID\n");
4000                ret = ath6kl_wmi_roam_tbl_event_rx(wmi, datap, len);
4001                break;
4002        case WMI_EXTENSION_EVENTID:
4003                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_EXTENSION_EVENTID\n");
4004                ret = ath6kl_wmi_control_rx_xtnd(wmi, skb);
4005                break;
4006        case WMI_CHANNEL_CHANGE_EVENTID:
4007                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CHANNEL_CHANGE_EVENTID\n");
4008                break;
4009        case WMI_REPORT_ROAM_DATA_EVENTID:
4010                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_DATA_EVENTID\n");
4011                break;
4012        case WMI_TEST_EVENTID:
4013                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TEST_EVENTID\n");
4014                ret = ath6kl_wmi_test_rx(wmi, datap, len);
4015                break;
4016        case WMI_GET_FIXRATES_CMDID:
4017                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_FIXRATES_CMDID\n");
4018                ret = ath6kl_wmi_ratemask_reply_rx(wmi, datap, len);
4019                break;
4020        case WMI_TX_RETRY_ERR_EVENTID:
4021                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_RETRY_ERR_EVENTID\n");
4022                break;
4023        case WMI_SNR_THRESHOLD_EVENTID:
4024                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SNR_THRESHOLD_EVENTID\n");
4025                ret = ath6kl_wmi_snr_threshold_event_rx(wmi, datap, len);
4026                break;
4027        case WMI_LQ_THRESHOLD_EVENTID:
4028                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_LQ_THRESHOLD_EVENTID\n");
4029                break;
4030        case WMI_APLIST_EVENTID:
4031                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_APLIST_EVENTID\n");
4032                ret = ath6kl_wmi_aplist_event_rx(wmi, datap, len);
4033                break;
4034        case WMI_GET_KEEPALIVE_CMDID:
4035                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_KEEPALIVE_CMDID\n");
4036                ret = ath6kl_wmi_keepalive_reply_rx(wmi, datap, len);
4037                break;
4038        case WMI_GET_WOW_LIST_EVENTID:
4039                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_WOW_LIST_EVENTID\n");
4040                break;
4041        case WMI_GET_PMKID_LIST_EVENTID:
4042                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_PMKID_LIST_EVENTID\n");
4043                ret = ath6kl_wmi_get_pmkid_list_event_rx(wmi, datap, len);
4044                break;
4045        case WMI_SET_PARAMS_REPLY_EVENTID:
4046                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SET_PARAMS_REPLY_EVENTID\n");
4047                break;
4048        case WMI_ADDBA_RESP_EVENTID:
4049                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_RESP_EVENTID\n");
4050                break;
4051        case WMI_REPORT_BTCOEX_CONFIG_EVENTID:
4052                ath6kl_dbg(ATH6KL_DBG_WMI,
4053                           "WMI_REPORT_BTCOEX_CONFIG_EVENTID\n");
4054                break;
4055        case WMI_REPORT_BTCOEX_STATS_EVENTID:
4056                ath6kl_dbg(ATH6KL_DBG_WMI,
4057                           "WMI_REPORT_BTCOEX_STATS_EVENTID\n");
4058                break;
4059        case WMI_TX_COMPLETE_EVENTID:
4060                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n");
4061                ret = ath6kl_wmi_tx_complete_event_rx(datap, len);
4062                break;
4063        case WMI_P2P_CAPABILITIES_EVENTID:
4064                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_CAPABILITIES_EVENTID\n");
4065                ret = ath6kl_wmi_p2p_capabilities_event_rx(datap, len);
4066                break;
4067        case WMI_P2P_INFO_EVENTID:
4068                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_INFO_EVENTID\n");
4069                ret = ath6kl_wmi_p2p_info_event_rx(datap, len);
4070                break;
4071        default:
4072                /* may be the event is interface specific */
4073                ret = ath6kl_wmi_proc_events_vif(wmi, if_idx, id, datap, len);
4074                break;
4075        }
4076
4077        dev_kfree_skb(skb);
4078        return ret;
4079}
4080
4081/* Control Path */
4082int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
4083{
4084        if (WARN_ON(skb == NULL))
4085                return -EINVAL;
4086
4087        if (skb->len < sizeof(struct wmi_cmd_hdr)) {
4088                ath6kl_err("bad packet 1\n");
4089                dev_kfree_skb(skb);
4090                return -EINVAL;
4091        }
4092
4093        trace_ath6kl_wmi_event(skb->data, skb->len);
4094
4095        return ath6kl_wmi_proc_events(wmi, skb);
4096}
4097
4098void ath6kl_wmi_reset(struct wmi *wmi)
4099{
4100        spin_lock_bh(&wmi->lock);
4101
4102        wmi->fat_pipe_exist = 0;
4103        memset(wmi->stream_exist_for_ac, 0, sizeof(wmi->stream_exist_for_ac));
4104
4105        spin_unlock_bh(&wmi->lock);
4106}
4107
4108void *ath6kl_wmi_init(struct ath6kl *dev)
4109{
4110        struct wmi *wmi;
4111
4112        wmi = kzalloc(sizeof(struct wmi), GFP_KERNEL);
4113        if (!wmi)
4114                return NULL;
4115
4116        spin_lock_init(&wmi->lock);
4117
4118        wmi->parent_dev = dev;
4119
4120        wmi->pwr_mode = REC_POWER;
4121
4122        ath6kl_wmi_reset(wmi);
4123
4124        return wmi;
4125}
4126
4127void ath6kl_wmi_shutdown(struct wmi *wmi)
4128{
4129        if (!wmi)
4130                return;
4131
4132        kfree(wmi->last_mgmt_tx_frame);
4133        kfree(wmi);
4134}
4135