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
  27#include "testmode_i.h"
  28
  29static const struct nla_policy ath10k_tm_policy[ATH10K_TM_ATTR_MAX + 1] = {
  30        [ATH10K_TM_ATTR_CMD]            = { .type = NLA_U32 },
  31        [ATH10K_TM_ATTR_DATA]           = { .type = NLA_BINARY,
  32                                            .len = ATH10K_TM_DATA_MAX_LEN },
  33        [ATH10K_TM_ATTR_WMI_CMDID]      = { .type = NLA_U32 },
  34        [ATH10K_TM_ATTR_VERSION_MAJOR]  = { .type = NLA_U32 },
  35        [ATH10K_TM_ATTR_VERSION_MINOR]  = { .type = NLA_U32 },
  36};
  37
  38/* Returns true if callee consumes the skb and the skb should be discarded.
  39 * Returns false if skb is not used. Does not sleep.
  40 */
  41bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb)
  42{
  43        struct sk_buff *nl_skb;
  44        bool consumed;
  45        int ret;
  46
  47        ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
  48                   "testmode event wmi cmd_id %d skb %p skb->len %d\n",
  49                   cmd_id, skb, skb->len);
  50
  51        ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", skb->data, skb->len);
  52
  53        spin_lock_bh(&ar->data_lock);
  54
  55        if (!ar->testmode.utf_monitor) {
  56                consumed = false;
  57                goto out;
  58        }
  59
  60        /* Only testmode.c should be handling events from utf firmware,
  61         * otherwise all sort of problems will arise as mac80211 operations
  62         * are not initialised.
  63         */
  64        consumed = true;
  65
  66        nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy,
  67                                                   2 * sizeof(u32) + skb->len,
  68                                                   GFP_ATOMIC);
  69        if (!nl_skb) {
  70                ath10k_warn(ar,
  71                            "failed to allocate skb for testmode wmi event\n");
  72                goto out;
  73        }
  74
  75        ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_CMD, ATH10K_TM_CMD_WMI);
  76        if (ret) {
  77                ath10k_warn(ar,
  78                            "failed to to put testmode wmi event cmd attribute: %d\n",
  79                            ret);
  80                kfree_skb(nl_skb);
  81                goto out;
  82        }
  83
  84        ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_WMI_CMDID, cmd_id);
  85        if (ret) {
  86                ath10k_warn(ar,
  87                            "failed to to put testmode wmi even cmd_id: %d\n",
  88                            ret);
  89                kfree_skb(nl_skb);
  90                goto out;
  91        }
  92
  93        ret = nla_put(nl_skb, ATH10K_TM_ATTR_DATA, skb->len, skb->data);
  94        if (ret) {
  95                ath10k_warn(ar,
  96                            "failed to copy skb to testmode wmi event: %d\n",
  97                            ret);
  98                kfree_skb(nl_skb);
  99                goto out;
 100        }
 101
 102        cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
 103
 104out:
 105        spin_unlock_bh(&ar->data_lock);
 106
 107        return consumed;
 108}
 109
 110static int ath10k_tm_cmd_get_version(struct ath10k *ar, struct nlattr *tb[])
 111{
 112        struct sk_buff *skb;
 113        int ret;
 114
 115        ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
 116                   "testmode cmd get version_major %d version_minor %d\n",
 117                   ATH10K_TESTMODE_VERSION_MAJOR,
 118                   ATH10K_TESTMODE_VERSION_MINOR);
 119
 120        skb = cfg80211_testmode_alloc_reply_skb(ar->hw->wiphy,
 121                                                nla_total_size(sizeof(u32)));
 122        if (!skb)
 123                return -ENOMEM;
 124
 125        ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MAJOR,
 126                          ATH10K_TESTMODE_VERSION_MAJOR);
 127        if (ret) {
 128                kfree_skb(skb);
 129                return ret;
 130        }
 131
 132        ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MINOR,
 133                          ATH10K_TESTMODE_VERSION_MINOR);
 134        if (ret) {
 135                kfree_skb(skb);
 136                return ret;
 137        }
 138
 139        return cfg80211_testmode_reply(skb);
 140}
 141
 142static int ath10k_tm_fetch_utf_firmware_api_2(struct ath10k *ar)
 143{
 144        size_t len, magic_len, ie_len;
 145        struct ath10k_fw_ie *hdr;
 146        char filename[100];
 147        __le32 *version;
 148        const u8 *data;
 149        int ie_id, ret;
 150
 151        snprintf(filename, sizeof(filename), "%s/%s",
 152                 ar->hw_params.fw.dir, ATH10K_FW_UTF_API2_FILE);
 153
 154        /* load utf firmware image */
 155        ret = request_firmware(&ar->testmode.utf, filename, ar->dev);
 156        if (ret) {
 157                ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n",
 158                            filename, ret);
 159                return ret;
 160        }
 161
 162        data = ar->testmode.utf->data;
 163        len = ar->testmode.utf->size;
 164
 165        /* FIXME: call release_firmware() in error cases */
 166
 167        /* magic also includes the null byte, check that as well */
 168        magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1;
 169
 170        if (len < magic_len) {
 171                ath10k_err(ar, "utf firmware file is too small to contain magic\n");
 172                ret = -EINVAL;
 173                goto err;
 174        }
 175
 176        if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) {
 177                ath10k_err(ar, "invalid firmware magic\n");
 178                ret = -EINVAL;
 179                goto err;
 180        }
 181
 182        /* jump over the padding */
 183        magic_len = ALIGN(magic_len, 4);
 184
 185        len -= magic_len;
 186        data += magic_len;
 187
 188        /* loop elements */
 189        while (len > sizeof(struct ath10k_fw_ie)) {
 190                hdr = (struct ath10k_fw_ie *)data;
 191
 192                ie_id = le32_to_cpu(hdr->id);
 193                ie_len = le32_to_cpu(hdr->len);
 194
 195                len -= sizeof(*hdr);
 196                data += sizeof(*hdr);
 197
 198                if (len < ie_len) {
 199                        ath10k_err(ar, "invalid length for FW IE %d (%zu < %zu)\n",
 200                                   ie_id, len, ie_len);
 201                        ret = -EINVAL;
 202                        goto err;
 203                }
 204
 205                switch (ie_id) {
 206                case ATH10K_FW_IE_FW_VERSION:
 207                        if (ie_len > sizeof(ar->testmode.utf_version) - 1)
 208                                break;
 209
 210                        memcpy(ar->testmode.utf_version, data, ie_len);
 211                        ar->testmode.utf_version[ie_len] = '\0';
 212
 213                        ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
 214                                   "testmode found fw utf version %s\n",
 215                                   ar->testmode.utf_version);
 216                        break;
 217                case ATH10K_FW_IE_TIMESTAMP:
 218                        /* ignore timestamp, but don't warn about it either */
 219                        break;
 220                case ATH10K_FW_IE_FW_IMAGE:
 221                        ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
 222                                   "testmode found fw image ie (%zd B)\n",
 223                                   ie_len);
 224
 225                        ar->testmode.utf_firmware_data = data;
 226                        ar->testmode.utf_firmware_len = ie_len;
 227                        break;
 228                case ATH10K_FW_IE_WMI_OP_VERSION:
 229                        if (ie_len != sizeof(u32))
 230                                break;
 231                        version = (__le32 *)data;
 232                        ar->testmode.op_version = le32_to_cpup(version);
 233                        ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode found fw ie wmi op version %d\n",
 234                                   ar->testmode.op_version);
 235                        break;
 236                default:
 237                        ath10k_warn(ar, "Unknown testmode FW IE: %u\n",
 238                                    le32_to_cpu(hdr->id));
 239                        break;
 240                }
 241                /* jump over the padding */
 242                ie_len = ALIGN(ie_len, 4);
 243
 244                len -= ie_len;
 245                data += ie_len;
 246        }
 247
 248        if (!ar->testmode.utf_firmware_data || !ar->testmode.utf_firmware_len) {
 249                ath10k_err(ar, "No ATH10K_FW_IE_FW_IMAGE found\n");
 250                ret = -EINVAL;
 251                goto err;
 252        }
 253
 254        return 0;
 255
 256err:
 257        release_firmware(ar->testmode.utf);
 258
 259        return ret;
 260}
 261
 262static int ath10k_tm_fetch_utf_firmware_api_1(struct ath10k *ar)
 263{
 264        char filename[100];
 265        int ret;
 266
 267        snprintf(filename, sizeof(filename), "%s/%s",
 268                 ar->hw_params.fw.dir, ATH10K_FW_UTF_FILE);
 269
 270        /* load utf firmware image */
 271        ret = request_firmware(&ar->testmode.utf, filename, ar->dev);
 272        if (ret) {
 273                ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n",
 274                            filename, ret);
 275                return ret;
 276        }
 277
 278        /* We didn't find FW UTF API 1 ("utf.bin") does not advertise
 279         * firmware features. Do an ugly hack where we force the firmware
 280         * features to match with 10.1 branch so that wmi.c will use the
 281         * correct WMI interface.
 282         */
 283
 284        ar->testmode.op_version = ATH10K_FW_WMI_OP_VERSION_10_1;
 285        ar->testmode.utf_firmware_data = ar->testmode.utf->data;
 286        ar->testmode.utf_firmware_len = ar->testmode.utf->size;
 287
 288        return 0;
 289}
 290
 291static int ath10k_tm_fetch_firmware(struct ath10k *ar)
 292{
 293        int ret;
 294
 295        ret = ath10k_tm_fetch_utf_firmware_api_2(ar);
 296        if (ret == 0) {
 297                ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using fw utf api 2");
 298                return 0;
 299        }
 300
 301        ret = ath10k_tm_fetch_utf_firmware_api_1(ar);
 302        if (ret) {
 303                ath10k_err(ar, "failed to fetch utf firmware binary: %d", ret);
 304                return ret;
 305        }
 306
 307        ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using utf api 1");
 308
 309        return 0;
 310}
 311
 312static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
 313{
 314        const char *ver;
 315        int ret;
 316
 317        ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf start\n");
 318
 319        mutex_lock(&ar->conf_mutex);
 320
 321        if (ar->state == ATH10K_STATE_UTF) {
 322                ret = -EALREADY;
 323                goto err;
 324        }
 325
 326        /* start utf only when the driver is not in use  */
 327        if (ar->state != ATH10K_STATE_OFF) {
 328                ret = -EBUSY;
 329                goto err;
 330        }
 331
 332        if (WARN_ON(ar->testmode.utf != NULL)) {
 333                /* utf image is already downloaded, it shouldn't be */
 334                ret = -EEXIST;
 335                goto err;
 336        }
 337
 338        ret = ath10k_tm_fetch_firmware(ar);
 339        if (ret) {
 340                ath10k_err(ar, "failed to fetch UTF firmware: %d", ret);
 341                goto err;
 342        }
 343
 344        spin_lock_bh(&ar->data_lock);
 345        ar->testmode.utf_monitor = true;
 346        spin_unlock_bh(&ar->data_lock);
 347        BUILD_BUG_ON(sizeof(ar->fw_features) !=
 348                     sizeof(ar->testmode.orig_fw_features));
 349
 350        memcpy(ar->testmode.orig_fw_features, ar->fw_features,
 351               sizeof(ar->fw_features));
 352        ar->testmode.orig_wmi_op_version = ar->wmi.op_version;
 353        memset(ar->fw_features, 0, sizeof(ar->fw_features));
 354
 355        ar->wmi.op_version = ar->testmode.op_version;
 356
 357        ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode wmi version %d\n",
 358                   ar->wmi.op_version);
 359
 360        ret = ath10k_hif_power_up(ar);
 361        if (ret) {
 362                ath10k_err(ar, "failed to power up hif (testmode): %d\n", ret);
 363                ar->state = ATH10K_STATE_OFF;
 364                goto err_fw_features;
 365        }
 366
 367        ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_UTF);
 368        if (ret) {
 369                ath10k_err(ar, "failed to start core (testmode): %d\n", ret);
 370                ar->state = ATH10K_STATE_OFF;
 371                goto err_power_down;
 372        }
 373
 374        ar->state = ATH10K_STATE_UTF;
 375
 376        if (strlen(ar->testmode.utf_version) > 0)
 377                ver = ar->testmode.utf_version;
 378        else
 379                ver = "API 1";
 380
 381        ath10k_info(ar, "UTF firmware %s started\n", ver);
 382
 383        mutex_unlock(&ar->conf_mutex);
 384
 385        return 0;
 386
 387err_power_down:
 388        ath10k_hif_power_down(ar);
 389
 390err_fw_features:
 391        /* return the original firmware features */
 392        memcpy(ar->fw_features, ar->testmode.orig_fw_features,
 393               sizeof(ar->fw_features));
 394        ar->wmi.op_version = ar->testmode.orig_wmi_op_version;
 395
 396        release_firmware(ar->testmode.utf);
 397        ar->testmode.utf = NULL;
 398
 399err:
 400        mutex_unlock(&ar->conf_mutex);
 401
 402        return ret;
 403}
 404
 405static void __ath10k_tm_cmd_utf_stop(struct ath10k *ar)
 406{
 407        lockdep_assert_held(&ar->conf_mutex);
 408
 409        ath10k_core_stop(ar);
 410        ath10k_hif_power_down(ar);
 411
 412        spin_lock_bh(&ar->data_lock);
 413
 414        ar->testmode.utf_monitor = false;
 415
 416        spin_unlock_bh(&ar->data_lock);
 417
 418        /* return the original firmware features */
 419        memcpy(ar->fw_features, ar->testmode.orig_fw_features,
 420               sizeof(ar->fw_features));
 421        ar->wmi.op_version = ar->testmode.orig_wmi_op_version;
 422
 423        release_firmware(ar->testmode.utf);
 424        ar->testmode.utf = NULL;
 425
 426        ar->state = ATH10K_STATE_OFF;
 427}
 428
 429static int ath10k_tm_cmd_utf_stop(struct ath10k *ar, struct nlattr *tb[])
 430{
 431        int ret;
 432
 433        ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf stop\n");
 434
 435        mutex_lock(&ar->conf_mutex);
 436
 437        if (ar->state != ATH10K_STATE_UTF) {
 438                ret = -ENETDOWN;
 439                goto out;
 440        }
 441
 442        __ath10k_tm_cmd_utf_stop(ar);
 443
 444        ret = 0;
 445
 446        ath10k_info(ar, "UTF firmware stopped\n");
 447
 448out:
 449        mutex_unlock(&ar->conf_mutex);
 450        return ret;
 451}
 452
 453static int ath10k_tm_cmd_wmi(struct ath10k *ar, struct nlattr *tb[])
 454{
 455        struct sk_buff *skb;
 456        int ret, buf_len;
 457        u32 cmd_id;
 458        void *buf;
 459
 460        mutex_lock(&ar->conf_mutex);
 461
 462        if (ar->state != ATH10K_STATE_UTF) {
 463                ret = -ENETDOWN;
 464                goto out;
 465        }
 466
 467        if (!tb[ATH10K_TM_ATTR_DATA]) {
 468                ret = -EINVAL;
 469                goto out;
 470        }
 471
 472        if (!tb[ATH10K_TM_ATTR_WMI_CMDID]) {
 473                ret = -EINVAL;
 474                goto out;
 475        }
 476
 477        buf = nla_data(tb[ATH10K_TM_ATTR_DATA]);
 478        buf_len = nla_len(tb[ATH10K_TM_ATTR_DATA]);
 479        cmd_id = nla_get_u32(tb[ATH10K_TM_ATTR_WMI_CMDID]);
 480
 481        ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
 482                   "testmode cmd wmi cmd_id %d buf %p buf_len %d\n",
 483                   cmd_id, buf, buf_len);
 484
 485        ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", buf, buf_len);
 486
 487        skb = ath10k_wmi_alloc_skb(ar, buf_len);
 488        if (!skb) {
 489                ret = -ENOMEM;
 490                goto out;
 491        }
 492
 493        memcpy(skb->data, buf, buf_len);
 494
 495        ret = ath10k_wmi_cmd_send(ar, skb, cmd_id);
 496        if (ret) {
 497                ath10k_warn(ar, "failed to transmit wmi command (testmode): %d\n",
 498                            ret);
 499                goto out;
 500        }
 501
 502        ret = 0;
 503
 504out:
 505        mutex_unlock(&ar->conf_mutex);
 506        return ret;
 507}
 508
 509int ath10k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 510                  void *data, int len)
 511{
 512        struct ath10k *ar = hw->priv;
 513        struct nlattr *tb[ATH10K_TM_ATTR_MAX + 1];
 514        int ret;
 515
 516        ret = nla_parse(tb, ATH10K_TM_ATTR_MAX, data, len,
 517                        ath10k_tm_policy);
 518        if (ret)
 519                return ret;
 520
 521        if (!tb[ATH10K_TM_ATTR_CMD])
 522                return -EINVAL;
 523
 524        switch (nla_get_u32(tb[ATH10K_TM_ATTR_CMD])) {
 525        case ATH10K_TM_CMD_GET_VERSION:
 526                return ath10k_tm_cmd_get_version(ar, tb);
 527        case ATH10K_TM_CMD_UTF_START:
 528                return ath10k_tm_cmd_utf_start(ar, tb);
 529        case ATH10K_TM_CMD_UTF_STOP:
 530                return ath10k_tm_cmd_utf_stop(ar, tb);
 531        case ATH10K_TM_CMD_WMI:
 532                return ath10k_tm_cmd_wmi(ar, tb);
 533        default:
 534                return -EOPNOTSUPP;
 535        }
 536}
 537
 538void ath10k_testmode_destroy(struct ath10k *ar)
 539{
 540        mutex_lock(&ar->conf_mutex);
 541
 542        if (ar->state != ATH10K_STATE_UTF) {
 543                /* utf firmware is not running, nothing to do */
 544                goto out;
 545        }
 546
 547        __ath10k_tm_cmd_utf_stop(ar);
 548
 549out:
 550        mutex_unlock(&ar->conf_mutex);
 551}
 552