linux/drivers/net/wireless/ath/ath10k/testmode.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2014 Qualcomm Atheros, 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#include "testmode.h"
  18
  19#include <net/netlink.h>
  20#include <linux/firmware.h>
  21
  22#include "debug.h"
  23#include "wmi.h"
  24#include "hif.h"
  25#include "hw.h"
  26#include "core.h"
  27
  28#include "testmode_i.h"
  29
  30static const struct nla_policy ath10k_tm_policy[ATH10K_TM_ATTR_MAX + 1] = {
  31        [ATH10K_TM_ATTR_CMD]            = { .type = NLA_U32 },
  32        [ATH10K_TM_ATTR_DATA]           = { .type = NLA_BINARY,
  33                                            .len = ATH10K_TM_DATA_MAX_LEN },
  34        [ATH10K_TM_ATTR_WMI_CMDID]      = { .type = NLA_U32 },
  35        [ATH10K_TM_ATTR_VERSION_MAJOR]  = { .type = NLA_U32 },
  36        [ATH10K_TM_ATTR_VERSION_MINOR]  = { .type = NLA_U32 },
  37};
  38
  39/* Returns true if callee consumes the skb and the skb should be discarded.
  40 * Returns false if skb is not used. Does not sleep.
  41 */
  42bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb)
  43{
  44        struct sk_buff *nl_skb;
  45        bool consumed;
  46        int ret;
  47
  48        ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
  49                   "testmode event wmi cmd_id %d skb %pK skb->len %d\n",
  50                   cmd_id, skb, skb->len);
  51
  52        ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", skb->data, skb->len);
  53
  54        spin_lock_bh(&ar->data_lock);
  55
  56        if (!ar->testmode.utf_monitor) {
  57                consumed = false;
  58                goto out;
  59        }
  60
  61        /* Only testmode.c should be handling events from utf firmware,
  62         * otherwise all sort of problems will arise as mac80211 operations
  63         * are not initialised.
  64         */
  65        consumed = true;
  66
  67        nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy,
  68                                                   2 * sizeof(u32) + skb->len,
  69                                                   GFP_ATOMIC);
  70        if (!nl_skb) {
  71                ath10k_warn(ar,
  72                            "failed to allocate skb for testmode wmi event\n");
  73                goto out;
  74        }
  75
  76        ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_CMD, ATH10K_TM_CMD_WMI);
  77        if (ret) {
  78                ath10k_warn(ar,
  79                            "failed to to put testmode wmi event cmd attribute: %d\n",
  80                            ret);
  81                kfree_skb(nl_skb);
  82                goto out;
  83        }
  84
  85        ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_WMI_CMDID, cmd_id);
  86        if (ret) {
  87                ath10k_warn(ar,
  88                            "failed to to put testmode wmi even cmd_id: %d\n",
  89                            ret);
  90                kfree_skb(nl_skb);
  91                goto out;
  92        }
  93
  94        ret = nla_put(nl_skb, ATH10K_TM_ATTR_DATA, skb->len, skb->data);
  95        if (ret) {
  96                ath10k_warn(ar,
  97                            "failed to copy skb to testmode wmi event: %d\n",
  98                            ret);
  99                kfree_skb(nl_skb);
 100                goto out;
 101        }
 102
 103        cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
 104
 105out:
 106        spin_unlock_bh(&ar->data_lock);
 107
 108        return consumed;
 109}
 110
 111static int ath10k_tm_cmd_get_version(struct ath10k *ar, struct nlattr *tb[])
 112{
 113        struct sk_buff *skb;
 114        int ret;
 115
 116        ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
 117                   "testmode cmd get version_major %d version_minor %d\n",
 118                   ATH10K_TESTMODE_VERSION_MAJOR,
 119                   ATH10K_TESTMODE_VERSION_MINOR);
 120
 121        skb = cfg80211_testmode_alloc_reply_skb(ar->hw->wiphy,
 122                                                nla_total_size(sizeof(u32)));
 123        if (!skb)
 124                return -ENOMEM;
 125
 126        ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MAJOR,
 127                          ATH10K_TESTMODE_VERSION_MAJOR);
 128        if (ret) {
 129                kfree_skb(skb);
 130                return ret;
 131        }
 132
 133        ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MINOR,
 134                          ATH10K_TESTMODE_VERSION_MINOR);
 135        if (ret) {
 136                kfree_skb(skb);
 137                return ret;
 138        }
 139
 140        ret = nla_put_u32(skb, ATH10K_TM_ATTR_WMI_OP_VERSION,
 141                          ar->normal_mode_fw.fw_file.wmi_op_version);
 142        if (ret) {
 143                kfree_skb(skb);
 144                return ret;
 145        }
 146
 147        return cfg80211_testmode_reply(skb);
 148}
 149
 150static int ath10k_tm_fetch_utf_firmware_api_1(struct ath10k *ar,
 151                                              struct ath10k_fw_file *fw_file)
 152{
 153        char filename[100];
 154        int ret;
 155
 156        snprintf(filename, sizeof(filename), "%s/%s",
 157                 ar->hw_params.fw.dir, ATH10K_FW_UTF_FILE);
 158
 159        /* load utf firmware image */
 160        ret = request_firmware_direct(&fw_file->firmware, filename, ar->dev);
 161        ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode fw request '%s': %d\n",
 162                   filename, ret);
 163
 164        if (ret) {
 165                ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n",
 166                            filename, ret);
 167                return ret;
 168        }
 169
 170        /* We didn't find FW UTF API 1 ("utf.bin") does not advertise
 171         * firmware features. Do an ugly hack where we force the firmware
 172         * features to match with 10.1 branch so that wmi.c will use the
 173         * correct WMI interface.
 174         */
 175
 176        fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_10_1;
 177        fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_10_1;
 178        fw_file->firmware_data = fw_file->firmware->data;
 179        fw_file->firmware_len = fw_file->firmware->size;
 180
 181        return 0;
 182}
 183
 184static int ath10k_tm_fetch_firmware(struct ath10k *ar)
 185{
 186        struct ath10k_fw_components *utf_mode_fw;
 187        int ret;
 188
 189        ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_UTF_API2_FILE,
 190                                               &ar->testmode.utf_mode_fw.fw_file);
 191        if (ret == 0) {
 192                ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using fw utf api 2");
 193                goto out;
 194        }
 195
 196        ret = ath10k_tm_fetch_utf_firmware_api_1(ar, &ar->testmode.utf_mode_fw.fw_file);
 197        if (ret) {
 198                ath10k_err(ar, "failed to fetch utf firmware binary: %d", ret);
 199                return ret;
 200        }
 201
 202        ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using utf api 1");
 203
 204out:
 205        utf_mode_fw = &ar->testmode.utf_mode_fw;
 206
 207        /* Use the same board data file as the normal firmware uses (but
 208         * it's still "owned" by normal_mode_fw so we shouldn't free it.
 209         */
 210        utf_mode_fw->board_data = ar->normal_mode_fw.board_data;
 211        utf_mode_fw->board_len = ar->normal_mode_fw.board_len;
 212
 213        if (!utf_mode_fw->fw_file.otp_data) {
 214                ath10k_info(ar, "utf.bin didn't contain otp binary, taking it from the normal mode firmware");
 215                utf_mode_fw->fw_file.otp_data = ar->normal_mode_fw.fw_file.otp_data;
 216                utf_mode_fw->fw_file.otp_len = ar->normal_mode_fw.fw_file.otp_len;
 217        }
 218
 219        return 0;
 220}
 221
 222static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
 223{
 224        const char *ver;
 225        int ret;
 226
 227        ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf start\n");
 228
 229        mutex_lock(&ar->conf_mutex);
 230
 231        if (ar->state == ATH10K_STATE_UTF) {
 232                ret = -EALREADY;
 233                goto err;
 234        }
 235
 236        /* start utf only when the driver is not in use  */
 237        if (ar->state != ATH10K_STATE_OFF) {
 238                ret = -EBUSY;
 239                goto err;
 240        }
 241
 242        if (WARN_ON(ar->testmode.utf_mode_fw.fw_file.firmware != NULL)) {
 243                /* utf image is already downloaded, it shouldn't be */
 244                ret = -EEXIST;
 245                goto err;
 246        }
 247
 248        ret = ath10k_tm_fetch_firmware(ar);
 249        if (ret) {
 250                ath10k_err(ar, "failed to fetch UTF firmware: %d", ret);
 251                goto err;
 252        }
 253
 254        if (ar->testmode.utf_mode_fw.fw_file.codeswap_data &&
 255            ar->testmode.utf_mode_fw.fw_file.codeswap_len) {
 256                ret = ath10k_swap_code_seg_init(ar,
 257                                                &ar->testmode.utf_mode_fw.fw_file);
 258                if (ret) {
 259                        ath10k_warn(ar,
 260                                    "failed to init utf code swap segment: %d\n",
 261                                    ret);
 262                        goto err_release_utf_mode_fw;
 263                }
 264        }
 265
 266        spin_lock_bh(&ar->data_lock);
 267        ar->testmode.utf_monitor = true;
 268        spin_unlock_bh(&ar->data_lock);
 269
 270        ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode wmi version %d\n",
 271                   ar->testmode.utf_mode_fw.fw_file.wmi_op_version);
 272
 273        ret = ath10k_hif_power_up(ar);
 274        if (ret) {
 275                ath10k_err(ar, "failed to power up hif (testmode): %d\n", ret);
 276                ar->state = ATH10K_STATE_OFF;
 277                goto err_release_utf_mode_fw;
 278        }
 279
 280        ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_UTF,
 281                                &ar->testmode.utf_mode_fw);
 282        if (ret) {
 283                ath10k_err(ar, "failed to start core (testmode): %d\n", ret);
 284                ar->state = ATH10K_STATE_OFF;
 285                goto err_power_down;
 286        }
 287
 288        ar->state = ATH10K_STATE_UTF;
 289
 290        if (strlen(ar->testmode.utf_mode_fw.fw_file.fw_version) > 0)
 291                ver = ar->testmode.utf_mode_fw.fw_file.fw_version;
 292        else
 293                ver = "API 1";
 294
 295        ath10k_info(ar, "UTF firmware %s started\n", ver);
 296
 297        mutex_unlock(&ar->conf_mutex);
 298
 299        return 0;
 300
 301err_power_down:
 302        ath10k_hif_power_down(ar);
 303
 304err_release_utf_mode_fw:
 305        if (ar->testmode.utf_mode_fw.fw_file.codeswap_data &&
 306            ar->testmode.utf_mode_fw.fw_file.codeswap_len)
 307                ath10k_swap_code_seg_release(ar,
 308                                             &ar->testmode.utf_mode_fw.fw_file);
 309
 310        release_firmware(ar->testmode.utf_mode_fw.fw_file.firmware);
 311        ar->testmode.utf_mode_fw.fw_file.firmware = NULL;
 312
 313err:
 314        mutex_unlock(&ar->conf_mutex);
 315
 316        return ret;
 317}
 318
 319static void __ath10k_tm_cmd_utf_stop(struct ath10k *ar)
 320{
 321        lockdep_assert_held(&ar->conf_mutex);
 322
 323        ath10k_core_stop(ar);
 324        ath10k_hif_power_down(ar);
 325
 326        spin_lock_bh(&ar->data_lock);
 327
 328        ar->testmode.utf_monitor = false;
 329
 330        spin_unlock_bh(&ar->data_lock);
 331
 332        if (ar->testmode.utf_mode_fw.fw_file.codeswap_data &&
 333            ar->testmode.utf_mode_fw.fw_file.codeswap_len)
 334                ath10k_swap_code_seg_release(ar,
 335                                             &ar->testmode.utf_mode_fw.fw_file);
 336
 337        release_firmware(ar->testmode.utf_mode_fw.fw_file.firmware);
 338        ar->testmode.utf_mode_fw.fw_file.firmware = NULL;
 339
 340        ar->state = ATH10K_STATE_OFF;
 341}
 342
 343static int ath10k_tm_cmd_utf_stop(struct ath10k *ar, struct nlattr *tb[])
 344{
 345        int ret;
 346
 347        ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf stop\n");
 348
 349        mutex_lock(&ar->conf_mutex);
 350
 351        if (ar->state != ATH10K_STATE_UTF) {
 352                ret = -ENETDOWN;
 353                goto out;
 354        }
 355
 356        __ath10k_tm_cmd_utf_stop(ar);
 357
 358        ret = 0;
 359
 360        ath10k_info(ar, "UTF firmware stopped\n");
 361
 362out:
 363        mutex_unlock(&ar->conf_mutex);
 364        return ret;
 365}
 366
 367static int ath10k_tm_cmd_wmi(struct ath10k *ar, struct nlattr *tb[])
 368{
 369        struct sk_buff *skb;
 370        int ret, buf_len;
 371        u32 cmd_id;
 372        void *buf;
 373
 374        mutex_lock(&ar->conf_mutex);
 375
 376        if (ar->state != ATH10K_STATE_UTF) {
 377                ret = -ENETDOWN;
 378                goto out;
 379        }
 380
 381        if (!tb[ATH10K_TM_ATTR_DATA]) {
 382                ret = -EINVAL;
 383                goto out;
 384        }
 385
 386        if (!tb[ATH10K_TM_ATTR_WMI_CMDID]) {
 387                ret = -EINVAL;
 388                goto out;
 389        }
 390
 391        buf = nla_data(tb[ATH10K_TM_ATTR_DATA]);
 392        buf_len = nla_len(tb[ATH10K_TM_ATTR_DATA]);
 393        cmd_id = nla_get_u32(tb[ATH10K_TM_ATTR_WMI_CMDID]);
 394
 395        ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
 396                   "testmode cmd wmi cmd_id %d buf %pK buf_len %d\n",
 397                   cmd_id, buf, buf_len);
 398
 399        ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", buf, buf_len);
 400
 401        skb = ath10k_wmi_alloc_skb(ar, buf_len);
 402        if (!skb) {
 403                ret = -ENOMEM;
 404                goto out;
 405        }
 406
 407        memcpy(skb->data, buf, buf_len);
 408
 409        ret = ath10k_wmi_cmd_send(ar, skb, cmd_id);
 410        if (ret) {
 411                ath10k_warn(ar, "failed to transmit wmi command (testmode): %d\n",
 412                            ret);
 413                goto out;
 414        }
 415
 416        ret = 0;
 417
 418out:
 419        mutex_unlock(&ar->conf_mutex);
 420        return ret;
 421}
 422
 423int ath10k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 424                  void *data, int len)
 425{
 426        struct ath10k *ar = hw->priv;
 427        struct nlattr *tb[ATH10K_TM_ATTR_MAX + 1];
 428        int ret;
 429
 430        ret = nla_parse(tb, ATH10K_TM_ATTR_MAX, data, len, ath10k_tm_policy,
 431                        NULL);
 432        if (ret)
 433                return ret;
 434
 435        if (!tb[ATH10K_TM_ATTR_CMD])
 436                return -EINVAL;
 437
 438        switch (nla_get_u32(tb[ATH10K_TM_ATTR_CMD])) {
 439        case ATH10K_TM_CMD_GET_VERSION:
 440                return ath10k_tm_cmd_get_version(ar, tb);
 441        case ATH10K_TM_CMD_UTF_START:
 442                return ath10k_tm_cmd_utf_start(ar, tb);
 443        case ATH10K_TM_CMD_UTF_STOP:
 444                return ath10k_tm_cmd_utf_stop(ar, tb);
 445        case ATH10K_TM_CMD_WMI:
 446                return ath10k_tm_cmd_wmi(ar, tb);
 447        default:
 448                return -EOPNOTSUPP;
 449        }
 450}
 451
 452void ath10k_testmode_destroy(struct ath10k *ar)
 453{
 454        mutex_lock(&ar->conf_mutex);
 455
 456        if (ar->state != ATH10K_STATE_UTF) {
 457                /* utf firmware is not running, nothing to do */
 458                goto out;
 459        }
 460
 461        __ath10k_tm_cmd_utf_stop(ar);
 462
 463out:
 464        mutex_unlock(&ar->conf_mutex);
 465}
 466