root/drivers/net/wireless/rsi/rsi_91x_main.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rsi_dbg
  2. opmode_str
  3. rsi_print_version
  4. rsi_prepare_skb
  5. rsi_read_pkt
  6. rsi_tx_scheduler_thread
  7. rsi_get_host_intf
  8. rsi_set_bt_context
  9. rsi_91x_init
  10. rsi_91x_deinit
  11. rsi_91x_hal_module_init
  12. rsi_91x_hal_module_exit

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

/* [<][>][^][v][top][bottom][index][help] */