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 * This function sends init/shutdown command
 150 * to firmware.
 151 */
 152int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
 153                             u32 func_init_shutdown)
 154{
 155        u16 cmd;
 156
 157        if (func_init_shutdown == MWIFIEX_FUNC_INIT) {
 158                cmd = HostCmd_CMD_FUNC_INIT;
 159        } else if (func_init_shutdown == MWIFIEX_FUNC_SHUTDOWN) {
 160                cmd = HostCmd_CMD_FUNC_SHUTDOWN;
 161        } else {
 162                mwifiex_dbg(priv->adapter, ERROR,
 163                            "unsupported parameter\n");
 164                return -1;
 165        }
 166
 167        return mwifiex_send_cmd(priv, cmd, HostCmd_ACT_GEN_SET, 0, NULL, true);
 168}
 169EXPORT_SYMBOL_GPL(mwifiex_init_shutdown_fw);
 170
 171/*
 172 * IOCTL request handler to set/get debug information.
 173 *
 174 * This function collates/sets the information from/to different driver
 175 * structures.
 176 */
 177int mwifiex_get_debug_info(struct mwifiex_private *priv,
 178                           struct mwifiex_debug_info *info)
 179{
 180        struct mwifiex_adapter *adapter = priv->adapter;
 181
 182        if (info) {
 183                info->debug_mask = adapter->debug_mask;
 184                memcpy(info->packets_out,
 185                       priv->wmm.packets_out,
 186                       sizeof(priv->wmm.packets_out));
 187                info->curr_tx_buf_size = (u32) adapter->curr_tx_buf_size;
 188                info->tx_buf_size = (u32) adapter->tx_buf_size;
 189                info->rx_tbl_num = mwifiex_get_rx_reorder_tbl(priv,
 190                                                              info->rx_tbl);
 191                info->tx_tbl_num = mwifiex_get_tx_ba_stream_tbl(priv,
 192                                                                info->tx_tbl);
 193                info->tdls_peer_num = mwifiex_get_tdls_list(priv,
 194                                                            info->tdls_list);
 195                info->ps_mode = adapter->ps_mode;
 196                info->ps_state = adapter->ps_state;
 197                info->is_deep_sleep = adapter->is_deep_sleep;
 198                info->pm_wakeup_card_req = adapter->pm_wakeup_card_req;
 199                info->pm_wakeup_fw_try = adapter->pm_wakeup_fw_try;
 200                info->is_hs_configured = test_bit(MWIFIEX_IS_HS_CONFIGURED,
 201                                                  &adapter->work_flags);
 202                info->hs_activated = adapter->hs_activated;
 203                info->is_cmd_timedout = test_bit(MWIFIEX_IS_CMD_TIMEDOUT,
 204                                                 &adapter->work_flags);
 205                info->num_cmd_host_to_card_failure
 206                                = adapter->dbg.num_cmd_host_to_card_failure;
 207                info->num_cmd_sleep_cfm_host_to_card_failure
 208                        = adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure;
 209                info->num_tx_host_to_card_failure
 210                                = adapter->dbg.num_tx_host_to_card_failure;
 211                info->num_event_deauth = adapter->dbg.num_event_deauth;
 212                info->num_event_disassoc = adapter->dbg.num_event_disassoc;
 213                info->num_event_link_lost = adapter->dbg.num_event_link_lost;
 214                info->num_cmd_deauth = adapter->dbg.num_cmd_deauth;
 215                info->num_cmd_assoc_success =
 216                                        adapter->dbg.num_cmd_assoc_success;
 217                info->num_cmd_assoc_failure =
 218                                        adapter->dbg.num_cmd_assoc_failure;
 219                info->num_tx_timeout = adapter->dbg.num_tx_timeout;
 220                info->timeout_cmd_id = adapter->dbg.timeout_cmd_id;
 221                info->timeout_cmd_act = adapter->dbg.timeout_cmd_act;
 222                memcpy(info->last_cmd_id, adapter->dbg.last_cmd_id,
 223                       sizeof(adapter->dbg.last_cmd_id));
 224                memcpy(info->last_cmd_act, adapter->dbg.last_cmd_act,
 225                       sizeof(adapter->dbg.last_cmd_act));
 226                info->last_cmd_index = adapter->dbg.last_cmd_index;
 227                memcpy(info->last_cmd_resp_id, adapter->dbg.last_cmd_resp_id,
 228                       sizeof(adapter->dbg.last_cmd_resp_id));
 229                info->last_cmd_resp_index = adapter->dbg.last_cmd_resp_index;
 230                memcpy(info->last_event, adapter->dbg.last_event,
 231                       sizeof(adapter->dbg.last_event));
 232                info->last_event_index = adapter->dbg.last_event_index;
 233                memcpy(info->last_mp_wr_bitmap, adapter->dbg.last_mp_wr_bitmap,
 234                       sizeof(adapter->dbg.last_mp_wr_bitmap));
 235                memcpy(info->last_mp_wr_ports, adapter->dbg.last_mp_wr_ports,
 236                       sizeof(adapter->dbg.last_mp_wr_ports));
 237                memcpy(info->last_mp_curr_wr_port,
 238                       adapter->dbg.last_mp_curr_wr_port,
 239                       sizeof(adapter->dbg.last_mp_curr_wr_port));
 240                memcpy(info->last_mp_wr_len, adapter->dbg.last_mp_wr_len,
 241                       sizeof(adapter->dbg.last_mp_wr_len));
 242                info->last_sdio_mp_index = adapter->dbg.last_sdio_mp_index;
 243                info->data_sent = adapter->data_sent;
 244                info->cmd_sent = adapter->cmd_sent;
 245                info->cmd_resp_received = adapter->cmd_resp_received;
 246        }
 247
 248        return 0;
 249}
 250
 251int mwifiex_debug_info_to_buffer(struct mwifiex_private *priv, char *buf,
 252                                 struct mwifiex_debug_info *info)
 253{
 254        char *p = buf;
 255        struct mwifiex_debug_data *d = &items[0];
 256        size_t size, addr;
 257        long val;
 258        int i, j;
 259
 260        if (!info)
 261                return 0;
 262
 263        for (i = 0; i < num_of_items; i++) {
 264                p += sprintf(p, "%s=", d[i].name);
 265
 266                size = d[i].size / d[i].num;
 267
 268                if (i < (num_of_items - 3))
 269                        addr = d[i].addr + (size_t)info;
 270                else /* The last 3 items are struct mwifiex_adapter variables */
 271                        addr = d[i].addr + (size_t)priv->adapter;
 272
 273                for (j = 0; j < d[i].num; j++) {
 274                        switch (size) {
 275                        case 1:
 276                                val = *((u8 *)addr);
 277                                break;
 278                        case 2:
 279                                val = get_unaligned((u16 *)addr);
 280                                break;
 281                        case 4:
 282                                val = get_unaligned((u32 *)addr);
 283                                break;
 284                        case 8:
 285                                val = get_unaligned((long long *)addr);
 286                                break;
 287                        default:
 288                                val = -1;
 289                                break;
 290                        }
 291
 292                        p += sprintf(p, "%#lx ", val);
 293                        addr += size;
 294                }
 295
 296                p += sprintf(p, "\n");
 297        }
 298
 299        if (info->tx_tbl_num) {
 300                p += sprintf(p, "Tx BA stream table:\n");
 301                for (i = 0; i < info->tx_tbl_num; i++)
 302                        p += sprintf(p, "tid = %d, ra = %pM\n",
 303                                     info->tx_tbl[i].tid, info->tx_tbl[i].ra);
 304        }
 305
 306        if (info->rx_tbl_num) {
 307                p += sprintf(p, "Rx reorder table:\n");
 308                for (i = 0; i < info->rx_tbl_num; i++) {
 309                        p += sprintf(p, "tid = %d, ta = %pM, ",
 310                                     info->rx_tbl[i].tid,
 311                                     info->rx_tbl[i].ta);
 312                        p += sprintf(p, "start_win = %d, ",
 313                                     info->rx_tbl[i].start_win);
 314                        p += sprintf(p, "win_size = %d, buffer: ",
 315                                     info->rx_tbl[i].win_size);
 316
 317                        for (j = 0; j < info->rx_tbl[i].win_size; j++)
 318                                p += sprintf(p, "%c ",
 319                                             info->rx_tbl[i].buffer[j] ?
 320                                             '1' : '0');
 321
 322                        p += sprintf(p, "\n");
 323                }
 324        }
 325
 326        if (info->tdls_peer_num) {
 327                p += sprintf(p, "TDLS peer table:\n");
 328                for (i = 0; i < info->tdls_peer_num; i++) {
 329                        p += sprintf(p, "peer = %pM",
 330                                     info->tdls_list[i].peer_addr);
 331                        p += sprintf(p, "\n");
 332                }
 333        }
 334
 335        return p - buf;
 336}
 337
 338static int
 339mwifiex_parse_mgmt_packet(struct mwifiex_private *priv, u8 *payload, u16 len,
 340                          struct rxpd *rx_pd)
 341{
 342        u16 stype;
 343        u8 category, action_code, *addr2;
 344        struct ieee80211_hdr *ieee_hdr = (void *)payload;
 345
 346        stype = (le16_to_cpu(ieee_hdr->frame_control) & IEEE80211_FCTL_STYPE);
 347
 348        switch (stype) {
 349        case IEEE80211_STYPE_ACTION:
 350                category = *(payload + sizeof(struct ieee80211_hdr));
 351                switch (category) {
 352                case WLAN_CATEGORY_PUBLIC:
 353                        action_code = *(payload + sizeof(struct ieee80211_hdr)
 354                                        + 1);
 355                        if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) {
 356                                addr2 = ieee_hdr->addr2;
 357                                mwifiex_dbg(priv->adapter, INFO,
 358                                            "TDLS discovery response %pM nf=%d, snr=%d\n",
 359                                            addr2, rx_pd->nf, rx_pd->snr);
 360                                mwifiex_auto_tdls_update_peer_signal(priv,
 361                                                                     addr2,
 362                                                                     rx_pd->snr,
 363                                                                     rx_pd->nf);
 364                        }
 365                        break;
 366                case WLAN_CATEGORY_BACK:
 367                        /*we dont indicate BACK action frames to cfg80211*/
 368                        mwifiex_dbg(priv->adapter, INFO,
 369                                    "drop BACK action frames");
 370                        return -1;
 371                default:
 372                        mwifiex_dbg(priv->adapter, INFO,
 373                                    "unknown public action frame category %d\n",
 374                                    category);
 375                }
 376                break;
 377        default:
 378                mwifiex_dbg(priv->adapter, INFO,
 379                    "unknown mgmt frame subtype %#x\n", stype);
 380                return 0;
 381        }
 382
 383        return 0;
 384}
 385/*
 386 * This function processes the received management packet and send it
 387 * to the kernel.
 388 */
 389int
 390mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
 391                            struct sk_buff *skb)
 392{
 393        struct rxpd *rx_pd;
 394        u16 pkt_len;
 395        struct ieee80211_hdr *ieee_hdr;
 396
 397        if (!skb)
 398                return -1;
 399
 400        if (!priv->mgmt_frame_mask ||
 401            priv->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED) {
 402                mwifiex_dbg(priv->adapter, ERROR,
 403                            "do not receive mgmt frames on uninitialized intf");
 404                return -1;
 405        }
 406
 407        rx_pd = (struct rxpd *)skb->data;
 408
 409        skb_pull(skb, le16_to_cpu(rx_pd->rx_pkt_offset));
 410        skb_pull(skb, sizeof(pkt_len));
 411
 412        pkt_len = le16_to_cpu(rx_pd->rx_pkt_length);
 413
 414        ieee_hdr = (void *)skb->data;
 415        if (ieee80211_is_mgmt(ieee_hdr->frame_control)) {
 416                if (mwifiex_parse_mgmt_packet(priv, (u8 *)ieee_hdr,
 417                                              pkt_len, rx_pd))
 418                        return -1;
 419        }
 420        /* Remove address4 */
 421        memmove(skb->data + sizeof(struct ieee80211_hdr_3addr),
 422                skb->data + sizeof(struct ieee80211_hdr),
 423                pkt_len - sizeof(struct ieee80211_hdr));
 424
 425        pkt_len -= ETH_ALEN + sizeof(pkt_len);
 426        rx_pd->rx_pkt_length = cpu_to_le16(pkt_len);
 427
 428        cfg80211_rx_mgmt(&priv->wdev, priv->roc_cfg.chan.center_freq,
 429                         CAL_RSSI(rx_pd->snr, rx_pd->nf), skb->data, pkt_len,
 430                         0);
 431
 432        return 0;
 433}
 434
 435/*
 436 * This function processes the received packet before sending it to the
 437 * kernel.
 438 *
 439 * It extracts the SKB from the received buffer and sends it to kernel.
 440 * In case the received buffer does not contain the data in SKB format,
 441 * the function creates a blank SKB, fills it with the data from the
 442 * received buffer and then sends this new SKB to the kernel.
 443 */
 444int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb)
 445{
 446        struct mwifiex_sta_node *src_node;
 447        struct ethhdr *p_ethhdr;
 448
 449        if (!skb)
 450                return -1;
 451
 452        priv->stats.rx_bytes += skb->len;
 453        priv->stats.rx_packets++;
 454
 455        if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
 456                p_ethhdr = (void *)skb->data;
 457                src_node = mwifiex_get_sta_entry(priv, p_ethhdr->h_source);
 458                if (src_node) {
 459                        src_node->stats.last_rx = jiffies;
 460                        src_node->stats.rx_bytes += skb->len;
 461                        src_node->stats.rx_packets++;
 462                }
 463        }
 464
 465        skb->dev = priv->netdev;
 466        skb->protocol = eth_type_trans(skb, priv->netdev);
 467        skb->ip_summed = CHECKSUM_NONE;
 468
 469        /* This is required only in case of 11n and USB/PCIE as we alloc
 470         * a buffer of 4K only if its 11N (to be able to receive 4K
 471         * AMSDU packets). In case of SD we allocate buffers based
 472         * on the size of packet and hence this is not needed.
 473         *
 474         * Modifying the truesize here as our allocation for each
 475         * skb is 4K but we only receive 2K packets and this cause
 476         * the kernel to start dropping packets in case where
 477         * application has allocated buffer based on 2K size i.e.
 478         * if there a 64K packet received (in IP fragments and
 479         * application allocates 64K to receive this packet but
 480         * this packet would almost double up because we allocate
 481         * each 1.5K fragment in 4K and pass it up. As soon as the
 482         * 64K limit hits kernel will start to drop rest of the
 483         * fragments. Currently we fail the Filesndl-ht.scr script
 484         * for UDP, hence this fix
 485         */
 486        if ((priv->adapter->iface_type == MWIFIEX_USB ||
 487             priv->adapter->iface_type == MWIFIEX_PCIE) &&
 488            (skb->truesize > MWIFIEX_RX_DATA_BUF_SIZE))
 489                skb->truesize += (skb->len - MWIFIEX_RX_DATA_BUF_SIZE);
 490
 491        if (in_interrupt())
 492                netif_rx(skb);
 493        else
 494                netif_rx_ni(skb);
 495
 496        return 0;
 497}
 498
 499/*
 500 * IOCTL completion callback handler.
 501 *
 502 * This function is called when a pending IOCTL is completed.
 503 *
 504 * If work queue support is enabled, the function wakes up the
 505 * corresponding waiting function. Otherwise, it processes the
 506 * IOCTL response and frees the response buffer.
 507 */
 508int mwifiex_complete_cmd(struct mwifiex_adapter *adapter,
 509                         struct cmd_ctrl_node *cmd_node)
 510{
 511        WARN_ON(!cmd_node->wait_q_enabled);
 512        mwifiex_dbg(adapter, CMD, "cmd completed: status=%d\n",
 513                    adapter->cmd_wait_q.status);
 514
 515        *cmd_node->condition = true;
 516        wake_up_interruptible(&adapter->cmd_wait_q.wait);
 517
 518        return 0;
 519}
 520
 521/* This function will return the pointer to station entry in station list
 522 * table which matches specified mac address.
 523 * This function should be called after acquiring RA list spinlock.
 524 * NULL is returned if station entry is not found in associated STA list.
 525 */
 526struct mwifiex_sta_node *
 527mwifiex_get_sta_entry(struct mwifiex_private *priv, const u8 *mac)
 528{
 529        struct mwifiex_sta_node *node;
 530
 531        if (!mac)
 532                return NULL;
 533
 534        list_for_each_entry(node, &priv->sta_list, list) {
 535                if (!memcmp(node->mac_addr, mac, ETH_ALEN))
 536                        return node;
 537        }
 538
 539        return NULL;
 540}
 541
 542static struct mwifiex_sta_node *
 543mwifiex_get_tdls_sta_entry(struct mwifiex_private *priv, u8 status)
 544{
 545        struct mwifiex_sta_node *node;
 546
 547        list_for_each_entry(node, &priv->sta_list, list) {
 548                if (node->tdls_status == status)
 549                        return node;
 550        }
 551
 552        return NULL;
 553}
 554
 555/* If tdls channel switching is on-going, tx data traffic should be
 556 * blocked until the switching stage completed.
 557 */
 558u8 mwifiex_is_tdls_chan_switching(struct mwifiex_private *priv)
 559{
 560        struct mwifiex_sta_node *sta_ptr;
 561
 562        if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info))
 563                return false;
 564
 565        sta_ptr = mwifiex_get_tdls_sta_entry(priv, TDLS_CHAN_SWITCHING);
 566        if (sta_ptr)
 567                return true;
 568
 569        return false;
 570}
 571
 572u8 mwifiex_is_tdls_off_chan(struct mwifiex_private *priv)
 573{
 574        struct mwifiex_sta_node *sta_ptr;
 575
 576        if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info))
 577                return false;
 578
 579        sta_ptr = mwifiex_get_tdls_sta_entry(priv, TDLS_IN_OFF_CHAN);
 580        if (sta_ptr)
 581                return true;
 582
 583        return false;
 584}
 585
 586/* If tdls channel switching is on-going or tdls operate on off-channel,
 587 * cmd path should be blocked until tdls switched to base-channel.
 588 */
 589u8 mwifiex_is_send_cmd_allowed(struct mwifiex_private *priv)
 590{
 591        if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info))
 592                return true;
 593
 594        if (mwifiex_is_tdls_chan_switching(priv) ||
 595            mwifiex_is_tdls_off_chan(priv))
 596                return false;
 597
 598        return true;
 599}
 600
 601/* This function will add a sta_node entry to associated station list
 602 * table with the given mac address.
 603 * If entry exist already, existing entry is returned.
 604 * If received mac address is NULL, NULL is returned.
 605 */
 606struct mwifiex_sta_node *
 607mwifiex_add_sta_entry(struct mwifiex_private *priv, const u8 *mac)
 608{
 609        struct mwifiex_sta_node *node;
 610
 611        if (!mac)
 612                return NULL;
 613
 614        spin_lock_bh(&priv->sta_list_spinlock);
 615        node = mwifiex_get_sta_entry(priv, mac);
 616        if (node)
 617                goto done;
 618
 619        node = kzalloc(sizeof(*node), GFP_ATOMIC);
 620        if (!node)
 621                goto done;
 622
 623        memcpy(node->mac_addr, mac, ETH_ALEN);
 624        list_add_tail(&node->list, &priv->sta_list);
 625
 626done:
 627        spin_unlock_bh(&priv->sta_list_spinlock);
 628        return node;
 629}
 630
 631/* This function will search for HT IE in association request IEs
 632 * and set station HT parameters accordingly.
 633 */
 634void
 635mwifiex_set_sta_ht_cap(struct mwifiex_private *priv, const u8 *ies,
 636                       int ies_len, struct mwifiex_sta_node *node)
 637{
 638        struct ieee_types_header *ht_cap_ie;
 639        const struct ieee80211_ht_cap *ht_cap;
 640
 641        if (!ies)
 642                return;
 643
 644        ht_cap_ie = (void *)cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies,
 645                                             ies_len);
 646        if (ht_cap_ie) {
 647                ht_cap = (void *)(ht_cap_ie + 1);
 648                node->is_11n_enabled = 1;
 649                node->max_amsdu = le16_to_cpu(ht_cap->cap_info) &
 650                                  IEEE80211_HT_CAP_MAX_AMSDU ?
 651                                  MWIFIEX_TX_DATA_BUF_SIZE_8K :
 652                                  MWIFIEX_TX_DATA_BUF_SIZE_4K;
 653        } else {
 654                node->is_11n_enabled = 0;
 655        }
 656
 657        return;
 658}
 659
 660/* This function will delete a station entry from station list */
 661void mwifiex_del_sta_entry(struct mwifiex_private *priv, const u8 *mac)
 662{
 663        struct mwifiex_sta_node *node;
 664
 665        spin_lock_bh(&priv->sta_list_spinlock);
 666
 667        node = mwifiex_get_sta_entry(priv, mac);
 668        if (node) {
 669                list_del(&node->list);
 670                kfree(node);
 671        }
 672
 673        spin_unlock_bh(&priv->sta_list_spinlock);
 674        return;
 675}
 676
 677/* This function will delete all stations from associated station list. */
 678void mwifiex_del_all_sta_list(struct mwifiex_private *priv)
 679{
 680        struct mwifiex_sta_node *node, *tmp;
 681
 682        spin_lock_bh(&priv->sta_list_spinlock);
 683
 684        list_for_each_entry_safe(node, tmp, &priv->sta_list, list) {
 685                list_del(&node->list);
 686                kfree(node);
 687        }
 688
 689        INIT_LIST_HEAD(&priv->sta_list);
 690        spin_unlock_bh(&priv->sta_list_spinlock);
 691        return;
 692}
 693
 694/* This function adds histogram data to histogram array*/
 695void mwifiex_hist_data_add(struct mwifiex_private *priv,
 696                           u8 rx_rate, s8 snr, s8 nflr)
 697{
 698        struct mwifiex_histogram_data *phist_data = priv->hist_data;
 699
 700        if (atomic_read(&phist_data->num_samples) > MWIFIEX_HIST_MAX_SAMPLES)
 701                mwifiex_hist_data_reset(priv);
 702        mwifiex_hist_data_set(priv, rx_rate, snr, nflr);
 703}
 704
 705/* function to add histogram record */
 706void mwifiex_hist_data_set(struct mwifiex_private *priv, u8 rx_rate, s8 snr,
 707                           s8 nflr)
 708{
 709        struct mwifiex_histogram_data *phist_data = priv->hist_data;
 710        s8 nf   = -nflr;
 711        s8 rssi = snr - nflr;
 712
 713        atomic_inc(&phist_data->num_samples);
 714        atomic_inc(&phist_data->rx_rate[rx_rate]);
 715        atomic_inc(&phist_data->snr[snr + 128]);
 716        atomic_inc(&phist_data->noise_flr[nf + 128]);
 717        atomic_inc(&phist_data->sig_str[rssi + 128]);
 718}
 719
 720/* function to reset histogram data during init/reset */
 721void mwifiex_hist_data_reset(struct mwifiex_private *priv)
 722{
 723        int ix;
 724        struct mwifiex_histogram_data *phist_data = priv->hist_data;
 725
 726        atomic_set(&phist_data->num_samples, 0);
 727        for (ix = 0; ix < MWIFIEX_MAX_AC_RX_RATES; ix++)
 728                atomic_set(&phist_data->rx_rate[ix], 0);
 729        for (ix = 0; ix < MWIFIEX_MAX_SNR; ix++)
 730                atomic_set(&phist_data->snr[ix], 0);
 731        for (ix = 0; ix < MWIFIEX_MAX_NOISE_FLR; ix++)
 732                atomic_set(&phist_data->noise_flr[ix], 0);
 733        for (ix = 0; ix < MWIFIEX_MAX_SIG_STRENGTH; ix++)
 734                atomic_set(&phist_data->sig_str[ix], 0);
 735}
 736
 737void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags)
 738{
 739        struct sk_buff *skb;
 740        int buf_len, pad;
 741
 742        buf_len = rx_len + MWIFIEX_RX_HEADROOM + MWIFIEX_DMA_ALIGN_SZ;
 743
 744        skb = __dev_alloc_skb(buf_len, flags);
 745
 746        if (!skb)
 747                return NULL;
 748
 749        skb_reserve(skb, MWIFIEX_RX_HEADROOM);
 750
 751        pad = MWIFIEX_ALIGN_ADDR(skb->data, MWIFIEX_DMA_ALIGN_SZ) -
 752              (long)skb->data;
 753
 754        skb_reserve(skb, pad);
 755
 756        return skb;
 757}
 758EXPORT_SYMBOL_GPL(mwifiex_alloc_dma_align_buf);
 759
 760void mwifiex_fw_dump_event(struct mwifiex_private *priv)
 761{
 762        mwifiex_send_cmd(priv, HostCmd_CMD_FW_DUMP_EVENT, HostCmd_ACT_GEN_SET,
 763                         0, NULL, true);
 764}
 765EXPORT_SYMBOL_GPL(mwifiex_fw_dump_event);
 766