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 ieee80211_tx_info *info;
 125        struct skb_info *rx_params;
 126        struct sk_buff *skb = NULL;
 127        u8 payload_offset;
 128        struct ieee80211_vif *vif;
 129        struct ieee80211_hdr *wh;
 130
 131        if (WARN(!pkt_len, "%s: Dummy pkt received", __func__))
 132                return NULL;
 133
 134        if (pkt_len > (RSI_RCV_BUFFER_LEN * 4)) {
 135                rsi_dbg(ERR_ZONE, "%s: Pkt size > max rx buf size %d\n",
 136                        __func__, pkt_len);
 137                pkt_len = RSI_RCV_BUFFER_LEN * 4;
 138        }
 139
 140        pkt_len -= extended_desc;
 141        skb = dev_alloc_skb(pkt_len + FRAME_DESC_SZ);
 142        if (skb == NULL)
 143                return NULL;
 144
 145        payload_offset = (extended_desc + FRAME_DESC_SZ);
 146        skb_put(skb, pkt_len);
 147        memcpy((skb->data), (buffer + payload_offset), skb->len);
 148        wh = (struct ieee80211_hdr *)skb->data;
 149        vif = rsi_get_vif(common->priv, wh->addr1);
 150
 151        info = IEEE80211_SKB_CB(skb);
 152        rx_params = (struct skb_info *)info->driver_data;
 153        rx_params->rssi = rsi_get_rssi(buffer);
 154        rx_params->channel = rsi_get_connected_channel(vif);
 155
 156        return skb;
 157}
 158
 159/**
 160 * rsi_read_pkt() - This function reads frames from the card.
 161 * @common: Pointer to the driver private structure.
 162 * @rcv_pkt_len: Received pkt length. In case of USB it is 0.
 163 *
 164 * Return: 0 on success, -1 on failure.
 165 */
 166int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len)
 167{
 168        u8 *frame_desc = NULL, extended_desc = 0;
 169        u32 index, length = 0, queueno = 0;
 170        u16 actual_length = 0, offset;
 171        struct sk_buff *skb = NULL;
 172#ifdef CONFIG_RSI_COEX
 173        u8 bt_pkt_type;
 174#endif
 175
 176        index = 0;
 177        do {
 178                frame_desc = &rx_pkt[index];
 179                actual_length = *(u16 *)&frame_desc[0];
 180                offset = *(u16 *)&frame_desc[2];
 181
 182                queueno = rsi_get_queueno(frame_desc, offset);
 183                length = rsi_get_length(frame_desc, offset);
 184
 185                /* Extended descriptor is valid for WLAN queues only */
 186                if (queueno == RSI_WIFI_DATA_Q || queueno == RSI_WIFI_MGMT_Q)
 187                        extended_desc = rsi_get_extended_desc(frame_desc,
 188                                                              offset);
 189
 190                switch (queueno) {
 191                case RSI_COEX_Q:
 192#ifdef CONFIG_RSI_COEX
 193                        if (common->coex_mode > 1)
 194                                rsi_coex_recv_pkt(common, frame_desc + offset);
 195                        else
 196#endif
 197                                rsi_mgmt_pkt_recv(common,
 198                                                  (frame_desc + offset));
 199                        break;
 200
 201                case RSI_WIFI_DATA_Q:
 202                        skb = rsi_prepare_skb(common,
 203                                              (frame_desc + offset),
 204                                              length,
 205                                              extended_desc);
 206                        if (skb == NULL)
 207                                goto fail;
 208
 209                        rsi_indicate_pkt_to_os(common, skb);
 210                        break;
 211
 212                case RSI_WIFI_MGMT_Q:
 213                        rsi_mgmt_pkt_recv(common, (frame_desc + offset));
 214                        break;
 215
 216#ifdef CONFIG_RSI_COEX
 217                case RSI_BT_MGMT_Q:
 218                case RSI_BT_DATA_Q:
 219#define BT_RX_PKT_TYPE_OFST     14
 220#define BT_CARD_READY_IND       0x89
 221                        bt_pkt_type = frame_desc[offset + BT_RX_PKT_TYPE_OFST];
 222                        if (bt_pkt_type == BT_CARD_READY_IND) {
 223                                rsi_dbg(INFO_ZONE, "BT Card ready recvd\n");
 224                                if (rsi_bt_ops.attach(common, &g_proto_ops))
 225                                        rsi_dbg(ERR_ZONE,
 226                                                "Failed to attach BT module\n");
 227                        } else {
 228                                if (common->bt_adapter)
 229                                        rsi_bt_ops.recv_pkt(common->bt_adapter,
 230                                                        frame_desc + offset);
 231                        }
 232                        break;
 233#endif
 234
 235                default:
 236                        rsi_dbg(ERR_ZONE, "%s: pkt from invalid queue: %d\n",
 237                                __func__,   queueno);
 238                        goto fail;
 239                }
 240
 241                index  += actual_length;
 242                rcv_pkt_len -= actual_length;
 243        } while (rcv_pkt_len > 0);
 244
 245        return 0;
 246fail:
 247        return -EINVAL;
 248}
 249EXPORT_SYMBOL_GPL(rsi_read_pkt);
 250
 251/**
 252 * rsi_tx_scheduler_thread() - This function is a kernel thread to send the
 253 *                             packets to the device.
 254 * @common: Pointer to the driver private structure.
 255 *
 256 * Return: None.
 257 */
 258static void rsi_tx_scheduler_thread(struct rsi_common *common)
 259{
 260        struct rsi_hw *adapter = common->priv;
 261        u32 timeout = EVENT_WAIT_FOREVER;
 262
 263        do {
 264                if (adapter->determine_event_timeout)
 265                        timeout = adapter->determine_event_timeout(adapter);
 266                rsi_wait_event(&common->tx_thread.event, timeout);
 267                rsi_reset_event(&common->tx_thread.event);
 268
 269                if (common->init_done)
 270                        rsi_core_qos_processor(common);
 271        } while (atomic_read(&common->tx_thread.thread_done) == 0);
 272        complete_and_exit(&common->tx_thread.completion, 0);
 273}
 274
 275#ifdef CONFIG_RSI_COEX
 276enum rsi_host_intf rsi_get_host_intf(void *priv)
 277{
 278        struct rsi_common *common = (struct rsi_common *)priv;
 279
 280        return common->priv->rsi_host_intf;
 281}
 282
 283void rsi_set_bt_context(void *priv, void *bt_context)
 284{
 285        struct rsi_common *common = (struct rsi_common *)priv;
 286
 287        common->bt_adapter = bt_context;
 288}
 289#endif
 290
 291/**
 292 * rsi_91x_init() - This function initializes os interface operations.
 293 * @void: Void.
 294 *
 295 * Return: Pointer to the adapter structure on success, NULL on failure .
 296 */
 297struct rsi_hw *rsi_91x_init(u16 oper_mode)
 298{
 299        struct rsi_hw *adapter = NULL;
 300        struct rsi_common *common = NULL;
 301        u8 ii = 0;
 302
 303        adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
 304        if (!adapter)
 305                return NULL;
 306
 307        adapter->priv = kzalloc(sizeof(*common), GFP_KERNEL);
 308        if (adapter->priv == NULL) {
 309                rsi_dbg(ERR_ZONE, "%s: Failed in allocation of memory\n",
 310                        __func__);
 311                kfree(adapter);
 312                return NULL;
 313        } else {
 314                common = adapter->priv;
 315                common->priv = adapter;
 316        }
 317
 318        for (ii = 0; ii < NUM_SOFT_QUEUES; ii++)
 319                skb_queue_head_init(&common->tx_queue[ii]);
 320
 321        rsi_init_event(&common->tx_thread.event);
 322        mutex_init(&common->mutex);
 323        mutex_init(&common->tx_lock);
 324        mutex_init(&common->rx_lock);
 325        mutex_init(&common->tx_bus_mutex);
 326
 327        if (rsi_create_kthread(common,
 328                               &common->tx_thread,
 329                               rsi_tx_scheduler_thread,
 330                               "Tx-Thread")) {
 331                rsi_dbg(ERR_ZONE, "%s: Unable to init tx thrd\n", __func__);
 332                goto err;
 333        }
 334
 335        rsi_default_ps_params(adapter);
 336        spin_lock_init(&adapter->ps_lock);
 337        timer_setup(&common->roc_timer, rsi_roc_timeout, 0);
 338        init_completion(&common->wlan_init_completion);
 339        common->init_done = true;
 340        adapter->device_model = RSI_DEV_9113;
 341        common->oper_mode = oper_mode;
 342
 343        /* Determine coex mode */
 344        switch (common->oper_mode) {
 345        case DEV_OPMODE_STA_BT_DUAL:
 346        case DEV_OPMODE_STA_BT:
 347        case DEV_OPMODE_STA_BT_LE:
 348        case DEV_OPMODE_BT_ALONE:
 349        case DEV_OPMODE_BT_LE_ALONE:
 350        case DEV_OPMODE_BT_DUAL:
 351                common->coex_mode = 2;
 352                break;
 353        case DEV_OPMODE_AP_BT_DUAL:
 354        case DEV_OPMODE_AP_BT:
 355                common->coex_mode = 4;
 356                break;
 357        case DEV_OPMODE_WIFI_ALONE:
 358                common->coex_mode = 1;
 359                break;
 360        default:
 361                common->oper_mode = 1;
 362                common->coex_mode = 1;
 363        }
 364        rsi_dbg(INFO_ZONE, "%s: oper_mode = %d, coex_mode = %d\n",
 365                __func__, common->oper_mode, common->coex_mode);
 366
 367        adapter->device_model = RSI_DEV_9113;
 368#ifdef CONFIG_RSI_COEX
 369        if (common->coex_mode > 1) {
 370                if (rsi_coex_attach(common)) {
 371                        rsi_dbg(ERR_ZONE, "Failed to init coex module\n");
 372                        goto err;
 373                }
 374        }
 375#endif
 376
 377        return adapter;
 378
 379err:
 380        kfree(common);
 381        kfree(adapter);
 382        return NULL;
 383}
 384EXPORT_SYMBOL_GPL(rsi_91x_init);
 385
 386/**
 387 * rsi_91x_deinit() - This function de-intializes os intf operations.
 388 * @adapter: Pointer to the adapter structure.
 389 *
 390 * Return: None.
 391 */
 392void rsi_91x_deinit(struct rsi_hw *adapter)
 393{
 394        struct rsi_common *common = adapter->priv;
 395        u8 ii;
 396
 397        rsi_dbg(INFO_ZONE, "%s: Performing deinit os ops\n", __func__);
 398
 399        rsi_kill_thread(&common->tx_thread);
 400
 401        for (ii = 0; ii < NUM_SOFT_QUEUES; ii++)
 402                skb_queue_purge(&common->tx_queue[ii]);
 403
 404#ifdef CONFIG_RSI_COEX
 405        if (common->coex_mode > 1) {
 406                if (common->bt_adapter) {
 407                        rsi_bt_ops.detach(common->bt_adapter);
 408                        common->bt_adapter = NULL;
 409                }
 410                rsi_coex_detach(common);
 411        }
 412#endif
 413
 414        common->init_done = false;
 415
 416        kfree(common);
 417        kfree(adapter->rsi_dev);
 418        kfree(adapter);
 419}
 420EXPORT_SYMBOL_GPL(rsi_91x_deinit);
 421
 422/**
 423 * rsi_91x_hal_module_init() - This function is invoked when the module is
 424 *                             loaded into the kernel.
 425 *                             It registers the client driver.
 426 * @void: Void.
 427 *
 428 * Return: 0 on success, -1 on failure.
 429 */
 430static int rsi_91x_hal_module_init(void)
 431{
 432        rsi_dbg(INIT_ZONE, "%s: Module init called\n", __func__);
 433        return 0;
 434}
 435
 436/**
 437 * rsi_91x_hal_module_exit() - This function is called at the time of
 438 *                             removing/unloading the module.
 439 *                             It unregisters the client driver.
 440 * @void: Void.
 441 *
 442 * Return: None.
 443 */
 444static void rsi_91x_hal_module_exit(void)
 445{
 446        rsi_dbg(INIT_ZONE, "%s: Module exit called\n", __func__);
 447}
 448
 449module_init(rsi_91x_hal_module_init);
 450module_exit(rsi_91x_hal_module_exit);
 451MODULE_AUTHOR("Redpine Signals Inc");
 452MODULE_DESCRIPTION("Station driver for RSI 91x devices");
 453MODULE_VERSION("0.1");
 454MODULE_LICENSE("Dual BSD/GPL");
 455