linux/drivers/net/wireless/ti/wl1251/init.c
<<
>>
Prefs
   1/*
   2 * This file is part of wl1251
   3 *
   4 * Copyright (C) 2009 Nokia Corporation
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * version 2 as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful, but
  11 * WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13 * General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  18 * 02110-1301 USA
  19 *
  20 */
  21
  22#include <linux/kernel.h>
  23#include <linux/module.h>
  24#include <linux/slab.h>
  25
  26#include "init.h"
  27#include "wl12xx_80211.h"
  28#include "acx.h"
  29#include "cmd.h"
  30#include "reg.h"
  31
  32int wl1251_hw_init_hwenc_config(struct wl1251 *wl)
  33{
  34        int ret;
  35
  36        ret = wl1251_acx_feature_cfg(wl, 0);
  37        if (ret < 0) {
  38                wl1251_warning("couldn't set feature config");
  39                return ret;
  40        }
  41
  42        ret = wl1251_acx_default_key(wl, wl->default_key);
  43        if (ret < 0) {
  44                wl1251_warning("couldn't set default key");
  45                return ret;
  46        }
  47
  48        return 0;
  49}
  50
  51int wl1251_hw_init_templates_config(struct wl1251 *wl)
  52{
  53        int ret;
  54        u8 partial_vbm[PARTIAL_VBM_MAX];
  55
  56        /* send empty templates for fw memory reservation */
  57        ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, NULL,
  58                                      sizeof(struct wl12xx_probe_req_template));
  59        if (ret < 0)
  60                return ret;
  61
  62        ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, NULL,
  63                                      sizeof(struct wl12xx_null_data_template));
  64        if (ret < 0)
  65                return ret;
  66
  67        ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, NULL,
  68                                      sizeof(struct wl12xx_ps_poll_template));
  69        if (ret < 0)
  70                return ret;
  71
  72        ret = wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL,
  73                                      sizeof
  74                                      (struct wl12xx_qos_null_data_template));
  75        if (ret < 0)
  76                return ret;
  77
  78        ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, NULL,
  79                                      sizeof
  80                                      (struct wl12xx_probe_resp_template));
  81        if (ret < 0)
  82                return ret;
  83
  84        ret = wl1251_cmd_template_set(wl, CMD_BEACON, NULL,
  85                                      sizeof
  86                                      (struct wl12xx_beacon_template));
  87        if (ret < 0)
  88                return ret;
  89
  90        /* tim templates, first reserve space then allocate an empty one */
  91        memset(partial_vbm, 0, PARTIAL_VBM_MAX);
  92        ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0);
  93        if (ret < 0)
  94                return ret;
  95
  96        ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0);
  97        if (ret < 0)
  98                return ret;
  99
 100        return 0;
 101}
 102
 103int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter)
 104{
 105        int ret;
 106
 107        ret = wl1251_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF);
 108        if (ret < 0)
 109                return ret;
 110
 111        ret = wl1251_acx_rx_config(wl, config, filter);
 112        if (ret < 0)
 113                return ret;
 114
 115        return 0;
 116}
 117
 118int wl1251_hw_init_phy_config(struct wl1251 *wl)
 119{
 120        int ret;
 121
 122        ret = wl1251_acx_pd_threshold(wl);
 123        if (ret < 0)
 124                return ret;
 125
 126        ret = wl1251_acx_slot(wl, DEFAULT_SLOT_TIME);
 127        if (ret < 0)
 128                return ret;
 129
 130        ret = wl1251_acx_group_address_tbl(wl, true, NULL, 0);
 131        if (ret < 0)
 132                return ret;
 133
 134        ret = wl1251_acx_service_period_timeout(wl);
 135        if (ret < 0)
 136                return ret;
 137
 138        ret = wl1251_acx_rts_threshold(wl, RTS_THRESHOLD_DEF);
 139        if (ret < 0)
 140                return ret;
 141
 142        return 0;
 143}
 144
 145int wl1251_hw_init_beacon_filter(struct wl1251 *wl)
 146{
 147        int ret;
 148
 149        /* disable beacon filtering at this stage */
 150        ret = wl1251_acx_beacon_filter_opt(wl, false);
 151        if (ret < 0)
 152                return ret;
 153
 154        ret = wl1251_acx_beacon_filter_table(wl);
 155        if (ret < 0)
 156                return ret;
 157
 158        return 0;
 159}
 160
 161int wl1251_hw_init_pta(struct wl1251 *wl)
 162{
 163        int ret;
 164
 165        ret = wl1251_acx_sg_enable(wl);
 166        if (ret < 0)
 167                return ret;
 168
 169        ret = wl1251_acx_sg_cfg(wl);
 170        if (ret < 0)
 171                return ret;
 172
 173        return 0;
 174}
 175
 176int wl1251_hw_init_energy_detection(struct wl1251 *wl)
 177{
 178        int ret;
 179
 180        ret = wl1251_acx_cca_threshold(wl);
 181        if (ret < 0)
 182                return ret;
 183
 184        return 0;
 185}
 186
 187int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl)
 188{
 189        int ret;
 190
 191        ret = wl1251_acx_bcn_dtim_options(wl);
 192        if (ret < 0)
 193                return ret;
 194
 195        return 0;
 196}
 197
 198int wl1251_hw_init_power_auth(struct wl1251 *wl)
 199{
 200        return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM);
 201}
 202
 203int wl1251_hw_init_mem_config(struct wl1251 *wl)
 204{
 205        int ret;
 206
 207        ret = wl1251_acx_mem_cfg(wl);
 208        if (ret < 0)
 209                return ret;
 210
 211        wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map),
 212                                          GFP_KERNEL);
 213        if (!wl->target_mem_map) {
 214                wl1251_error("couldn't allocate target memory map");
 215                return -ENOMEM;
 216        }
 217
 218        /* we now ask for the firmware built memory map */
 219        ret = wl1251_acx_mem_map(wl, wl->target_mem_map,
 220                                 sizeof(struct wl1251_acx_mem_map));
 221        if (ret < 0) {
 222                wl1251_error("couldn't retrieve firmware memory map");
 223                kfree(wl->target_mem_map);
 224                wl->target_mem_map = NULL;
 225                return ret;
 226        }
 227
 228        return 0;
 229}
 230
 231static int wl1251_hw_init_txq_fill(u8 qid,
 232                                   struct acx_tx_queue_qos_config *config,
 233                                   u32 num_blocks)
 234{
 235        config->qid = qid;
 236
 237        switch (qid) {
 238        case QOS_AC_BE:
 239                config->high_threshold =
 240                        (QOS_TX_HIGH_BE_DEF * num_blocks) / 100;
 241                config->low_threshold =
 242                        (QOS_TX_LOW_BE_DEF * num_blocks) / 100;
 243                break;
 244        case QOS_AC_BK:
 245                config->high_threshold =
 246                        (QOS_TX_HIGH_BK_DEF * num_blocks) / 100;
 247                config->low_threshold =
 248                        (QOS_TX_LOW_BK_DEF * num_blocks) / 100;
 249                break;
 250        case QOS_AC_VI:
 251                config->high_threshold =
 252                        (QOS_TX_HIGH_VI_DEF * num_blocks) / 100;
 253                config->low_threshold =
 254                        (QOS_TX_LOW_VI_DEF * num_blocks) / 100;
 255                break;
 256        case QOS_AC_VO:
 257                config->high_threshold =
 258                        (QOS_TX_HIGH_VO_DEF * num_blocks) / 100;
 259                config->low_threshold =
 260                        (QOS_TX_LOW_VO_DEF * num_blocks) / 100;
 261                break;
 262        default:
 263                wl1251_error("Invalid TX queue id: %d", qid);
 264                return -EINVAL;
 265        }
 266
 267        return 0;
 268}
 269
 270static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl)
 271{
 272        struct acx_tx_queue_qos_config *config;
 273        struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map;
 274        int ret, i;
 275
 276        wl1251_debug(DEBUG_ACX, "acx tx queue config");
 277
 278        config = kzalloc(sizeof(*config), GFP_KERNEL);
 279        if (!config) {
 280                ret = -ENOMEM;
 281                goto out;
 282        }
 283
 284        for (i = 0; i < MAX_NUM_OF_AC; i++) {
 285                ret = wl1251_hw_init_txq_fill(i, config,
 286                                              wl_mem_map->num_tx_mem_blocks);
 287                if (ret < 0)
 288                        goto out;
 289
 290                ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG,
 291                                           config, sizeof(*config));
 292                if (ret < 0)
 293                        goto out;
 294        }
 295
 296        wl1251_acx_ac_cfg(wl, AC_BE, CWMIN_BE, CWMAX_BE, AIFS_DIFS, TXOP_BE);
 297        wl1251_acx_ac_cfg(wl, AC_BK, CWMIN_BK, CWMAX_BK, AIFS_DIFS, TXOP_BK);
 298        wl1251_acx_ac_cfg(wl, AC_VI, CWMIN_VI, CWMAX_VI, AIFS_DIFS, TXOP_VI);
 299        wl1251_acx_ac_cfg(wl, AC_VO, CWMIN_VO, CWMAX_VO, AIFS_DIFS, TXOP_VO);
 300
 301out:
 302        kfree(config);
 303        return ret;
 304}
 305
 306static int wl1251_hw_init_data_path_config(struct wl1251 *wl)
 307{
 308        int ret;
 309
 310        /* asking for the data path parameters */
 311        wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp),
 312                                GFP_KERNEL);
 313        if (!wl->data_path) {
 314                wl1251_error("Couldnt allocate data path parameters");
 315                return -ENOMEM;
 316        }
 317
 318        ret = wl1251_acx_data_path_params(wl, wl->data_path);
 319        if (ret < 0) {
 320                kfree(wl->data_path);
 321                wl->data_path = NULL;
 322                return ret;
 323        }
 324
 325        return 0;
 326}
 327
 328
 329int wl1251_hw_init(struct wl1251 *wl)
 330{
 331        struct wl1251_acx_mem_map *wl_mem_map;
 332        int ret;
 333
 334        ret = wl1251_hw_init_hwenc_config(wl);
 335        if (ret < 0)
 336                return ret;
 337
 338        /* Template settings */
 339        ret = wl1251_hw_init_templates_config(wl);
 340        if (ret < 0)
 341                return ret;
 342
 343        /* Default memory configuration */
 344        ret = wl1251_hw_init_mem_config(wl);
 345        if (ret < 0)
 346                return ret;
 347
 348        /* Default data path configuration  */
 349        ret = wl1251_hw_init_data_path_config(wl);
 350        if (ret < 0)
 351                goto out_free_memmap;
 352
 353        /* RX config */
 354        ret = wl1251_hw_init_rx_config(wl,
 355                                       RX_CFG_PROMISCUOUS | RX_CFG_TSF,
 356                                       RX_FILTER_OPTION_DEF);
 357        /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS,
 358           RX_FILTER_OPTION_FILTER_ALL); */
 359        if (ret < 0)
 360                goto out_free_data_path;
 361
 362        /* TX queues config */
 363        ret = wl1251_hw_init_tx_queue_config(wl);
 364        if (ret < 0)
 365                goto out_free_data_path;
 366
 367        /* PHY layer config */
 368        ret = wl1251_hw_init_phy_config(wl);
 369        if (ret < 0)
 370                goto out_free_data_path;
 371
 372        /* Initialize connection monitoring thresholds */
 373        ret = wl1251_acx_conn_monit_params(wl);
 374        if (ret < 0)
 375                goto out_free_data_path;
 376
 377        /* Beacon filtering */
 378        ret = wl1251_hw_init_beacon_filter(wl);
 379        if (ret < 0)
 380                goto out_free_data_path;
 381
 382        /* Bluetooth WLAN coexistence */
 383        ret = wl1251_hw_init_pta(wl);
 384        if (ret < 0)
 385                goto out_free_data_path;
 386
 387        /* Energy detection */
 388        ret = wl1251_hw_init_energy_detection(wl);
 389        if (ret < 0)
 390                goto out_free_data_path;
 391
 392        /* Beacons and boradcast settings */
 393        ret = wl1251_hw_init_beacon_broadcast(wl);
 394        if (ret < 0)
 395                goto out_free_data_path;
 396
 397        /* Enable rx data path */
 398        ret = wl1251_cmd_data_path_rx(wl, wl->channel, 1);
 399        if (ret < 0)
 400                goto out_free_data_path;
 401
 402        /* Enable tx data path */
 403        ret = wl1251_cmd_data_path_tx(wl, wl->channel, 1);
 404        if (ret < 0)
 405                goto out_free_data_path;
 406
 407        /* Default power state */
 408        ret = wl1251_hw_init_power_auth(wl);
 409        if (ret < 0)
 410                goto out_free_data_path;
 411
 412        wl_mem_map = wl->target_mem_map;
 413        wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x",
 414                    wl_mem_map->num_tx_mem_blocks,
 415                    wl->data_path->tx_control_addr,
 416                    wl_mem_map->num_rx_mem_blocks,
 417                    wl->data_path->rx_control_addr);
 418
 419        return 0;
 420
 421 out_free_data_path:
 422        kfree(wl->data_path);
 423
 424 out_free_memmap:
 425        kfree(wl->target_mem_map);
 426
 427        return ret;
 428}
 429