linux/drivers/net/wireless/rsi/rsi_91x_main.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2014 Redpine Signals Inc.
   3 *
   4 * Permission to use, copy, modify, and/or distribute this software for any
   5 * purpose with or without fee is hereby granted, provided that the above
   6 * copyright notice and this permission notice appear in all copies.
   7 *
   8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15 */
  16
  17#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  18
  19#include <linux/module.h>
  20#include <linux/firmware.h>
  21#include <net/rsi_91x.h>
  22#include "rsi_mgmt.h"
  23#include "rsi_common.h"
  24#include "rsi_coex.h"
  25#include "rsi_hal.h"
  26
  27u32 rsi_zone_enabled = /* INFO_ZONE |
  28                        INIT_ZONE |
  29                        MGMT_TX_ZONE |
  30                        MGMT_RX_ZONE |
  31                        DATA_TX_ZONE |
  32                        DATA_RX_ZONE |
  33                        FSM_ZONE |
  34                        ISR_ZONE | */
  35                        ERR_ZONE |
  36                        0;
  37EXPORT_SYMBOL_GPL(rsi_zone_enabled);
  38
  39#ifdef CONFIG_RSI_COEX
  40static struct rsi_proto_ops g_proto_ops = {
  41        .coex_send_pkt = rsi_coex_send_pkt,
  42        .get_host_intf = rsi_get_host_intf,
  43        .set_bt_context = rsi_set_bt_context,
  44};
  45#endif
  46
  47/**
  48 * rsi_dbg() - This function outputs informational messages.
  49 * @zone: Zone of interest for output message.
  50 * @fmt: printf-style format for output message.
  51 *
  52 * Return: none
  53 */
  54void rsi_dbg(u32 zone, const char *fmt, ...)
  55{
  56        struct va_format vaf;
  57        va_list args;
  58
  59        va_start(args, fmt);
  60
  61        vaf.fmt = fmt;
  62        vaf.va = &args;
  63
  64        if (zone & rsi_zone_enabled)
  65                pr_info("%pV", &vaf);
  66        va_end(args);
  67}
  68EXPORT_SYMBOL_GPL(rsi_dbg);
  69
  70static char *opmode_str(int oper_mode)
  71{
  72        switch (oper_mode) {
  73        case DEV_OPMODE_WIFI_ALONE:
  74                return "Wi-Fi alone";
  75        case DEV_OPMODE_BT_ALONE:
  76                return "BT EDR alone";
  77        case DEV_OPMODE_BT_LE_ALONE:
  78                return "BT LE alone";
  79        case DEV_OPMODE_BT_DUAL:
  80                return "BT Dual";
  81        case DEV_OPMODE_STA_BT:
  82                return "Wi-Fi STA + BT EDR";
  83        case DEV_OPMODE_STA_BT_LE:
  84                return "Wi-Fi STA + BT LE";
  85        case DEV_OPMODE_STA_BT_DUAL:
  86                return "Wi-Fi STA + BT DUAL";
  87        case DEV_OPMODE_AP_BT:
  88                return "Wi-Fi AP + BT EDR";
  89        case DEV_OPMODE_AP_BT_DUAL:
  90                return "Wi-Fi AP + BT DUAL";
  91        }
  92
  93        return "Unknown";
  94}
  95
  96void rsi_print_version(struct rsi_common *common)
  97{
  98        rsi_dbg(ERR_ZONE, "================================================\n");
  99        rsi_dbg(ERR_ZONE, "================ RSI Version Info ==============\n");
 100        rsi_dbg(ERR_ZONE, "================================================\n");
 101        rsi_dbg(ERR_ZONE, "FW Version\t: %d.%d.%d\n",
 102                common->lmac_ver.major, common->lmac_ver.minor,
 103                common->lmac_ver.release_num);
 104        rsi_dbg(ERR_ZONE, "Operating mode\t: %d [%s]",
 105                common->oper_mode, opmode_str(common->oper_mode));
 106        rsi_dbg(ERR_ZONE, "Firmware file\t: %s", common->priv->fw_file_name);
 107        rsi_dbg(ERR_ZONE, "================================================\n");
 108}
 109
 110/**
 111 * rsi_prepare_skb() - This function prepares the skb.
 112 * @common: Pointer to the driver private structure.
 113 * @buffer: Pointer to the packet data.
 114 * @pkt_len: Length of the packet.
 115 * @extended_desc: Extended descriptor.
 116 *
 117 * Return: Successfully skb.
 118 */
 119static struct sk_buff *rsi_prepare_skb(struct rsi_common *common,
 120                                       u8 *buffer,
 121                                       u32 pkt_len,
 122                                       u8 extended_desc)
 123{
 124        struct sk_buff *skb = NULL;
 125        u8 payload_offset;
 126
 127        if (WARN(!pkt_len, "%s: Dummy pkt received", __func__))
 128                return NULL;
 129
 130        if (pkt_len > (RSI_RCV_BUFFER_LEN * 4)) {
 131                rsi_dbg(ERR_ZONE, "%s: Pkt size > max rx buf size %d\n",
 132                        __func__, pkt_len);
 133                pkt_len = RSI_RCV_BUFFER_LEN * 4;
 134        }
 135
 136        pkt_len -= extended_desc;
 137        skb = dev_alloc_skb(pkt_len + FRAME_DESC_SZ);
 138        if (skb == NULL)
 139                return NULL;
 140
 141        payload_offset = (extended_desc + FRAME_DESC_SZ);
 142        skb_put(skb, pkt_len);
 143        memcpy((skb->data), (buffer + payload_offset), skb->len);
 144
 145        return skb;
 146}
 147
 148/**
 149 * rsi_read_pkt() - This function reads frames from the card.
 150 * @common: Pointer to the driver private structure.
 151 * @rx_pkt: Received pkt.
 152 * @rcv_pkt_len: Received pkt length. In case of USB it is 0.
 153 *
 154 * Return: 0 on success, -1 on failure.
 155 */
 156int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len)
 157{
 158        u8 *frame_desc = NULL, extended_desc = 0;
 159        u32 index, length = 0, queueno = 0;
 160        u16 actual_length = 0, offset;
 161        struct sk_buff *skb = NULL;
 162#ifdef CONFIG_RSI_COEX
 163        u8 bt_pkt_type;
 164#endif
 165
 166        index = 0;
 167        do {
 168                frame_desc = &rx_pkt[index];
 169                actual_length = *(u16 *)&frame_desc[0];
 170                offset = *(u16 *)&frame_desc[2];
 171
 172                queueno = rsi_get_queueno(frame_desc, offset);
 173                length = rsi_get_length(frame_desc, offset);
 174
 175                /* Extended descriptor is valid for WLAN queues only */
 176                if (queueno == RSI_WIFI_DATA_Q || queueno == RSI_WIFI_MGMT_Q)
 177                        extended_desc = rsi_get_extended_desc(frame_desc,
 178                                                              offset);
 179
 180                switch (queueno) {
 181                case RSI_COEX_Q:
 182#ifdef CONFIG_RSI_COEX
 183                        if (common->coex_mode > 1)
 184                                rsi_coex_recv_pkt(common, frame_desc + offset);
 185                        else
 186#endif
 187                                rsi_mgmt_pkt_recv(common,
 188                                                  (frame_desc + offset));
 189                        break;
 190
 191                case RSI_WIFI_DATA_Q:
 192                        skb = rsi_prepare_skb(common,
 193                                              (frame_desc + offset),
 194                                              length,
 195                                              extended_desc);
 196                        if (skb == NULL)
 197                                goto fail;
 198
 199                        rsi_indicate_pkt_to_os(common, skb);
 200                        break;
 201
 202                case RSI_WIFI_MGMT_Q:
 203                        rsi_mgmt_pkt_recv(common, (frame_desc + offset));
 204                        break;
 205
 206#ifdef CONFIG_RSI_COEX
 207                case RSI_BT_MGMT_Q:
 208                case RSI_BT_DATA_Q:
 209#define BT_RX_PKT_TYPE_OFST     14
 210#define BT_CARD_READY_IND       0x89
 211                        bt_pkt_type = frame_desc[offset + BT_RX_PKT_TYPE_OFST];
 212                        if (bt_pkt_type == BT_CARD_READY_IND) {
 213                                rsi_dbg(INFO_ZONE, "BT Card ready recvd\n");
 214                                if (rsi_bt_ops.attach(common, &g_proto_ops))
 215                                        rsi_dbg(ERR_ZONE,
 216                                                "Failed to attach BT module\n");
 217                        } else {
 218                                if (common->bt_adapter)
 219                                        rsi_bt_ops.recv_pkt(common->bt_adapter,
 220                                                        frame_desc + offset);
 221                        }
 222                        break;
 223#endif
 224
 225                default:
 226                        rsi_dbg(ERR_ZONE, "%s: pkt from invalid queue: %d\n",
 227                                __func__,   queueno);
 228                        goto fail;
 229                }
 230
 231                index  += actual_length;
 232                rcv_pkt_len -= actual_length;
 233        } while (rcv_pkt_len > 0);
 234
 235        return 0;
 236fail:
 237        return -EINVAL;
 238}
 239EXPORT_SYMBOL_GPL(rsi_read_pkt);
 240
 241/**
 242 * rsi_tx_scheduler_thread() - This function is a kernel thread to send the
 243 *                             packets to the device.
 244 * @common: Pointer to the driver private structure.
 245 *
 246 * Return: None.
 247 */
 248static void rsi_tx_scheduler_thread(struct rsi_common *common)
 249{
 250        struct rsi_hw *adapter = common->priv;
 251        u32 timeout = EVENT_WAIT_FOREVER;
 252
 253        do {
 254                if (adapter->determine_event_timeout)
 255                        timeout = adapter->determine_event_timeout(adapter);
 256                rsi_wait_event(&common->tx_thread.event, timeout);
 257                rsi_reset_event(&common->tx_thread.event);
 258
 259                if (common->init_done)
 260                        rsi_core_qos_processor(common);
 261        } while (atomic_read(&common->tx_thread.thread_done) == 0);
 262        complete_and_exit(&common->tx_thread.completion, 0);
 263}
 264
 265#ifdef CONFIG_RSI_COEX
 266enum rsi_host_intf rsi_get_host_intf(void *priv)
 267{
 268        struct rsi_common *common = (struct rsi_common *)priv;
 269
 270        return common->priv->rsi_host_intf;
 271}
 272
 273void rsi_set_bt_context(void *priv, void *bt_context)
 274{
 275        struct rsi_common *common = (struct rsi_common *)priv;
 276
 277        common->bt_adapter = bt_context;
 278}
 279#endif
 280
 281/**
 282 * rsi_91x_init() - This function initializes os interface operations.
 283 * @oper_mode: One of DEV_OPMODE_*.
 284 *
 285 * Return: Pointer to the adapter structure on success, NULL on failure .
 286 */
 287struct rsi_hw *rsi_91x_init(u16 oper_mode)
 288{
 289        struct rsi_hw *adapter = NULL;
 290        struct rsi_common *common = NULL;
 291        u8 ii = 0;
 292
 293        adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
 294        if (!adapter)
 295                return NULL;
 296
 297        adapter->priv = kzalloc(sizeof(*common), GFP_KERNEL);
 298        if (adapter->priv == NULL) {
 299                rsi_dbg(ERR_ZONE, "%s: Failed in allocation of memory\n",
 300                        __func__);
 301                kfree(adapter);
 302                return NULL;
 303        } else {
 304                common = adapter->priv;
 305                common->priv = adapter;
 306        }
 307
 308        for (ii = 0; ii < NUM_SOFT_QUEUES; ii++)
 309                skb_queue_head_init(&common->tx_queue[ii]);
 310
 311        rsi_init_event(&common->tx_thread.event);
 312        mutex_init(&common->mutex);
 313        mutex_init(&common->tx_lock);
 314        mutex_init(&common->rx_lock);
 315        mutex_init(&common->tx_bus_mutex);
 316
 317        if (rsi_create_kthread(common,
 318                               &common->tx_thread,
 319                               rsi_tx_scheduler_thread,
 320                               "Tx-Thread")) {
 321                rsi_dbg(ERR_ZONE, "%s: Unable to init tx thrd\n", __func__);
 322                goto err;
 323        }
 324
 325        rsi_default_ps_params(adapter);
 326        init_bgscan_params(common);
 327        spin_lock_init(&adapter->ps_lock);
 328        timer_setup(&common->roc_timer, rsi_roc_timeout, 0);
 329        init_completion(&common->wlan_init_completion);
 330        adapter->device_model = RSI_DEV_9113;
 331        common->oper_mode = oper_mode;
 332
 333        /* Determine coex mode */
 334        switch (common->oper_mode) {
 335        case DEV_OPMODE_STA_BT_DUAL:
 336        case DEV_OPMODE_STA_BT:
 337        case DEV_OPMODE_STA_BT_LE:
 338        case DEV_OPMODE_BT_ALONE:
 339        case DEV_OPMODE_BT_LE_ALONE:
 340        case DEV_OPMODE_BT_DUAL:
 341                common->coex_mode = 2;
 342                break;
 343        case DEV_OPMODE_AP_BT_DUAL:
 344        case DEV_OPMODE_AP_BT:
 345                common->coex_mode = 4;
 346                break;
 347        case DEV_OPMODE_WIFI_ALONE:
 348                common->coex_mode = 1;
 349                break;
 350        default:
 351                common->oper_mode = 1;
 352                common->coex_mode = 1;
 353        }
 354        rsi_dbg(INFO_ZONE, "%s: oper_mode = %d, coex_mode = %d\n",
 355                __func__, common->oper_mode, common->coex_mode);
 356
 357        adapter->device_model = RSI_DEV_9113;
 358#ifdef CONFIG_RSI_COEX
 359        if (common->coex_mode > 1) {
 360                if (rsi_coex_attach(common)) {
 361                        rsi_dbg(ERR_ZONE, "Failed to init coex module\n");
 362                        goto err;
 363                }
 364        }
 365#endif
 366
 367        common->init_done = true;
 368        return adapter;
 369
 370err:
 371        kfree(common);
 372        kfree(adapter);
 373        return NULL;
 374}
 375EXPORT_SYMBOL_GPL(rsi_91x_init);
 376
 377/**
 378 * rsi_91x_deinit() - This function de-intializes os intf operations.
 379 * @adapter: Pointer to the adapter structure.
 380 *
 381 * Return: None.
 382 */
 383void rsi_91x_deinit(struct rsi_hw *adapter)
 384{
 385        struct rsi_common *common = adapter->priv;
 386        u8 ii;
 387
 388        rsi_dbg(INFO_ZONE, "%s: Performing deinit os ops\n", __func__);
 389
 390        rsi_kill_thread(&common->tx_thread);
 391
 392        for (ii = 0; ii < NUM_SOFT_QUEUES; ii++)
 393                skb_queue_purge(&common->tx_queue[ii]);
 394
 395#ifdef CONFIG_RSI_COEX
 396        if (common->coex_mode > 1) {
 397                if (common->bt_adapter) {
 398                        rsi_bt_ops.detach(common->bt_adapter);
 399                        common->bt_adapter = NULL;
 400                }
 401                rsi_coex_detach(common);
 402        }
 403#endif
 404
 405        common->init_done = false;
 406
 407        kfree(common);
 408        kfree(adapter->rsi_dev);
 409        kfree(adapter);
 410}
 411EXPORT_SYMBOL_GPL(rsi_91x_deinit);
 412
 413/**
 414 * rsi_91x_hal_module_init() - This function is invoked when the module is
 415 *                             loaded into the kernel.
 416 *                             It registers the client driver.
 417 * @void: Void.
 418 *
 419 * Return: 0 on success, -1 on failure.
 420 */
 421static int rsi_91x_hal_module_init(void)
 422{
 423        rsi_dbg(INIT_ZONE, "%s: Module init called\n", __func__);
 424        return 0;
 425}
 426
 427/**
 428 * rsi_91x_hal_module_exit() - This function is called at the time of
 429 *                             removing/unloading the module.
 430 *                             It unregisters the client driver.
 431 * @void: Void.
 432 *
 433 * Return: None.
 434 */
 435static void rsi_91x_hal_module_exit(void)
 436{
 437        rsi_dbg(INIT_ZONE, "%s: Module exit called\n", __func__);
 438}
 439
 440module_init(rsi_91x_hal_module_init);
 441module_exit(rsi_91x_hal_module_exit);
 442MODULE_AUTHOR("Redpine Signals Inc");
 443MODULE_DESCRIPTION("Station driver for RSI 91x devices");
 444MODULE_VERSION("0.1");
 445MODULE_LICENSE("Dual BSD/GPL");
 446