iwlwifi: move iwl_set_rate to iwl-agn-rxon.c
[deliverable/linux.git] / drivers / net / wireless / iwlwifi / iwl-core.c
CommitLineData
df48c323 1/******************************************************************************
df48c323
TW
2 *
3 * GPL LICENSE SUMMARY
4 *
4e318262 5 * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
df48c323
TW
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of version 2 of the GNU General Public License as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
19 * USA
20 *
21 * The full GNU General Public License is included in this distribution
22 * in the file called LICENSE.GPL.
23 *
24 * Contact Information:
759ef89f 25 * Intel Linux Wireless <ilw@linux.intel.com>
df48c323
TW
26 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
27 *****************************************************************************/
28
29#include <linux/kernel.h>
30#include <linux/module.h>
d43c36dc 31#include <linux/sched.h>
5a0e3ad6 32#include <linux/slab.h>
1d0a082d 33#include <net/mac80211.h>
df48c323 34
6bc913bd 35#include "iwl-eeprom.h"
19335774 36#include "iwl-debug.h"
df48c323 37#include "iwl-core.h"
b661c819 38#include "iwl-io.h"
5da4b55f 39#include "iwl-power.h"
48f20d35 40#include "iwl-shared.h"
9d143e9a 41#include "iwl-agn.h"
bdfbf092 42#include "iwl-trans.h"
df48c323 43
57bd1bea 44const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
57bd1bea 45
79d07325
WYG
46void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
47{
8bd413e6
JB
48 /*
49 * MULTI-FIXME
ade4c649 50 * See iwlagn_mac_channel_switch.
8bd413e6
JB
51 */
52 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
53
83626404 54 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
79d07325
WYG
55 return;
56
83626404 57 if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
8bd413e6 58 ieee80211_chswitch_done(ctx->vif, is_success);
79d07325 59}
8ccde88a 60
8ccde88a 61#ifdef CONFIG_IWLWIFI_DEBUG
14991a9d
EG
62void iwl_print_rx_config_cmd(struct iwl_priv *priv,
63 enum iwl_rxon_context_id ctxid)
8ccde88a 64{
522376d2 65 struct iwl_rxon_context *ctx = &priv->contexts[ctxid];
246ed355 66 struct iwl_rxon_cmd *rxon = &ctx->staging;
8ccde88a 67
e1623446 68 IWL_DEBUG_RADIO(priv, "RX CONFIG:\n");
3d816c77 69 iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
e1623446
TW
70 IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
71 IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
72 IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n",
8ccde88a 73 le32_to_cpu(rxon->filter_flags));
e1623446
TW
74 IWL_DEBUG_RADIO(priv, "u8 dev_type: 0x%x\n", rxon->dev_type);
75 IWL_DEBUG_RADIO(priv, "u8 ofdm_basic_rates: 0x%02x\n",
8ccde88a 76 rxon->ofdm_basic_rates);
e1623446
TW
77 IWL_DEBUG_RADIO(priv, "u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates);
78 IWL_DEBUG_RADIO(priv, "u8[6] node_addr: %pM\n", rxon->node_addr);
79 IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr);
80 IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
8ccde88a 81}
6686d17e 82#endif
e649437f 83
b7e21bf0 84void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
8ccde88a 85{
491bc292
WYG
86 unsigned int reload_msec;
87 unsigned long reload_jiffies;
88
3e6895c5 89#ifdef CONFIG_IWLWIFI_DEBUG
a8bceb39 90 if (iwl_have_debug_level(IWL_DL_FW_ERRORS))
3e6895c5
EG
91 iwl_print_rx_config_cmd(priv, IWL_RXON_CTX_BSS);
92#endif
93
8f7ffbe2
DS
94 /* uCode is no longer loaded. */
95 priv->ucode_loaded = false;
96
8ccde88a 97 /* Set the FW error flag -- cleared on iwl_down */
17acd0b6 98 set_bit(STATUS_FW_ERROR, &priv->status);
8ccde88a
SO
99
100 /* Cancel currently queued command. */
63013ae3 101 clear_bit(STATUS_HCMD_ACTIVE, &priv->shrd->status);
8ccde88a 102
4bd14dd5 103 iwl_abort_notification_waits(&priv->notif_wait);
e74fe233 104
e649437f
JB
105 /* Keep the restart process from trying to send host
106 * commands by clearing the ready bit */
83626404 107 clear_bit(STATUS_READY, &priv->status);
e649437f 108
69a10b29 109 wake_up(&trans(priv)->wait_command_queue);
e649437f
JB
110
111 if (!ondemand) {
112 /*
113 * If firmware keep reloading, then it indicate something
114 * serious wrong and firmware having problem to recover
115 * from it. Instead of keep trying which will fill the syslog
116 * and hang the system, let's just stop it
117 */
118 reload_jiffies = jiffies;
119 reload_msec = jiffies_to_msecs((long) reload_jiffies -
120 (long) priv->reload_jiffies);
121 priv->reload_jiffies = reload_jiffies;
122 if (reload_msec <= IWL_MIN_RELOAD_DURATION) {
123 priv->reload_count++;
124 if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) {
125 IWL_ERR(priv, "BUG_ON, Stop restarting\n");
126 return;
127 }
128 } else
129 priv->reload_count = 0;
130 }
131
83626404 132 if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
9d143e9a 133 if (iwlagn_mod_params.restart_fw) {
9ca06f0a 134 IWL_DEBUG_FW_ERRORS(priv,
e649437f 135 "Restarting adapter due to uCode error.\n");
1ee158d8 136 queue_work(priv->workqueue, &priv->restart);
e649437f 137 } else
9ca06f0a 138 IWL_DEBUG_FW_ERRORS(priv,
e649437f
JB
139 "Detected FW error, but not restarting\n");
140 }
141}
142
630fe9b6
TW
143int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
144{
a25a66ac
SG
145 int ret;
146 s8 prev_tx_power;
f844a709
SG
147 bool defer;
148 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
a25a66ac 149
b1eea297 150 lockdep_assert_held(&priv->mutex);
a25a66ac
SG
151
152 if (priv->tx_power_user_lmt == tx_power && !force)
153 return 0;
154
b744cb79
WYG
155 if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) {
156 IWL_WARN(priv,
157 "Requested user TXPOWER %d below lower limit %d.\n",
daf518de 158 tx_power,
b744cb79 159 IWLAGN_TX_POWER_TARGET_POWER_MIN);
630fe9b6
TW
160 return -EINVAL;
161 }
162
dc1b0973 163 if (tx_power > priv->tx_power_device_lmt) {
08f2d58d
WYG
164 IWL_WARN(priv,
165 "Requested user TXPOWER %d above upper limit %d.\n",
dc1b0973 166 tx_power, priv->tx_power_device_lmt);
630fe9b6
TW
167 return -EINVAL;
168 }
169
83626404 170 if (!iwl_is_ready_rf(priv))
a25a66ac 171 return -EIO;
630fe9b6 172
f844a709
SG
173 /* scan complete and commit_rxon use tx_power_next value,
174 * it always need to be updated for newest request */
a25a66ac 175 priv->tx_power_next = tx_power;
f844a709
SG
176
177 /* do not set tx power when scanning or channel changing */
83626404 178 defer = test_bit(STATUS_SCANNING, &priv->status) ||
f844a709
SG
179 memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging));
180 if (defer && !force) {
181 IWL_DEBUG_INFO(priv, "Deferring tx power set\n");
a25a66ac 182 return 0;
5eadd94b 183 }
630fe9b6 184
a25a66ac
SG
185 prev_tx_power = priv->tx_power_user_lmt;
186 priv->tx_power_user_lmt = tx_power;
187
5beaaf37 188 ret = iwlagn_send_tx_power(priv);
a25a66ac
SG
189
190 /* if fail to set tx_power, restore the orig. tx power */
191 if (ret) {
192 priv->tx_power_user_lmt = prev_tx_power;
193 priv->tx_power_next = prev_tx_power;
194 }
630fe9b6
TW
195 return ret;
196}
630fe9b6 197
65b52bde 198void iwl_send_bt_config(struct iwl_priv *priv)
17f841cd
SO
199{
200 struct iwl_bt_cmd bt_cmd = {
456d0f76
WYG
201 .lead_time = BT_LEAD_TIME_DEF,
202 .max_kill = BT_MAX_KILL_DEF,
17f841cd
SO
203 .kill_ack_mask = 0,
204 .kill_cts_mask = 0,
205 };
206
b60eec9b 207 if (!iwlagn_mod_params.bt_coex_active)
06702a73
WYG
208 bt_cmd.flags = BT_COEX_DISABLE;
209 else
210 bt_cmd.flags = BT_COEX_ENABLE;
211
f21dd005 212 priv->bt_enable_flag = bt_cmd.flags;
06702a73
WYG
213 IWL_DEBUG_INFO(priv, "BT coex %s\n",
214 (bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active");
215
e10a0533 216 if (iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
e419d62d 217 CMD_SYNC, sizeof(struct iwl_bt_cmd), &bt_cmd))
65b52bde 218 IWL_ERR(priv, "failed to send BT Coex Config\n");
17f841cd 219}
17f841cd 220
ef8d5529 221int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
49ea8596 222{
ef8d5529
WYG
223 struct iwl_statistics_cmd statistics_cmd = {
224 .configuration_flags =
225 clear ? IWL_STATS_CONF_CLEAR_STATS : 0,
49ea8596 226 };
ef8d5529
WYG
227
228 if (flags & CMD_ASYNC)
e10a0533 229 return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
e419d62d 230 CMD_ASYNC,
ef8d5529 231 sizeof(struct iwl_statistics_cmd),
e419d62d 232 &statistics_cmd);
ef8d5529 233 else
e10a0533 234 return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
e419d62d 235 CMD_SYNC,
ef8d5529
WYG
236 sizeof(struct iwl_statistics_cmd),
237 &statistics_cmd);
49ea8596 238}
7e8c519e 239
488829f1 240
727882d6 241
d8052319 242
20594eb0
WYG
243#ifdef CONFIG_IWLWIFI_DEBUGFS
244
245#define IWL_TRAFFIC_DUMP_SIZE (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES)
246
247void iwl_reset_traffic_log(struct iwl_priv *priv)
248{
249 priv->tx_traffic_idx = 0;
250 priv->rx_traffic_idx = 0;
251 if (priv->tx_traffic)
252 memset(priv->tx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE);
253 if (priv->rx_traffic)
254 memset(priv->rx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE);
255}
256
257int iwl_alloc_traffic_mem(struct iwl_priv *priv)
258{
259 u32 traffic_size = IWL_TRAFFIC_DUMP_SIZE;
260
a8bceb39 261 if (iwl_have_debug_level(IWL_DL_TX)) {
20594eb0
WYG
262 if (!priv->tx_traffic) {
263 priv->tx_traffic =
264 kzalloc(traffic_size, GFP_KERNEL);
265 if (!priv->tx_traffic)
266 return -ENOMEM;
267 }
268 }
a8bceb39 269 if (iwl_have_debug_level(IWL_DL_RX)) {
20594eb0
WYG
270 if (!priv->rx_traffic) {
271 priv->rx_traffic =
272 kzalloc(traffic_size, GFP_KERNEL);
273 if (!priv->rx_traffic)
274 return -ENOMEM;
275 }
276 }
277 iwl_reset_traffic_log(priv);
278 return 0;
279}
20594eb0
WYG
280
281void iwl_free_traffic_mem(struct iwl_priv *priv)
282{
283 kfree(priv->tx_traffic);
284 priv->tx_traffic = NULL;
285
286 kfree(priv->rx_traffic);
287 priv->rx_traffic = NULL;
288}
20594eb0
WYG
289
290void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv,
291 u16 length, struct ieee80211_hdr *header)
292{
293 __le16 fc;
294 u16 len;
295
a8bceb39 296 if (likely(!iwl_have_debug_level(IWL_DL_TX)))
20594eb0
WYG
297 return;
298
299 if (!priv->tx_traffic)
300 return;
301
302 fc = header->frame_control;
303 if (ieee80211_is_data(fc)) {
304 len = (length > IWL_TRAFFIC_ENTRY_SIZE)
305 ? IWL_TRAFFIC_ENTRY_SIZE : length;
306 memcpy((priv->tx_traffic +
307 (priv->tx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)),
308 header, len);
309 priv->tx_traffic_idx =
310 (priv->tx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES;
311 }
312}
20594eb0
WYG
313
314void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv,
315 u16 length, struct ieee80211_hdr *header)
316{
317 __le16 fc;
318 u16 len;
319
a8bceb39 320 if (likely(!iwl_have_debug_level(IWL_DL_RX)))
20594eb0
WYG
321 return;
322
323 if (!priv->rx_traffic)
324 return;
325
326 fc = header->frame_control;
327 if (ieee80211_is_data(fc)) {
328 len = (length > IWL_TRAFFIC_ENTRY_SIZE)
329 ? IWL_TRAFFIC_ENTRY_SIZE : length;
330 memcpy((priv->rx_traffic +
331 (priv->rx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)),
332 header, len);
333 priv->rx_traffic_idx =
334 (priv->rx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES;
335 }
336}
22fdf3c9
WYG
337
338const char *get_mgmt_string(int cmd)
339{
340 switch (cmd) {
341 IWL_CMD(MANAGEMENT_ASSOC_REQ);
342 IWL_CMD(MANAGEMENT_ASSOC_RESP);
343 IWL_CMD(MANAGEMENT_REASSOC_REQ);
344 IWL_CMD(MANAGEMENT_REASSOC_RESP);
345 IWL_CMD(MANAGEMENT_PROBE_REQ);
346 IWL_CMD(MANAGEMENT_PROBE_RESP);
347 IWL_CMD(MANAGEMENT_BEACON);
348 IWL_CMD(MANAGEMENT_ATIM);
349 IWL_CMD(MANAGEMENT_DISASSOC);
350 IWL_CMD(MANAGEMENT_AUTH);
351 IWL_CMD(MANAGEMENT_DEAUTH);
352 IWL_CMD(MANAGEMENT_ACTION);
353 default:
354 return "UNKNOWN";
355
356 }
357}
358
359const char *get_ctrl_string(int cmd)
360{
361 switch (cmd) {
362 IWL_CMD(CONTROL_BACK_REQ);
363 IWL_CMD(CONTROL_BACK);
364 IWL_CMD(CONTROL_PSPOLL);
365 IWL_CMD(CONTROL_RTS);
366 IWL_CMD(CONTROL_CTS);
367 IWL_CMD(CONTROL_ACK);
368 IWL_CMD(CONTROL_CFEND);
369 IWL_CMD(CONTROL_CFENDACK);
370 default:
371 return "UNKNOWN";
372
373 }
374}
375
7163b8a4 376void iwl_clear_traffic_stats(struct iwl_priv *priv)
22fdf3c9
WYG
377{
378 memset(&priv->tx_stats, 0, sizeof(struct traffic_stats));
22fdf3c9
WYG
379 memset(&priv->rx_stats, 0, sizeof(struct traffic_stats));
380}
381
382/*
383 * if CONFIG_IWLWIFI_DEBUGFS defined, iwl_update_stats function will
384 * record all the MGMT, CTRL and DATA pkt for both TX and Rx pass.
385 * Use debugFs to display the rx/rx_statistics
386 * if CONFIG_IWLWIFI_DEBUGFS not being defined, then no MGMT and CTRL
387 * information will be recorded, but DATA pkt still will be recorded
388 * for the reason of iwl_led.c need to control the led blinking based on
389 * number of tx and rx data.
390 *
391 */
392void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len)
393{
394 struct traffic_stats *stats;
395
396 if (is_tx)
397 stats = &priv->tx_stats;
398 else
399 stats = &priv->rx_stats;
400
401 if (ieee80211_is_mgmt(fc)) {
402 switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
403 case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
404 stats->mgmt[MANAGEMENT_ASSOC_REQ]++;
405 break;
406 case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
407 stats->mgmt[MANAGEMENT_ASSOC_RESP]++;
408 break;
409 case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
410 stats->mgmt[MANAGEMENT_REASSOC_REQ]++;
411 break;
412 case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
413 stats->mgmt[MANAGEMENT_REASSOC_RESP]++;
414 break;
415 case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
416 stats->mgmt[MANAGEMENT_PROBE_REQ]++;
417 break;
418 case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
419 stats->mgmt[MANAGEMENT_PROBE_RESP]++;
420 break;
421 case cpu_to_le16(IEEE80211_STYPE_BEACON):
422 stats->mgmt[MANAGEMENT_BEACON]++;
423 break;
424 case cpu_to_le16(IEEE80211_STYPE_ATIM):
425 stats->mgmt[MANAGEMENT_ATIM]++;
426 break;
427 case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
428 stats->mgmt[MANAGEMENT_DISASSOC]++;
429 break;
430 case cpu_to_le16(IEEE80211_STYPE_AUTH):
431 stats->mgmt[MANAGEMENT_AUTH]++;
432 break;
433 case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
434 stats->mgmt[MANAGEMENT_DEAUTH]++;
435 break;
436 case cpu_to_le16(IEEE80211_STYPE_ACTION):
437 stats->mgmt[MANAGEMENT_ACTION]++;
438 break;
439 }
440 } else if (ieee80211_is_ctl(fc)) {
441 switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
442 case cpu_to_le16(IEEE80211_STYPE_BACK_REQ):
443 stats->ctrl[CONTROL_BACK_REQ]++;
444 break;
445 case cpu_to_le16(IEEE80211_STYPE_BACK):
446 stats->ctrl[CONTROL_BACK]++;
447 break;
448 case cpu_to_le16(IEEE80211_STYPE_PSPOLL):
449 stats->ctrl[CONTROL_PSPOLL]++;
450 break;
451 case cpu_to_le16(IEEE80211_STYPE_RTS):
452 stats->ctrl[CONTROL_RTS]++;
453 break;
454 case cpu_to_le16(IEEE80211_STYPE_CTS):
455 stats->ctrl[CONTROL_CTS]++;
456 break;
457 case cpu_to_le16(IEEE80211_STYPE_ACK):
458 stats->ctrl[CONTROL_ACK]++;
459 break;
460 case cpu_to_le16(IEEE80211_STYPE_CFEND):
461 stats->ctrl[CONTROL_CFEND]++;
462 break;
463 case cpu_to_le16(IEEE80211_STYPE_CFENDACK):
464 stats->ctrl[CONTROL_CFENDACK]++;
465 break;
466 }
467 } else {
468 /* data */
469 stats->data_cnt++;
470 stats->data_bytes += len;
471 }
472}
20594eb0
WYG
473#endif
474
48dffd39 475int iwl_force_rf_reset(struct iwl_priv *priv, bool external)
afbdd69a 476{
48dffd39
JB
477 struct iwl_rf_reset *rf_reset;
478
83626404 479 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
48dffd39 480 return -EAGAIN;
afbdd69a 481
246ed355 482 if (!iwl_is_any_associated(priv)) {
afbdd69a 483 IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n");
48dffd39 484 return -ENOLINK;
afbdd69a 485 }
48dffd39
JB
486
487 rf_reset = &priv->rf_reset;
488 rf_reset->reset_request_count++;
489 if (!external && rf_reset->last_reset_jiffies &&
490 time_after(rf_reset->last_reset_jiffies +
491 IWL_DELAY_NEXT_FORCE_RF_RESET, jiffies)) {
492 IWL_DEBUG_INFO(priv, "RF reset rejected\n");
493 rf_reset->reset_reject_count++;
494 return -EAGAIN;
495 }
496 rf_reset->reset_success_count++;
497 rf_reset->last_reset_jiffies = jiffies;
498
afbdd69a
WYG
499 /*
500 * There is no easy and better way to force reset the radio,
501 * the only known method is switching channel which will force to
502 * reset and tune the radio.
503 * Use internal short scan (single channel) operation to should
504 * achieve this objective.
505 * Driver should reset the radio when number of consecutive missed
506 * beacon, or any other uCode error condition detected.
507 */
508 IWL_DEBUG_INFO(priv, "perform radio reset.\n");
509 iwl_internal_short_hw_scan(priv);
a93e7973
WYG
510 return 0;
511}
b74e31a9 512
d4daaea6 513
317d09f7
WYG
514int iwl_cmd_echo_test(struct iwl_priv *priv)
515{
7e4005cc 516 int ret;
317d09f7
WYG
517 struct iwl_host_cmd cmd = {
518 .id = REPLY_ECHO,
89db3b97 519 .len = { 0 },
317d09f7
WYG
520 .flags = CMD_SYNC,
521 };
522
e10a0533 523 ret = iwl_dvm_send_cmd(priv, &cmd);
7e4005cc
WYG
524 if (ret)
525 IWL_ERR(priv, "echo testing fail: 0X%x\n", ret);
526 else
527 IWL_DEBUG_INFO(priv, "echo testing pass\n");
528 return ret;
317d09f7 529}
This page took 0.728834 seconds and 5 git commands to generate.