linux/drivers/net/wireless/iwlwifi/dvm/testmode.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * This file is provided under a dual BSD/GPLv2 license.  When using or
   4 * redistributing this file, you may do so under either license.
   5 *
   6 * GPL LICENSE SUMMARY
   7 *
   8 * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of version 2 of the GNU General Public License as
  12 * published by the Free Software Foundation.
  13 *
  14 * This program is distributed in the hope that it will be useful, but
  15 * WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU General Public License
  20 * along with this program; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
  22 * USA
  23 *
  24 * The full GNU General Public License is included in this distribution
  25 * in the file called LICENSE.GPL.
  26 *
  27 * Contact Information:
  28 *  Intel Linux Wireless <ilw@linux.intel.com>
  29 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  30 *
  31 * BSD LICENSE
  32 *
  33 * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
  34 * All rights reserved.
  35 *
  36 * Redistribution and use in source and binary forms, with or without
  37 * modification, are permitted provided that the following conditions
  38 * are met:
  39 *
  40 *  * Redistributions of source code must retain the above copyright
  41 *    notice, this list of conditions and the following disclaimer.
  42 *  * Redistributions in binary form must reproduce the above copyright
  43 *    notice, this list of conditions and the following disclaimer in
  44 *    the documentation and/or other materials provided with the
  45 *    distribution.
  46 *  * Neither the name Intel Corporation nor the names of its
  47 *    contributors may be used to endorse or promote products derived
  48 *    from this software without specific prior written permission.
  49 *
  50 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  51 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  52 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  53 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  54 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  55 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  56 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  57 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  58 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  59 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  60 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  61 *
  62 *****************************************************************************/
  63
  64#include <linux/init.h>
  65#include <linux/kernel.h>
  66#include <linux/module.h>
  67#include <linux/dma-mapping.h>
  68#include <net/net_namespace.h>
  69#include <linux/netdevice.h>
  70#include <net/cfg80211.h>
  71#include <net/mac80211.h>
  72#include <net/netlink.h>
  73
  74#include "iwl-debug.h"
  75#include "iwl-trans.h"
  76#include "dev.h"
  77#include "agn.h"
  78#include "iwl-test.h"
  79#include "iwl-testmode.h"
  80
  81static int iwl_testmode_send_cmd(struct iwl_op_mode *op_mode,
  82                                 struct iwl_host_cmd *cmd)
  83{
  84        struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
  85        return iwl_dvm_send_cmd(priv, cmd);
  86}
  87
  88static bool iwl_testmode_valid_hw_addr(u32 addr)
  89{
  90        if (iwlagn_hw_valid_rtc_data_addr(addr))
  91                return true;
  92
  93        if (IWLAGN_RTC_INST_LOWER_BOUND <= addr &&
  94            addr < IWLAGN_RTC_INST_UPPER_BOUND)
  95                return true;
  96
  97        return false;
  98}
  99
 100static u32 iwl_testmode_get_fw_ver(struct iwl_op_mode *op_mode)
 101{
 102        struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
 103        return priv->fw->ucode_ver;
 104}
 105
 106static struct sk_buff*
 107iwl_testmode_alloc_reply(struct iwl_op_mode *op_mode, int len)
 108{
 109        struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
 110        return cfg80211_testmode_alloc_reply_skb(priv->hw->wiphy, len);
 111}
 112
 113static int iwl_testmode_reply(struct iwl_op_mode *op_mode, struct sk_buff *skb)
 114{
 115        return cfg80211_testmode_reply(skb);
 116}
 117
 118static struct sk_buff *iwl_testmode_alloc_event(struct iwl_op_mode *op_mode,
 119                                                int len)
 120{
 121        struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
 122        return cfg80211_testmode_alloc_event_skb(priv->hw->wiphy, len,
 123                                                 GFP_ATOMIC);
 124}
 125
 126static void iwl_testmode_event(struct iwl_op_mode *op_mode, struct sk_buff *skb)
 127{
 128        return cfg80211_testmode_event(skb, GFP_ATOMIC);
 129}
 130
 131static struct iwl_test_ops tst_ops = {
 132        .send_cmd = iwl_testmode_send_cmd,
 133        .valid_hw_addr = iwl_testmode_valid_hw_addr,
 134        .get_fw_ver = iwl_testmode_get_fw_ver,
 135        .alloc_reply = iwl_testmode_alloc_reply,
 136        .reply = iwl_testmode_reply,
 137        .alloc_event = iwl_testmode_alloc_event,
 138        .event = iwl_testmode_event,
 139};
 140
 141void iwl_testmode_init(struct iwl_priv *priv)
 142{
 143        iwl_test_init(&priv->tst, priv->trans, &tst_ops);
 144}
 145
 146void iwl_testmode_free(struct iwl_priv *priv)
 147{
 148        iwl_test_free(&priv->tst);
 149}
 150
 151static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv)
 152{
 153        struct iwl_notification_wait calib_wait;
 154        static const u8 calib_complete[] = {
 155                CALIBRATION_COMPLETE_NOTIFICATION
 156        };
 157        int ret;
 158
 159        iwl_init_notification_wait(&priv->notif_wait, &calib_wait,
 160                                   calib_complete, ARRAY_SIZE(calib_complete),
 161                                   NULL, NULL);
 162        ret = iwl_init_alive_start(priv);
 163        if (ret) {
 164                IWL_ERR(priv, "Fail init calibration: %d\n", ret);
 165                goto cfg_init_calib_error;
 166        }
 167
 168        ret = iwl_wait_notification(&priv->notif_wait, &calib_wait, 2 * HZ);
 169        if (ret)
 170                IWL_ERR(priv, "Error detecting"
 171                        " CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret);
 172        return ret;
 173
 174cfg_init_calib_error:
 175        iwl_remove_notification(&priv->notif_wait, &calib_wait);
 176        return ret;
 177}
 178
 179/*
 180 * This function handles the user application commands for driver.
 181 *
 182 * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
 183 * handlers respectively.
 184 *
 185 * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned
 186 * value of the actual command execution is replied to the user application.
 187 *
 188 * If there's any message responding to the user space, IWL_TM_ATTR_SYNC_RSP
 189 * is used for carry the message while IWL_TM_ATTR_COMMAND must set to
 190 * IWL_TM_CMD_DEV2APP_SYNC_RSP.
 191 *
 192 * @hw: ieee80211_hw object that represents the device
 193 * @tb: gnl message fields from the user space
 194 */
 195static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
 196{
 197        struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 198        struct iwl_trans *trans = priv->trans;
 199        struct sk_buff *skb;
 200        unsigned char *rsp_data_ptr = NULL;
 201        int status = 0, rsp_data_len = 0;
 202        u32 inst_size = 0, data_size = 0;
 203        const struct fw_img *img;
 204
 205        switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
 206        case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
 207                rsp_data_ptr = (unsigned char *)priv->cfg->name;
 208                rsp_data_len = strlen(priv->cfg->name);
 209                skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
 210                                                        rsp_data_len + 20);
 211                if (!skb) {
 212                        IWL_ERR(priv, "Memory allocation fail\n");
 213                        return -ENOMEM;
 214                }
 215                if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND,
 216                                IWL_TM_CMD_DEV2APP_SYNC_RSP) ||
 217                    nla_put(skb, IWL_TM_ATTR_SYNC_RSP,
 218                            rsp_data_len, rsp_data_ptr))
 219                        goto nla_put_failure;
 220                status = cfg80211_testmode_reply(skb);
 221                if (status < 0)
 222                        IWL_ERR(priv, "Error sending msg : %d\n", status);
 223                break;
 224
 225        case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
 226                status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_INIT);
 227                if (status)
 228                        IWL_ERR(priv, "Error loading init ucode: %d\n", status);
 229                break;
 230
 231        case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
 232                iwl_testmode_cfg_init_calib(priv);
 233                priv->ucode_loaded = false;
 234                iwl_trans_stop_device(trans);
 235                break;
 236
 237        case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
 238                status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR);
 239                if (status) {
 240                        IWL_ERR(priv,
 241                                "Error loading runtime ucode: %d\n", status);
 242                        break;
 243                }
 244                status = iwl_alive_start(priv);
 245                if (status)
 246                        IWL_ERR(priv,
 247                                "Error starting the device: %d\n", status);
 248                break;
 249
 250        case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW:
 251                iwl_scan_cancel_timeout(priv, 200);
 252                priv->ucode_loaded = false;
 253                iwl_trans_stop_device(trans);
 254                status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN);
 255                if (status) {
 256                        IWL_ERR(priv,
 257                                "Error loading WOWLAN ucode: %d\n", status);
 258                        break;
 259                }
 260                status = iwl_alive_start(priv);
 261                if (status)
 262                        IWL_ERR(priv,
 263                                "Error starting the device: %d\n", status);
 264                break;
 265
 266        case IWL_TM_CMD_APP2DEV_GET_EEPROM:
 267                if (priv->eeprom_blob) {
 268                        skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
 269                                priv->eeprom_blob_size + 20);
 270                        if (!skb) {
 271                                IWL_ERR(priv, "Memory allocation fail\n");
 272                                return -ENOMEM;
 273                        }
 274                        if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND,
 275                                        IWL_TM_CMD_DEV2APP_EEPROM_RSP) ||
 276                            nla_put(skb, IWL_TM_ATTR_EEPROM,
 277                                    priv->eeprom_blob_size,
 278                                    priv->eeprom_blob))
 279                                goto nla_put_failure;
 280                        status = cfg80211_testmode_reply(skb);
 281                        if (status < 0)
 282                                IWL_ERR(priv, "Error sending msg : %d\n",
 283                                        status);
 284                } else
 285                        return -ENODATA;
 286                break;
 287
 288        case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
 289                if (!tb[IWL_TM_ATTR_FIXRATE]) {
 290                        IWL_ERR(priv, "Missing fixrate setting\n");
 291                        return -ENOMSG;
 292                }
 293                priv->tm_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]);
 294                break;
 295
 296        case IWL_TM_CMD_APP2DEV_GET_FW_INFO:
 297                skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20 + 8);
 298                if (!skb) {
 299                        IWL_ERR(priv, "Memory allocation fail\n");
 300                        return -ENOMEM;
 301                }
 302                if (!priv->ucode_loaded) {
 303                        IWL_ERR(priv, "No uCode has not been loaded\n");
 304                        return -EINVAL;
 305                } else {
 306                        img = &priv->fw->img[priv->cur_ucode];
 307                        inst_size = img->sec[IWL_UCODE_SECTION_INST].len;
 308                        data_size = img->sec[IWL_UCODE_SECTION_DATA].len;
 309                }
 310                if (nla_put_u32(skb, IWL_TM_ATTR_FW_TYPE, priv->cur_ucode) ||
 311                    nla_put_u32(skb, IWL_TM_ATTR_FW_INST_SIZE, inst_size) ||
 312                    nla_put_u32(skb, IWL_TM_ATTR_FW_DATA_SIZE, data_size))
 313                        goto nla_put_failure;
 314                status = cfg80211_testmode_reply(skb);
 315                if (status < 0)
 316                        IWL_ERR(priv, "Error sending msg : %d\n", status);
 317                break;
 318
 319        default:
 320                IWL_ERR(priv, "Unknown testmode driver command ID\n");
 321                return -ENOSYS;
 322        }
 323        return status;
 324
 325nla_put_failure:
 326        kfree_skb(skb);
 327        return -EMSGSIZE;
 328}
 329
 330/*
 331 * This function handles the user application switch ucode ownership.
 332 *
 333 * It retrieves the mandatory fields IWL_TM_ATTR_UCODE_OWNER and
 334 * decide who the current owner of the uCode
 335 *
 336 * If the current owner is OWNERSHIP_TM, then the only host command
 337 * can deliver to uCode is from testmode, all the other host commands
 338 * will dropped.
 339 *
 340 * default driver is the owner of uCode in normal operational mode
 341 *
 342 * @hw: ieee80211_hw object that represents the device
 343 * @tb: gnl message fields from the user space
 344 */
 345static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb)
 346{
 347        struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 348        u8 owner;
 349
 350        if (!tb[IWL_TM_ATTR_UCODE_OWNER]) {
 351                IWL_ERR(priv, "Missing ucode owner\n");
 352                return -ENOMSG;
 353        }
 354
 355        owner = nla_get_u8(tb[IWL_TM_ATTR_UCODE_OWNER]);
 356        if (owner == IWL_OWNERSHIP_DRIVER) {
 357                priv->ucode_owner = owner;
 358                iwl_test_enable_notifications(&priv->tst, false);
 359        } else if (owner == IWL_OWNERSHIP_TM) {
 360                priv->ucode_owner = owner;
 361                iwl_test_enable_notifications(&priv->tst, true);
 362        } else {
 363                IWL_ERR(priv, "Invalid owner\n");
 364                return -EINVAL;
 365        }
 366        return 0;
 367}
 368
 369/* The testmode gnl message handler that takes the gnl message from the
 370 * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then
 371 * invoke the corresponding handlers.
 372 *
 373 * This function is invoked when there is user space application sending
 374 * gnl message through the testmode tunnel NL80211_CMD_TESTMODE regulated
 375 * by nl80211.
 376 *
 377 * It retrieves the mandatory field, IWL_TM_ATTR_COMMAND, before
 378 * dispatching it to the corresponding handler.
 379 *
 380 * If IWL_TM_ATTR_COMMAND is missing, -ENOMSG is replied to user application;
 381 * -ENOSYS is replied to the user application if the command is unknown;
 382 * Otherwise, the command is dispatched to the respective handler.
 383 *
 384 * @hw: ieee80211_hw object that represents the device
 385 * @data: pointer to user space message
 386 * @len: length in byte of @data
 387 */
 388int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
 389{
 390        struct nlattr *tb[IWL_TM_ATTR_MAX];
 391        struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 392        int result;
 393
 394        result = iwl_test_parse(&priv->tst, tb, data, len);
 395        if (result)
 396                return result;
 397
 398        /* in case multiple accesses to the device happens */
 399        mutex_lock(&priv->mutex);
 400        switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
 401        case IWL_TM_CMD_APP2DEV_UCODE:
 402        case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32:
 403        case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32:
 404        case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8:
 405        case IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
 406        case IWL_TM_CMD_APP2DEV_END_TRACE:
 407        case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ:
 408        case IWL_TM_CMD_APP2DEV_NOTIFICATIONS:
 409        case IWL_TM_CMD_APP2DEV_GET_FW_VERSION:
 410        case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID:
 411        case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE:
 412                result = iwl_test_handle_cmd(&priv->tst, tb);
 413                break;
 414
 415        case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
 416        case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
 417        case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
 418        case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
 419        case IWL_TM_CMD_APP2DEV_GET_EEPROM:
 420        case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
 421        case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW:
 422        case IWL_TM_CMD_APP2DEV_GET_FW_INFO:
 423                IWL_DEBUG_INFO(priv, "testmode cmd to driver\n");
 424                result = iwl_testmode_driver(hw, tb);
 425                break;
 426
 427        case IWL_TM_CMD_APP2DEV_OWNERSHIP:
 428                IWL_DEBUG_INFO(priv, "testmode change uCode ownership\n");
 429                result = iwl_testmode_ownership(hw, tb);
 430                break;
 431
 432        default:
 433                IWL_ERR(priv, "Unknown testmode command\n");
 434                result = -ENOSYS;
 435                break;
 436        }
 437        mutex_unlock(&priv->mutex);
 438
 439        if (result)
 440                IWL_ERR(priv, "Test cmd failed result=%d\n", result);
 441        return result;
 442}
 443
 444int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
 445                      struct netlink_callback *cb,
 446                      void *data, int len)
 447{
 448        struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 449        int result;
 450        u32 cmd;
 451
 452        if (cb->args[3]) {
 453                /* offset by 1 since commands start at 0 */
 454                cmd = cb->args[3] - 1;
 455        } else {
 456                struct nlattr *tb[IWL_TM_ATTR_MAX];
 457
 458                result = iwl_test_parse(&priv->tst, tb, data, len);
 459                if (result)
 460                        return result;
 461
 462                cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]);
 463                cb->args[3] = cmd + 1;
 464        }
 465
 466        /* in case multiple accesses to the device happens */
 467        mutex_lock(&priv->mutex);
 468        result = iwl_test_dump(&priv->tst, cmd, skb, cb);
 469        mutex_unlock(&priv->mutex);
 470        return result;
 471}
 472