linux/drivers/net/wireless/marvell/mwifiex/util.c
<<
>>
Prefs
   1/*
   2 * Marvell Wireless LAN device driver: utility functions
   3 *
   4 * Copyright (C) 2011-2014, Marvell International Ltd.
   5 *
   6 * This software file (the "File") is distributed by Marvell International
   7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
   8 * (the "License").  You may use, redistribute and/or modify this File in
   9 * accordance with the terms and conditions of the License, a copy of which
  10 * is available by writing to the Free Software Foundation, Inc.,
  11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
  12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
  13 *
  14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
  15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
  16 * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
  17 * this warranty disclaimer.
  18 */
  19
  20#include "decl.h"
  21#include "ioctl.h"
  22#include "util.h"
  23#include "fw.h"
  24#include "main.h"
  25#include "wmm.h"
  26#include "11n.h"
  27
  28static struct mwifiex_debug_data items[] = {
  29        {"debug_mask", item_size(debug_mask),
  30         item_addr(debug_mask), 1},
  31        {"int_counter", item_size(int_counter),
  32         item_addr(int_counter), 1},
  33        {"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]),
  34         item_addr(packets_out[WMM_AC_VO]), 1},
  35        {"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]),
  36         item_addr(packets_out[WMM_AC_VI]), 1},
  37        {"wmm_ac_be", item_size(packets_out[WMM_AC_BE]),
  38         item_addr(packets_out[WMM_AC_BE]), 1},
  39        {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]),
  40         item_addr(packets_out[WMM_AC_BK]), 1},
  41        {"tx_buf_size", item_size(tx_buf_size),
  42         item_addr(tx_buf_size), 1},
  43        {"curr_tx_buf_size", item_size(curr_tx_buf_size),
  44         item_addr(curr_tx_buf_size), 1},
  45        {"ps_mode", item_size(ps_mode),
  46         item_addr(ps_mode), 1},
  47        {"ps_state", item_size(ps_state),
  48         item_addr(ps_state), 1},
  49        {"is_deep_sleep", item_size(is_deep_sleep),
  50         item_addr(is_deep_sleep), 1},
  51        {"wakeup_dev_req", item_size(pm_wakeup_card_req),
  52         item_addr(pm_wakeup_card_req), 1},
  53        {"wakeup_tries", item_size(pm_wakeup_fw_try),
  54         item_addr(pm_wakeup_fw_try), 1},
  55        {"hs_configured", item_size(is_hs_configured),
  56         item_addr(is_hs_configured), 1},
  57        {"hs_activated", item_size(hs_activated),
  58         item_addr(hs_activated), 1},
  59        {"num_tx_timeout", item_size(num_tx_timeout),
  60         item_addr(num_tx_timeout), 1},
  61        {"is_cmd_timedout", item_size(is_cmd_timedout),
  62         item_addr(is_cmd_timedout), 1},
  63        {"timeout_cmd_id", item_size(timeout_cmd_id),
  64         item_addr(timeout_cmd_id), 1},
  65        {"timeout_cmd_act", item_size(timeout_cmd_act),
  66         item_addr(timeout_cmd_act), 1},
  67        {"last_cmd_id", item_size(last_cmd_id),
  68         item_addr(last_cmd_id), DBG_CMD_NUM},
  69        {"last_cmd_act", item_size(last_cmd_act),
  70         item_addr(last_cmd_act), DBG_CMD_NUM},
  71        {"last_cmd_index", item_size(last_cmd_index),
  72         item_addr(last_cmd_index), 1},
  73        {"last_cmd_resp_id", item_size(last_cmd_resp_id),
  74         item_addr(last_cmd_resp_id), DBG_CMD_NUM},
  75        {"last_cmd_resp_index", item_size(last_cmd_resp_index),
  76         item_addr(last_cmd_resp_index), 1},
  77        {"last_event", item_size(last_event),
  78         item_addr(last_event), DBG_CMD_NUM},
  79        {"last_event_index", item_size(last_event_index),
  80         item_addr(last_event_index), 1},
  81        {"last_mp_wr_bitmap", item_size(last_mp_wr_bitmap),
  82         item_addr(last_mp_wr_bitmap), MWIFIEX_DBG_SDIO_MP_NUM},
  83        {"last_mp_wr_ports", item_size(last_mp_wr_ports),
  84         item_addr(last_mp_wr_ports), MWIFIEX_DBG_SDIO_MP_NUM},
  85        {"last_mp_wr_len", item_size(last_mp_wr_len),
  86         item_addr(last_mp_wr_len), MWIFIEX_DBG_SDIO_MP_NUM},
  87        {"last_mp_curr_wr_port", item_size(last_mp_curr_wr_port),
  88         item_addr(last_mp_curr_wr_port), MWIFIEX_DBG_SDIO_MP_NUM},
  89        {"last_sdio_mp_index", item_size(last_sdio_mp_index),
  90         item_addr(last_sdio_mp_index), 1},
  91        {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure),
  92         item_addr(num_cmd_host_to_card_failure), 1},
  93        {"num_cmd_sleep_cfm_fail",
  94         item_size(num_cmd_sleep_cfm_host_to_card_failure),
  95         item_addr(num_cmd_sleep_cfm_host_to_card_failure), 1},
  96        {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure),
  97         item_addr(num_tx_host_to_card_failure), 1},
  98        {"num_evt_deauth", item_size(num_event_deauth),
  99         item_addr(num_event_deauth), 1},
 100        {"num_evt_disassoc", item_size(num_event_disassoc),
 101         item_addr(num_event_disassoc), 1},
 102        {"num_evt_link_lost", item_size(num_event_link_lost),
 103         item_addr(num_event_link_lost), 1},
 104        {"num_cmd_deauth", item_size(num_cmd_deauth),
 105         item_addr(num_cmd_deauth), 1},
 106        {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success),
 107         item_addr(num_cmd_assoc_success), 1},
 108        {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure),
 109         item_addr(num_cmd_assoc_failure), 1},
 110        {"cmd_sent", item_size(cmd_sent),
 111         item_addr(cmd_sent), 1},
 112        {"data_sent", item_size(data_sent),
 113         item_addr(data_sent), 1},
 114        {"cmd_resp_received", item_size(cmd_resp_received),
 115         item_addr(cmd_resp_received), 1},
 116        {"event_received", item_size(event_received),
 117         item_addr(event_received), 1},
 118
 119        /* variables defined in struct mwifiex_adapter */
 120        {"cmd_pending", adapter_item_size(cmd_pending),
 121         adapter_item_addr(cmd_pending), 1},
 122        {"tx_pending", adapter_item_size(tx_pending),
 123         adapter_item_addr(tx_pending), 1},
 124        {"rx_pending", adapter_item_size(rx_pending),
 125         adapter_item_addr(rx_pending), 1},
 126};
 127
 128static int num_of_items = ARRAY_SIZE(items);
 129
 130/*
 131 * Firmware initialization complete callback handler.
 132 *
 133 * This function wakes up the function waiting on the init
 134 * wait queue for the firmware initialization to complete.
 135 */
 136int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter)
 137{
 138
 139        if (adapter->hw_status == MWIFIEX_HW_STATUS_READY)
 140                if (adapter->if_ops.init_fw_port)
 141                        adapter->if_ops.init_fw_port(adapter);
 142
 143        adapter->init_wait_q_woken = true;
 144        wake_up_interruptible(&adapter->init_wait_q);
 145        return 0;
 146}
 147
 148/*
 149 * Firmware shutdown complete callback handler.
 150 *
 151 * This function sets the hardware status to not ready and wakes up
 152 * the function waiting on the init wait queue for the firmware
 153 * shutdown to complete.
 154 */
 155int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter)
 156{
 157        adapter->hw_status = MWIFIEX_HW_STATUS_NOT_READY;
 158        adapter->init_wait_q_woken = true;
 159        wake_up_interruptible(&adapter->init_wait_q);
 160        return 0;
 161}
 162
 163/*
 164 * This function sends init/shutdown command
 165 * to firmware.
 166 */
 167int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
 168                             u32 func_init_shutdown)
 169{
 170        u16 cmd;
 171
 172        if (func_init_shutdown == MWIFIEX_FUNC_INIT) {
 173                cmd = HostCmd_CMD_FUNC_INIT;
 174        } else if (func_init_shutdown == MWIFIEX_FUNC_SHUTDOWN) {
 175                cmd = HostCmd_CMD_FUNC_SHUTDOWN;
 176        } else {
 177                mwifiex_dbg(priv->adapter, ERROR,
 178                            "unsupported parameter\n");
 179                return -1;
 180        }
 181
 182        return mwifiex_send_cmd(priv, cmd, HostCmd_ACT_GEN_SET, 0, NULL, true);
 183}
 184EXPORT_SYMBOL_GPL(mwifiex_init_shutdown_fw);
 185
 186/*
 187 * IOCTL request handler to set/get debug information.
 188 *
 189 * This function collates/sets the information from/to different driver
 190 * structures.
 191 */
 192int mwifiex_get_debug_info(struct mwifiex_private *priv,
 193                           struct mwifiex_debug_info *info)
 194{
 195        struct mwifiex_adapter *adapter = priv->adapter;
 196
 197        if (info) {
 198                info->debug_mask = adapter->debug_mask;
 199                memcpy(info->packets_out,
 200                       priv->wmm.packets_out,
 201                       sizeof(priv->wmm.packets_out));
 202                info->curr_tx_buf_size = (u32) adapter->curr_tx_buf_size;
 203                info->tx_buf_size = (u32) adapter->tx_buf_size;
 204                info->rx_tbl_num = mwifiex_get_rx_reorder_tbl(priv,
 205                                                              info->rx_tbl);
 206                info->tx_tbl_num = mwifiex_get_tx_ba_stream_tbl(priv,
 207                                                                info->tx_tbl);
 208                info->tdls_peer_num = mwifiex_get_tdls_list(priv,
 209                                                            info->tdls_list);
 210                info->ps_mode = adapter->ps_mode;
 211                info->ps_state = adapter->ps_state;
 212                info->is_deep_sleep = adapter->is_deep_sleep;
 213                info->pm_wakeup_card_req = adapter->pm_wakeup_card_req;
 214                info->pm_wakeup_fw_try = adapter->pm_wakeup_fw_try;
 215                info->is_hs_configured = adapter->is_hs_configured;
 216                info->hs_activated = adapter->hs_activated;
 217                info->is_cmd_timedout = adapter->is_cmd_timedout;
 218                info->num_cmd_host_to_card_failure
 219                                = adapter->dbg.num_cmd_host_to_card_failure;
 220                info->num_cmd_sleep_cfm_host_to_card_failure
 221                        = adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure;
 222                info->num_tx_host_to_card_failure
 223                                = adapter->dbg.num_tx_host_to_card_failure;
 224                info->num_event_deauth = adapter->dbg.num_event_deauth;
 225                info->num_event_disassoc = adapter->dbg.num_event_disassoc;
 226                info->num_event_link_lost = adapter->dbg.num_event_link_lost;
 227                info->num_cmd_deauth = adapter->dbg.num_cmd_deauth;
 228                info->num_cmd_assoc_success =
 229                                        adapter->dbg.num_cmd_assoc_success;
 230                info->num_cmd_assoc_failure =
 231                                        adapter->dbg.num_cmd_assoc_failure;
 232                info->num_tx_timeout = adapter->dbg.num_tx_timeout;
 233                info->timeout_cmd_id = adapter->dbg.timeout_cmd_id;
 234                info->timeout_cmd_act = adapter->dbg.timeout_cmd_act;
 235                memcpy(info->last_cmd_id, adapter->dbg.last_cmd_id,
 236                       sizeof(adapter->dbg.last_cmd_id));
 237                memcpy(info->last_cmd_act, adapter->dbg.last_cmd_act,
 238                       sizeof(adapter->dbg.last_cmd_act));
 239                info->last_cmd_index = adapter->dbg.last_cmd_index;
 240                memcpy(info->last_cmd_resp_id, adapter->dbg.last_cmd_resp_id,
 241                       sizeof(adapter->dbg.last_cmd_resp_id));
 242                info->last_cmd_resp_index = adapter->dbg.last_cmd_resp_index;
 243                memcpy(info->last_event, adapter->dbg.last_event,
 244                       sizeof(adapter->dbg.last_event));
 245                info->last_event_index = adapter->dbg.last_event_index;
 246                memcpy(info->last_mp_wr_bitmap, adapter->dbg.last_mp_wr_bitmap,
 247                       sizeof(adapter->dbg.last_mp_wr_bitmap));
 248                memcpy(info->last_mp_wr_ports, adapter->dbg.last_mp_wr_ports,
 249                       sizeof(adapter->dbg.last_mp_wr_ports));
 250                memcpy(info->last_mp_curr_wr_port,
 251                       adapter->dbg.last_mp_curr_wr_port,
 252                       sizeof(adapter->dbg.last_mp_curr_wr_port));
 253                memcpy(info->last_mp_wr_len, adapter->dbg.last_mp_wr_len,
 254                       sizeof(adapter->dbg.last_mp_wr_len));
 255                info->last_sdio_mp_index = adapter->dbg.last_sdio_mp_index;
 256                info->data_sent = adapter->data_sent;
 257                info->cmd_sent = adapter->cmd_sent;
 258                info->cmd_resp_received = adapter->cmd_resp_received;
 259        }
 260
 261        return 0;
 262}
 263
 264int mwifiex_debug_info_to_buffer(struct mwifiex_private *priv, char *buf,
 265                                 struct mwifiex_debug_info *info)
 266{
 267        char *p = buf;
 268        struct mwifiex_debug_data *d = &items[0];
 269        size_t size, addr;
 270        long val;
 271        int i, j;
 272
 273        if (!info)
 274                return 0;
 275
 276        for (i = 0; i < num_of_items; i++) {
 277                p += sprintf(p, "%s=", d[i].name);
 278
 279                size = d[i].size / d[i].num;
 280
 281                if (i < (num_of_items - 3))
 282                        addr = d[i].addr + (size_t)info;
 283                else /* The last 3 items are struct mwifiex_adapter variables */
 284                        addr = d[i].addr + (size_t)priv->adapter;
 285
 286                for (j = 0; j < d[i].num; j++) {
 287                        switch (size) {
 288                        case 1:
 289                                val = *((u8 *)addr);
 290                                break;
 291                        case 2:
 292                                val = *((u16 *)addr);
 293                                break;
 294                        case 4:
 295                                val = *((u32 *)addr);
 296                                break;
 297                        case 8:
 298                                val = *((long long *)addr);
 299                                break;
 300                        default:
 301                                val = -1;
 302                                break;
 303                        }
 304
 305                        p += sprintf(p, "%#lx ", val);
 306                        addr += size;
 307                }
 308
 309                p += sprintf(p, "\n");
 310        }
 311
 312        if (info->tx_tbl_num) {
 313                p += sprintf(p, "Tx BA stream table:\n");
 314                for (i = 0; i < info->tx_tbl_num; i++)
 315                        p += sprintf(p, "tid = %d, ra = %pM\n",
 316                                     info->tx_tbl[i].tid, info->tx_tbl[i].ra);
 317        }
 318
 319        if (info->rx_tbl_num) {
 320                p += sprintf(p, "Rx reorder table:\n");
 321                for (i = 0; i < info->rx_tbl_num; i++) {
 322                        p += sprintf(p, "tid = %d, ta = %pM, ",
 323                                     info->rx_tbl[i].tid,
 324                                     info->rx_tbl[i].ta);
 325                        p += sprintf(p, "start_win = %d, ",
 326                                     info->rx_tbl[i].start_win);
 327                        p += sprintf(p, "win_size = %d, buffer: ",
 328                                     info->rx_tbl[i].win_size);
 329
 330                        for (j = 0; j < info->rx_tbl[i].win_size; j++)
 331                                p += sprintf(p, "%c ",
 332                                             info->rx_tbl[i].buffer[j] ?
 333                                             '1' : '0');
 334
 335                        p += sprintf(p, "\n");
 336                }
 337        }
 338
 339        if (info->tdls_peer_num) {
 340                p += sprintf(p, "TDLS peer table:\n");
 341                for (i = 0; i < info->tdls_peer_num; i++) {
 342                        p += sprintf(p, "peer = %pM",
 343                                     info->tdls_list[i].peer_addr);
 344                        p += sprintf(p, "\n");
 345                }
 346        }
 347
 348        return p - buf;
 349}
 350
 351static int
 352mwifiex_parse_mgmt_packet(struct mwifiex_private *priv, u8 *payload, u16 len,
 353                          struct rxpd *rx_pd)
 354{
 355        u16 stype;
 356        u8 category, action_code, *addr2;
 357        struct ieee80211_hdr *ieee_hdr = (void *)payload;
 358
 359        stype = (le16_to_cpu(ieee_hdr->frame_control) & IEEE80211_FCTL_STYPE);
 360
 361        switch (stype) {
 362        case IEEE80211_STYPE_ACTION:
 363                category = *(payload + sizeof(struct ieee80211_hdr));
 364                switch (category) {
 365                case WLAN_CATEGORY_PUBLIC:
 366                        action_code = *(payload + sizeof(struct ieee80211_hdr)
 367                                        + 1);
 368                        if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) {
 369                                addr2 = ieee_hdr->addr2;
 370                                mwifiex_dbg(priv->adapter, INFO,
 371                                            "TDLS discovery response %pM nf=%d, snr=%d\n",
 372                                            addr2, rx_pd->nf, rx_pd->snr);
 373                                mwifiex_auto_tdls_update_peer_signal(priv,
 374                                                                     addr2,
 375                                                                     rx_pd->snr,
 376                                                                     rx_pd->nf);
 377                        }
 378                        break;
 379                case WLAN_CATEGORY_BACK:
 380                        /*we dont indicate BACK action frames to cfg80211*/
 381                        mwifiex_dbg(priv->adapter, INFO,
 382                                    "drop BACK action frames");
 383                        return -1;
 384                default:
 385                        mwifiex_dbg(priv->adapter, INFO,
 386                                    "unknown public action frame category %d\n",
 387                                    category);
 388                }
 389                break;
 390        default:
 391                mwifiex_dbg(priv->adapter, INFO,
 392                    "unknown mgmt frame subtype %#x\n", stype);
 393                return 0;
 394        }
 395
 396        return 0;
 397}
 398/*
 399 * This function processes the received management packet and send it
 400 * to the kernel.
 401 */
 402int
 403mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
 404                            struct sk_buff *skb)
 405{
 406        struct rxpd *rx_pd;
 407        u16 pkt_len;
 408        struct ieee80211_hdr *ieee_hdr;
 409
 410        if (!skb)
 411                return -1;
 412
 413        if (!priv->mgmt_frame_mask ||
 414            priv->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED) {
 415                mwifiex_dbg(priv->adapter, ERROR,
 416                            "do not receive mgmt frames on uninitialized intf");
 417                return -1;
 418        }
 419
 420        rx_pd = (struct rxpd *)skb->data;
 421
 422        skb_pull(skb, le16_to_cpu(rx_pd->rx_pkt_offset));
 423        skb_pull(skb, sizeof(pkt_len));
 424
 425        pkt_len = le16_to_cpu(rx_pd->rx_pkt_length);
 426
 427        ieee_hdr = (void *)skb->data;
 428        if (ieee80211_is_mgmt(ieee_hdr->frame_control)) {
 429                if (mwifiex_parse_mgmt_packet(priv, (u8 *)ieee_hdr,
 430                                              pkt_len, rx_pd))
 431                        return -1;
 432        }
 433        /* Remove address4 */
 434        memmove(skb->data + sizeof(struct ieee80211_hdr_3addr),
 435                skb->data + sizeof(struct ieee80211_hdr),
 436                pkt_len - sizeof(struct ieee80211_hdr));
 437
 438        pkt_len -= ETH_ALEN + sizeof(pkt_len);
 439        rx_pd->rx_pkt_length = cpu_to_le16(pkt_len);
 440
 441        cfg80211_rx_mgmt(&priv->wdev, priv->roc_cfg.chan.center_freq,
 442                         CAL_RSSI(rx_pd->snr, rx_pd->nf), skb->data, pkt_len,
 443                         0);
 444
 445        return 0;
 446}
 447
 448/*
 449 * This function processes the received packet before sending it to the
 450 * kernel.
 451 *
 452 * It extracts the SKB from the received buffer and sends it to kernel.
 453 * In case the received buffer does not contain the data in SKB format,
 454 * the function creates a blank SKB, fills it with the data from the
 455 * received buffer and then sends this new SKB to the kernel.
 456 */
 457int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb)
 458{
 459        struct mwifiex_sta_node *src_node;
 460        struct ethhdr *p_ethhdr;
 461
 462        if (!skb)
 463                return -1;
 464
 465        priv->stats.rx_bytes += skb->len;
 466        priv->stats.rx_packets++;
 467
 468        if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
 469                p_ethhdr = (void *)skb->data;
 470                src_node = mwifiex_get_sta_entry(priv, p_ethhdr->h_source);
 471                if (src_node) {
 472                        src_node->stats.last_rx = jiffies;
 473                        src_node->stats.rx_bytes += skb->len;
 474                        src_node->stats.rx_packets++;
 475                }
 476        }
 477
 478        skb->dev = priv->netdev;
 479        skb->protocol = eth_type_trans(skb, priv->netdev);
 480        skb->ip_summed = CHECKSUM_NONE;
 481
 482        /* This is required only in case of 11n and USB/PCIE as we alloc
 483         * a buffer of 4K only if its 11N (to be able to receive 4K
 484         * AMSDU packets). In case of SD we allocate buffers based
 485         * on the size of packet and hence this is not needed.
 486         *
 487         * Modifying the truesize here as our allocation for each
 488         * skb is 4K but we only receive 2K packets and this cause
 489         * the kernel to start dropping packets in case where
 490         * application has allocated buffer based on 2K size i.e.
 491         * if there a 64K packet received (in IP fragments and
 492         * application allocates 64K to receive this packet but
 493         * this packet would almost double up because we allocate
 494         * each 1.5K fragment in 4K and pass it up. As soon as the
 495         * 64K limit hits kernel will start to drop rest of the
 496         * fragments. Currently we fail the Filesndl-ht.scr script
 497         * for UDP, hence this fix
 498         */
 499        if ((priv->adapter->iface_type == MWIFIEX_USB ||
 500             priv->adapter->iface_type == MWIFIEX_PCIE) &&
 501            (skb->truesize > MWIFIEX_RX_DATA_BUF_SIZE))
 502                skb->truesize += (skb->len - MWIFIEX_RX_DATA_BUF_SIZE);
 503
 504        if (in_interrupt())
 505                netif_rx(skb);
 506        else
 507                netif_rx_ni(skb);
 508
 509        return 0;
 510}
 511
 512/*
 513 * IOCTL completion callback handler.
 514 *
 515 * This function is called when a pending IOCTL is completed.
 516 *
 517 * If work queue support is enabled, the function wakes up the
 518 * corresponding waiting function. Otherwise, it processes the
 519 * IOCTL response and frees the response buffer.
 520 */
 521int mwifiex_complete_cmd(struct mwifiex_adapter *adapter,
 522                         struct cmd_ctrl_node *cmd_node)
 523{
 524        WARN_ON(!cmd_node->wait_q_enabled);
 525        mwifiex_dbg(adapter, CMD, "cmd completed: status=%d\n",
 526                    adapter->cmd_wait_q.status);
 527
 528        *cmd_node->condition = true;
 529        wake_up_interruptible(&adapter->cmd_wait_q.wait);
 530
 531        return 0;
 532}
 533
 534/* This function will return the pointer to station entry in station list
 535 * table which matches specified mac address.
 536 * This function should be called after acquiring RA list spinlock.
 537 * NULL is returned if station entry is not found in associated STA list.
 538 */
 539struct mwifiex_sta_node *
 540mwifiex_get_sta_entry(struct mwifiex_private *priv, const u8 *mac)
 541{
 542        struct mwifiex_sta_node *node;
 543
 544        if (!mac)
 545                return NULL;
 546
 547        list_for_each_entry(node, &priv->sta_list, list) {
 548                if (!memcmp(node->mac_addr, mac, ETH_ALEN))
 549                        return node;
 550        }
 551
 552        return NULL;
 553}
 554
 555static struct mwifiex_sta_node *
 556mwifiex_get_tdls_sta_entry(struct mwifiex_private *priv, u8 status)
 557{
 558        struct mwifiex_sta_node *node;
 559
 560        list_for_each_entry(node, &priv->sta_list, list) {
 561                if (node->tdls_status == status)
 562                        return node;
 563        }
 564
 565        return NULL;
 566}
 567
 568/* If tdls channel switching is on-going, tx data traffic should be
 569 * blocked until the switching stage completed.
 570 */
 571u8 mwifiex_is_tdls_chan_switching(struct mwifiex_private *priv)
 572{
 573        struct mwifiex_sta_node *sta_ptr;
 574
 575        if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info))
 576                return false;
 577
 578        sta_ptr = mwifiex_get_tdls_sta_entry(priv, TDLS_CHAN_SWITCHING);
 579        if (sta_ptr)
 580                return true;
 581
 582        return false;
 583}
 584
 585u8 mwifiex_is_tdls_off_chan(struct mwifiex_private *priv)
 586{
 587        struct mwifiex_sta_node *sta_ptr;
 588
 589        if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info))
 590                return false;
 591
 592        sta_ptr = mwifiex_get_tdls_sta_entry(priv, TDLS_IN_OFF_CHAN);
 593        if (sta_ptr)
 594                return true;
 595
 596        return false;
 597}
 598
 599/* If tdls channel switching is on-going or tdls operate on off-channel,
 600 * cmd path should be blocked until tdls switched to base-channel.
 601 */
 602u8 mwifiex_is_send_cmd_allowed(struct mwifiex_private *priv)
 603{
 604        if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info))
 605                return true;
 606
 607        if (mwifiex_is_tdls_chan_switching(priv) ||
 608            mwifiex_is_tdls_off_chan(priv))
 609                return false;
 610
 611        return true;
 612}
 613
 614/* This function will add a sta_node entry to associated station list
 615 * table with the given mac address.
 616 * If entry exist already, existing entry is returned.
 617 * If received mac address is NULL, NULL is returned.
 618 */
 619struct mwifiex_sta_node *
 620mwifiex_add_sta_entry(struct mwifiex_private *priv, const u8 *mac)
 621{
 622        struct mwifiex_sta_node *node;
 623        unsigned long flags;
 624
 625        if (!mac)
 626                return NULL;
 627
 628        spin_lock_irqsave(&priv->sta_list_spinlock, flags);
 629        node = mwifiex_get_sta_entry(priv, mac);
 630        if (node)
 631                goto done;
 632
 633        node = kzalloc(sizeof(*node), GFP_ATOMIC);
 634        if (!node)
 635                goto done;
 636
 637        memcpy(node->mac_addr, mac, ETH_ALEN);
 638        list_add_tail(&node->list, &priv->sta_list);
 639
 640done:
 641        spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
 642        return node;
 643}
 644
 645/* This function will search for HT IE in association request IEs
 646 * and set station HT parameters accordingly.
 647 */
 648void
 649mwifiex_set_sta_ht_cap(struct mwifiex_private *priv, const u8 *ies,
 650                       int ies_len, struct mwifiex_sta_node *node)
 651{
 652        struct ieee_types_header *ht_cap_ie;
 653        const struct ieee80211_ht_cap *ht_cap;
 654
 655        if (!ies)
 656                return;
 657
 658        ht_cap_ie = (void *)cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies,
 659                                             ies_len);
 660        if (ht_cap_ie) {
 661                ht_cap = (void *)(ht_cap_ie + 1);
 662                node->is_11n_enabled = 1;
 663                node->max_amsdu = le16_to_cpu(ht_cap->cap_info) &
 664                                  IEEE80211_HT_CAP_MAX_AMSDU ?
 665                                  MWIFIEX_TX_DATA_BUF_SIZE_8K :
 666                                  MWIFIEX_TX_DATA_BUF_SIZE_4K;
 667        } else {
 668                node->is_11n_enabled = 0;
 669        }
 670
 671        return;
 672}
 673
 674/* This function will delete a station entry from station list */
 675void mwifiex_del_sta_entry(struct mwifiex_private *priv, const u8 *mac)
 676{
 677        struct mwifiex_sta_node *node;
 678        unsigned long flags;
 679
 680        spin_lock_irqsave(&priv->sta_list_spinlock, flags);
 681
 682        node = mwifiex_get_sta_entry(priv, mac);
 683        if (node) {
 684                list_del(&node->list);
 685                kfree(node);
 686        }
 687
 688        spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
 689        return;
 690}
 691
 692/* This function will delete all stations from associated station list. */
 693void mwifiex_del_all_sta_list(struct mwifiex_private *priv)
 694{
 695        struct mwifiex_sta_node *node, *tmp;
 696        unsigned long flags;
 697
 698        spin_lock_irqsave(&priv->sta_list_spinlock, flags);
 699
 700        list_for_each_entry_safe(node, tmp, &priv->sta_list, list) {
 701                list_del(&node->list);
 702                kfree(node);
 703        }
 704
 705        INIT_LIST_HEAD(&priv->sta_list);
 706        spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
 707        return;
 708}
 709
 710/* This function adds histogram data to histogram array*/
 711void mwifiex_hist_data_add(struct mwifiex_private *priv,
 712                           u8 rx_rate, s8 snr, s8 nflr)
 713{
 714        struct mwifiex_histogram_data *phist_data = priv->hist_data;
 715
 716        if (atomic_read(&phist_data->num_samples) > MWIFIEX_HIST_MAX_SAMPLES)
 717                mwifiex_hist_data_reset(priv);
 718        mwifiex_hist_data_set(priv, rx_rate, snr, nflr);
 719}
 720
 721/* function to add histogram record */
 722void mwifiex_hist_data_set(struct mwifiex_private *priv, u8 rx_rate, s8 snr,
 723                           s8 nflr)
 724{
 725        struct mwifiex_histogram_data *phist_data = priv->hist_data;
 726
 727        atomic_inc(&phist_data->num_samples);
 728        atomic_inc(&phist_data->rx_rate[rx_rate]);
 729        atomic_inc(&phist_data->snr[snr]);
 730        atomic_inc(&phist_data->noise_flr[128 + nflr]);
 731        atomic_inc(&phist_data->sig_str[nflr - snr]);
 732}
 733
 734/* function to reset histogram data during init/reset */
 735void mwifiex_hist_data_reset(struct mwifiex_private *priv)
 736{
 737        int ix;
 738        struct mwifiex_histogram_data *phist_data = priv->hist_data;
 739
 740        atomic_set(&phist_data->num_samples, 0);
 741        for (ix = 0; ix < MWIFIEX_MAX_AC_RX_RATES; ix++)
 742                atomic_set(&phist_data->rx_rate[ix], 0);
 743        for (ix = 0; ix < MWIFIEX_MAX_SNR; ix++)
 744                atomic_set(&phist_data->snr[ix], 0);
 745        for (ix = 0; ix < MWIFIEX_MAX_NOISE_FLR; ix++)
 746                atomic_set(&phist_data->noise_flr[ix], 0);
 747        for (ix = 0; ix < MWIFIEX_MAX_SIG_STRENGTH; ix++)
 748                atomic_set(&phist_data->sig_str[ix], 0);
 749}
 750
 751void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags)
 752{
 753        struct sk_buff *skb;
 754        int buf_len, pad;
 755
 756        buf_len = rx_len + MWIFIEX_RX_HEADROOM + MWIFIEX_DMA_ALIGN_SZ;
 757
 758        skb = __dev_alloc_skb(buf_len, flags);
 759
 760        if (!skb)
 761                return NULL;
 762
 763        skb_reserve(skb, MWIFIEX_RX_HEADROOM);
 764
 765        pad = MWIFIEX_ALIGN_ADDR(skb->data, MWIFIEX_DMA_ALIGN_SZ) -
 766              (long)skb->data;
 767
 768        skb_reserve(skb, pad);
 769
 770        return skb;
 771}
 772EXPORT_SYMBOL_GPL(mwifiex_alloc_dma_align_buf);
 773