blob: df7ab332c833a38e41e5dc213d8a1221792b3cd2 [file] [log] [blame]
Cindy H. Kao4613e722011-05-06 10:40:15 -07001/******************************************************************************
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 *
Wey-Yi Guy4e318262011-12-27 11:21:32 -08008 * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
Cindy H. Kao4613e722011-05-06 10:40:15 -07009 *
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 *
Wey-Yi Guy4e318262011-12-27 11:21:32 -080033 * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
Cindy H. Kao4613e722011-05-06 10:40:15 -070034 * 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#include <linux/init.h>
64#include <linux/kernel.h>
65#include <linux/module.h>
Emmanuel Grumbach522376d2011-09-06 09:31:19 -070066#include <linux/dma-mapping.h>
Cindy H. Kao4613e722011-05-06 10:40:15 -070067#include <net/net_namespace.h>
68#include <linux/netdevice.h>
69#include <net/cfg80211.h>
70#include <net/mac80211.h>
71#include <net/netlink.h>
72
Don Fry69a679b2011-12-07 08:50:46 -080073#include "iwl-wifi.h"
Cindy H. Kao4613e722011-05-06 10:40:15 -070074#include "iwl-dev.h"
75#include "iwl-core.h"
76#include "iwl-debug.h"
Cindy H. Kao4613e722011-05-06 10:40:15 -070077#include "iwl-io.h"
78#include "iwl-agn.h"
79#include "iwl-testmode.h"
Emmanuel Grumbachbdfbf092011-07-08 08:46:16 -070080#include "iwl-trans.h"
Hsu, Kenny0bec12b2011-12-01 01:12:50 -080081#include "iwl-bus.h"
Amit Beka6fe7dd02012-01-25 09:19:24 +020082#include "iwl-fh.h"
Cindy H. Kao4613e722011-05-06 10:40:15 -070083
84/* The TLVs used in the gnl message policy between the kernel module and
85 * user space application. iwl_testmode_gnl_msg_policy is to be carried
86 * through the NL80211_CMD_TESTMODE channel regulated by nl80211.
87 * See iwl-testmode.h
88 */
89static
90struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = {
91 [IWL_TM_ATTR_COMMAND] = { .type = NLA_U32, },
92
93 [IWL_TM_ATTR_UCODE_CMD_ID] = { .type = NLA_U8, },
94 [IWL_TM_ATTR_UCODE_CMD_DATA] = { .type = NLA_UNSPEC, },
95
96 [IWL_TM_ATTR_REG_OFFSET] = { .type = NLA_U32, },
97 [IWL_TM_ATTR_REG_VALUE8] = { .type = NLA_U8, },
98 [IWL_TM_ATTR_REG_VALUE32] = { .type = NLA_U32, },
99
100 [IWL_TM_ATTR_SYNC_RSP] = { .type = NLA_UNSPEC, },
101 [IWL_TM_ATTR_UCODE_RX_PKT] = { .type = NLA_UNSPEC, },
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700102
Wey-Yi Guy4babc352011-05-03 18:05:12 -0700103 [IWL_TM_ATTR_EEPROM] = { .type = NLA_UNSPEC, },
104
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700105 [IWL_TM_ATTR_TRACE_ADDR] = { .type = NLA_UNSPEC, },
Wey-Yi Guyeb64dca2011-05-31 08:03:02 -0700106 [IWL_TM_ATTR_TRACE_DUMP] = { .type = NLA_UNSPEC, },
Wey-Yi Guy49b72102011-05-30 10:29:37 -0700107 [IWL_TM_ATTR_TRACE_SIZE] = { .type = NLA_U32, },
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700108
Wey-Yi Guy64898542011-05-03 18:05:13 -0700109 [IWL_TM_ATTR_FIXRATE] = { .type = NLA_U32, },
Wey-Yi Guy49b72102011-05-30 10:29:37 -0700110
Wey-Yi Guye98a1932011-07-08 08:46:26 -0700111 [IWL_TM_ATTR_UCODE_OWNER] = { .type = NLA_U8, },
Hsu, Kenny306713f2011-11-22 23:03:39 -0800112
113 [IWL_TM_ATTR_SRAM_ADDR] = { .type = NLA_U32, },
114 [IWL_TM_ATTR_SRAM_SIZE] = { .type = NLA_U32, },
115 [IWL_TM_ATTR_SRAM_DUMP] = { .type = NLA_UNSPEC, },
Hsu, Kennye1a38fe2011-11-28 00:55:38 -0800116
117 [IWL_TM_ATTR_FW_VERSION] = { .type = NLA_U32, },
Hsu, Kenny0bec12b2011-12-01 01:12:50 -0800118 [IWL_TM_ATTR_DEVICE_ID] = { .type = NLA_U32, },
Kenny Hsuaca9b5f2011-12-24 12:12:12 +0800119 [IWL_TM_ATTR_FW_TYPE] = { .type = NLA_U32, },
120 [IWL_TM_ATTR_FW_INST_SIZE] = { .type = NLA_U32, },
121 [IWL_TM_ATTR_FW_DATA_SIZE] = { .type = NLA_U32, },
Cindy H. Kao4613e722011-05-06 10:40:15 -0700122};
123
124/*
125 * See the struct iwl_rx_packet in iwl-commands.h for the format of the
126 * received events from the device
127 */
128static inline int get_event_length(struct iwl_rx_mem_buffer *rxb)
129{
130 struct iwl_rx_packet *pkt = rxb_addr(rxb);
131 if (pkt)
132 return le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
133 else
134 return 0;
135}
136
137
138/*
139 * This function multicasts the spontaneous messages from the device to the
140 * user space. It is invoked whenever there is a received messages
141 * from the device. This function is called within the ISR of the rx handlers
142 * in iwlagn driver.
143 *
144 * The parsing of the message content is left to the user space application,
145 * The message content is treated as unattacked raw data and is encapsulated
146 * with IWL_TM_ATTR_UCODE_RX_PKT multicasting to the user space.
147 *
148 * @priv: the instance of iwlwifi device
149 * @rxb: pointer to rx data content received by the ISR
150 *
151 * See the message policies and TLVs in iwl_testmode_gnl_msg_policy[].
152 * For the messages multicasting to the user application, the mandatory
153 * TLV fields are :
154 * IWL_TM_ATTR_COMMAND must be IWL_TM_CMD_DEV2APP_UCODE_RX_PKT
155 * IWL_TM_ATTR_UCODE_RX_PKT for carrying the message content
156 */
157
158static void iwl_testmode_ucode_rx_pkt(struct iwl_priv *priv,
159 struct iwl_rx_mem_buffer *rxb)
160{
161 struct ieee80211_hw *hw = priv->hw;
162 struct sk_buff *skb;
163 void *data;
164 int length;
165
166 data = (void *)rxb_addr(rxb);
167 length = get_event_length(rxb);
168
169 if (!data || length == 0)
170 return;
171
172 skb = cfg80211_testmode_alloc_event_skb(hw->wiphy, 20 + length,
173 GFP_ATOMIC);
174 if (skb == NULL) {
175 IWL_DEBUG_INFO(priv,
176 "Run out of memory for messages to user space ?\n");
177 return;
178 }
179 NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT);
180 NLA_PUT(skb, IWL_TM_ATTR_UCODE_RX_PKT, length, data);
181 cfg80211_testmode_event(skb, GFP_ATOMIC);
182 return;
183
184nla_put_failure:
185 kfree_skb(skb);
186 IWL_DEBUG_INFO(priv, "Ouch, overran buffer, check allocation!\n");
187}
188
189void iwl_testmode_init(struct iwl_priv *priv)
190{
191 priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700192 priv->testmode_trace.trace_enabled = false;
Hsu, Kenny306713f2011-11-22 23:03:39 -0800193 priv->testmode_sram.sram_readed = false;
194}
195
Wey-Yi Guy6b5a26f52011-11-23 07:08:22 -0800196static void iwl_sram_cleanup(struct iwl_priv *priv)
Hsu, Kenny306713f2011-11-22 23:03:39 -0800197{
198 if (priv->testmode_sram.sram_readed) {
199 kfree(priv->testmode_sram.buff_addr);
200 priv->testmode_sram.buff_addr = NULL;
201 priv->testmode_sram.buff_size = 0;
202 priv->testmode_sram.num_chunks = 0;
203 priv->testmode_sram.sram_readed = false;
204 }
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700205}
206
207static void iwl_trace_cleanup(struct iwl_priv *priv)
208{
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700209 if (priv->testmode_trace.trace_enabled) {
210 if (priv->testmode_trace.cpu_addr &&
211 priv->testmode_trace.dma_addr)
Emmanuel Grumbach1042db22012-01-03 16:56:15 +0200212 dma_free_coherent(trans(priv)->dev,
Wey-Yi Guy49b72102011-05-30 10:29:37 -0700213 priv->testmode_trace.total_size,
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700214 priv->testmode_trace.cpu_addr,
215 priv->testmode_trace.dma_addr);
216 priv->testmode_trace.trace_enabled = false;
217 priv->testmode_trace.cpu_addr = NULL;
218 priv->testmode_trace.trace_addr = NULL;
219 priv->testmode_trace.dma_addr = 0;
Wey-Yi Guy49b72102011-05-30 10:29:37 -0700220 priv->testmode_trace.buff_size = 0;
221 priv->testmode_trace.total_size = 0;
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700222 }
223}
224
225
226void iwl_testmode_cleanup(struct iwl_priv *priv)
227{
228 iwl_trace_cleanup(priv);
Hsu, Kenny306713f2011-11-22 23:03:39 -0800229 iwl_sram_cleanup(priv);
Cindy H. Kao4613e722011-05-06 10:40:15 -0700230}
231
232/*
233 * This function handles the user application commands to the ucode.
234 *
235 * It retrieves the mandatory fields IWL_TM_ATTR_UCODE_CMD_ID and
236 * IWL_TM_ATTR_UCODE_CMD_DATA and calls to the handler to send the
237 * host command to the ucode.
238 *
239 * If any mandatory field is missing, -ENOMSG is replied to the user space
240 * application; otherwise, the actual execution result of the host command to
241 * ucode is replied.
242 *
243 * @hw: ieee80211_hw object that represents the device
244 * @tb: gnl message fields from the user space
245 */
246static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb)
247{
248 struct iwl_priv *priv = hw->priv;
249 struct iwl_host_cmd cmd;
250
251 memset(&cmd, 0, sizeof(struct iwl_host_cmd));
252
253 if (!tb[IWL_TM_ATTR_UCODE_CMD_ID] ||
254 !tb[IWL_TM_ATTR_UCODE_CMD_DATA]) {
255 IWL_DEBUG_INFO(priv,
256 "Error finding ucode command mandatory fields\n");
257 return -ENOMSG;
258 }
259
Wey-Yi Guyc7c11152011-07-08 08:46:25 -0700260 cmd.flags = CMD_ON_DEMAND;
Cindy H. Kao4613e722011-05-06 10:40:15 -0700261 cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]);
Johannes Berg3fa50732011-05-04 07:50:38 -0700262 cmd.data[0] = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
263 cmd.len[0] = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
Johannes Berg4ce7cc22011-05-13 11:57:40 -0700264 cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
Cindy H. Kao4613e722011-05-06 10:40:15 -0700265 IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x,"
Johannes Berg3fa50732011-05-04 07:50:38 -0700266 " len %d\n", cmd.id, cmd.flags, cmd.len[0]);
Cindy H. Kao4613e722011-05-06 10:40:15 -0700267 /* ok, let's submit the command to ucode */
Emmanuel Grumbache6bb4c92011-08-25 23:10:48 -0700268 return iwl_trans_send_cmd(trans(priv), &cmd);
Cindy H. Kao4613e722011-05-06 10:40:15 -0700269}
270
271
272/*
273 * This function handles the user application commands for register access.
274 *
275 * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
276 * handlers respectively.
277 *
278 * If it's an unknown commdn ID, -ENOSYS is returned; or -ENOMSG if the
279 * mandatory fields(IWL_TM_ATTR_REG_OFFSET,IWL_TM_ATTR_REG_VALUE32,
280 * IWL_TM_ATTR_REG_VALUE8) are missing; Otherwise 0 is replied indicating
281 * the success of the command execution.
282 *
283 * If IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_REG_READ32, the register read
284 * value is returned with IWL_TM_ATTR_REG_VALUE32.
285 *
286 * @hw: ieee80211_hw object that represents the device
287 * @tb: gnl message fields from the user space
288 */
289static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
290{
291 struct iwl_priv *priv = hw->priv;
Amit Beka6fe7dd02012-01-25 09:19:24 +0200292 u32 ofs, val32, cmd;
Cindy H. Kao4613e722011-05-06 10:40:15 -0700293 u8 val8;
294 struct sk_buff *skb;
295 int status = 0;
296
297 if (!tb[IWL_TM_ATTR_REG_OFFSET]) {
298 IWL_DEBUG_INFO(priv, "Error finding register offset\n");
299 return -ENOMSG;
300 }
301 ofs = nla_get_u32(tb[IWL_TM_ATTR_REG_OFFSET]);
302 IWL_INFO(priv, "testmode register access command offset 0x%x\n", ofs);
303
Amit Beka6fe7dd02012-01-25 09:19:24 +0200304 /* Allow access only to FH/CSR/HBUS in direct mode.
305 Since we don't have the upper bounds for the CSR and HBUS segments,
306 we will use only the upper bound of FH for sanity check. */
307 cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]);
308 if ((cmd == IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32 ||
309 cmd == IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32 ||
310 cmd == IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8) &&
311 (ofs >= FH_MEM_UPPER_BOUND)) {
312 IWL_DEBUG_INFO(priv, "offset out of segment (0x0 - 0x%x)\n",
313 FH_MEM_UPPER_BOUND);
314 return -EINVAL;
315 }
316
317 switch (cmd) {
Hsu, Kenny72bcacc2011-11-15 19:24:32 -0800318 case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32:
Emmanuel Grumbach1042db22012-01-03 16:56:15 +0200319 val32 = iwl_read_direct32(trans(priv), ofs);
Cindy H. Kao4613e722011-05-06 10:40:15 -0700320 IWL_INFO(priv, "32bit value to read 0x%x\n", val32);
321
322 skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
323 if (!skb) {
324 IWL_DEBUG_INFO(priv, "Error allocating memory\n");
325 return -ENOMEM;
326 }
327 NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32);
328 status = cfg80211_testmode_reply(skb);
329 if (status < 0)
330 IWL_DEBUG_INFO(priv,
331 "Error sending msg : %d\n", status);
332 break;
Hsu, Kenny72bcacc2011-11-15 19:24:32 -0800333 case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32:
Cindy H. Kao4613e722011-05-06 10:40:15 -0700334 if (!tb[IWL_TM_ATTR_REG_VALUE32]) {
335 IWL_DEBUG_INFO(priv,
336 "Error finding value to write\n");
337 return -ENOMSG;
338 } else {
339 val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]);
340 IWL_INFO(priv, "32bit value to write 0x%x\n", val32);
Emmanuel Grumbach1042db22012-01-03 16:56:15 +0200341 iwl_write_direct32(trans(priv), ofs, val32);
Cindy H. Kao4613e722011-05-06 10:40:15 -0700342 }
343 break;
Hsu, Kenny72bcacc2011-11-15 19:24:32 -0800344 case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8:
Cindy H. Kao4613e722011-05-06 10:40:15 -0700345 if (!tb[IWL_TM_ATTR_REG_VALUE8]) {
346 IWL_DEBUG_INFO(priv, "Error finding value to write\n");
347 return -ENOMSG;
348 } else {
349 val8 = nla_get_u8(tb[IWL_TM_ATTR_REG_VALUE8]);
350 IWL_INFO(priv, "8bit value to write 0x%x\n", val8);
Emmanuel Grumbach1042db22012-01-03 16:56:15 +0200351 iwl_write8(trans(priv), ofs, val8);
Cindy H. Kao4613e722011-05-06 10:40:15 -0700352 }
353 break;
Hsu, Kenny72bcacc2011-11-15 19:24:32 -0800354 case IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32:
Emmanuel Grumbach1042db22012-01-03 16:56:15 +0200355 val32 = iwl_read_prph(trans(priv), ofs);
Hsu, Kenny72bcacc2011-11-15 19:24:32 -0800356 IWL_INFO(priv, "32bit value to read 0x%x\n", val32);
357
358 skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
359 if (!skb) {
360 IWL_DEBUG_INFO(priv, "Error allocating memory\n");
361 return -ENOMEM;
362 }
363 NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32);
364 status = cfg80211_testmode_reply(skb);
365 if (status < 0)
366 IWL_DEBUG_INFO(priv,
367 "Error sending msg : %d\n", status);
368 break;
369 case IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32:
370 if (!tb[IWL_TM_ATTR_REG_VALUE32]) {
371 IWL_DEBUG_INFO(priv,
372 "Error finding value to write\n");
373 return -ENOMSG;
374 } else {
375 val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]);
376 IWL_INFO(priv, "32bit value to write 0x%x\n", val32);
Emmanuel Grumbach1042db22012-01-03 16:56:15 +0200377 iwl_write_prph(trans(priv), ofs, val32);
Hsu, Kenny72bcacc2011-11-15 19:24:32 -0800378 }
379 break;
Cindy H. Kao4613e722011-05-06 10:40:15 -0700380 default:
381 IWL_DEBUG_INFO(priv, "Unknown testmode register command ID\n");
382 return -ENOSYS;
383 }
384
385 return status;
386
387nla_put_failure:
388 kfree_skb(skb);
389 return -EMSGSIZE;
390}
391
392
393static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv)
394{
395 struct iwl_notification_wait calib_wait;
396 int ret;
397
Don Frydd5fe102011-11-28 16:13:19 -0800398 iwl_init_notification_wait(priv->shrd, &calib_wait,
Cindy H. Kao4613e722011-05-06 10:40:15 -0700399 CALIBRATION_COMPLETE_NOTIFICATION,
400 NULL, NULL);
Don Fry69a679b2011-12-07 08:50:46 -0800401 ret = iwl_init_alive_start(trans(priv));
Cindy H. Kao4613e722011-05-06 10:40:15 -0700402 if (ret) {
403 IWL_DEBUG_INFO(priv,
404 "Error configuring init calibration: %d\n", ret);
405 goto cfg_init_calib_error;
406 }
407
Don Frydd5fe102011-11-28 16:13:19 -0800408 ret = iwl_wait_notification(priv->shrd, &calib_wait, 2 * HZ);
Cindy H. Kao4613e722011-05-06 10:40:15 -0700409 if (ret)
410 IWL_DEBUG_INFO(priv, "Error detecting"
411 " CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret);
412 return ret;
413
414cfg_init_calib_error:
Don Frydd5fe102011-11-28 16:13:19 -0800415 iwl_remove_notification(priv->shrd, &calib_wait);
Cindy H. Kao4613e722011-05-06 10:40:15 -0700416 return ret;
417}
418
419/*
420 * This function handles the user application commands for driver.
421 *
422 * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
423 * handlers respectively.
424 *
425 * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned
426 * value of the actual command execution is replied to the user application.
427 *
428 * If there's any message responding to the user space, IWL_TM_ATTR_SYNC_RSP
429 * is used for carry the message while IWL_TM_ATTR_COMMAND must set to
430 * IWL_TM_CMD_DEV2APP_SYNC_RSP.
431 *
432 * @hw: ieee80211_hw object that represents the device
433 * @tb: gnl message fields from the user space
434 */
435static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
436{
437 struct iwl_priv *priv = hw->priv;
Don Fry69a679b2011-12-07 08:50:46 -0800438 struct iwl_trans *trans = trans(priv);
Cindy H. Kao4613e722011-05-06 10:40:15 -0700439 struct sk_buff *skb;
440 unsigned char *rsp_data_ptr = NULL;
441 int status = 0, rsp_data_len = 0;
Kenny Hsuaca9b5f2011-12-24 12:12:12 +0800442 u32 devid, inst_size = 0, data_size = 0;
Cindy H. Kao4613e722011-05-06 10:40:15 -0700443
444 switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
445 case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
Don Fry38622412011-12-16 07:07:36 -0800446 rsp_data_ptr = (unsigned char *)cfg(priv)->name;
447 rsp_data_len = strlen(cfg(priv)->name);
Cindy H. Kao4613e722011-05-06 10:40:15 -0700448 skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
449 rsp_data_len + 20);
450 if (!skb) {
451 IWL_DEBUG_INFO(priv,
452 "Error allocating memory\n");
453 return -ENOMEM;
454 }
455 NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND,
456 IWL_TM_CMD_DEV2APP_SYNC_RSP);
457 NLA_PUT(skb, IWL_TM_ATTR_SYNC_RSP,
458 rsp_data_len, rsp_data_ptr);
459 status = cfg80211_testmode_reply(skb);
460 if (status < 0)
461 IWL_DEBUG_INFO(priv, "Error sending msg : %d\n",
462 status);
463 break;
464
465 case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
Don Fry69a679b2011-12-07 08:50:46 -0800466 status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_INIT);
Cindy H. Kao4613e722011-05-06 10:40:15 -0700467 if (status)
468 IWL_DEBUG_INFO(priv,
469 "Error loading init ucode: %d\n", status);
470 break;
471
472 case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
473 iwl_testmode_cfg_init_calib(priv);
Don Fry69a679b2011-12-07 08:50:46 -0800474 iwl_trans_stop_device(trans);
Cindy H. Kao4613e722011-05-06 10:40:15 -0700475 break;
476
477 case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
Don Fry69a679b2011-12-07 08:50:46 -0800478 status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_REGULAR);
Cindy H. Kao4613e722011-05-06 10:40:15 -0700479 if (status) {
480 IWL_DEBUG_INFO(priv,
481 "Error loading runtime ucode: %d\n", status);
482 break;
483 }
484 status = iwl_alive_start(priv);
485 if (status)
486 IWL_DEBUG_INFO(priv,
487 "Error starting the device: %d\n", status);
488 break;
489
Hsu, Kennyd4af19f2011-11-24 22:26:53 -0800490 case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW:
491 iwl_scan_cancel_timeout(priv, 200);
Don Fry69a679b2011-12-07 08:50:46 -0800492 iwl_trans_stop_device(trans);
493 status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_WOWLAN);
Hsu, Kennyd4af19f2011-11-24 22:26:53 -0800494 if (status) {
495 IWL_DEBUG_INFO(priv,
496 "Error loading WOWLAN ucode: %d\n", status);
497 break;
498 }
499 status = iwl_alive_start(priv);
500 if (status)
501 IWL_DEBUG_INFO(priv,
502 "Error starting the device: %d\n", status);
503 break;
504
Wey-Yi Guy4babc352011-05-03 18:05:12 -0700505 case IWL_TM_CMD_APP2DEV_GET_EEPROM:
Don Fryab36eab2011-11-30 15:37:32 -0800506 if (priv->shrd->eeprom) {
Wey-Yi Guy4babc352011-05-03 18:05:12 -0700507 skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
Don Fry38622412011-12-16 07:07:36 -0800508 cfg(priv)->base_params->eeprom_size + 20);
Wey-Yi Guy4babc352011-05-03 18:05:12 -0700509 if (!skb) {
510 IWL_DEBUG_INFO(priv,
511 "Error allocating memory\n");
512 return -ENOMEM;
513 }
514 NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND,
515 IWL_TM_CMD_DEV2APP_EEPROM_RSP);
516 NLA_PUT(skb, IWL_TM_ATTR_EEPROM,
Don Fry38622412011-12-16 07:07:36 -0800517 cfg(priv)->base_params->eeprom_size,
Don Fryab36eab2011-11-30 15:37:32 -0800518 priv->shrd->eeprom);
Wey-Yi Guy4babc352011-05-03 18:05:12 -0700519 status = cfg80211_testmode_reply(skb);
520 if (status < 0)
521 IWL_DEBUG_INFO(priv,
522 "Error sending msg : %d\n",
523 status);
524 } else
525 return -EFAULT;
526 break;
527
Wey-Yi Guy64898542011-05-03 18:05:13 -0700528 case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
529 if (!tb[IWL_TM_ATTR_FIXRATE]) {
530 IWL_DEBUG_INFO(priv,
531 "Error finding fixrate setting\n");
532 return -ENOMSG;
533 }
Wey-Yi Guy4e308112011-07-08 08:46:28 -0700534 priv->tm_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]);
Wey-Yi Guy64898542011-05-03 18:05:13 -0700535 break;
536
Hsu, Kennye1a38fe2011-11-28 00:55:38 -0800537 case IWL_TM_CMD_APP2DEV_GET_FW_VERSION:
538 IWL_INFO(priv, "uCode version raw: 0x%x\n", priv->ucode_ver);
539
540 skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
541 if (!skb) {
542 IWL_DEBUG_INFO(priv, "Error allocating memory\n");
543 return -ENOMEM;
544 }
545 NLA_PUT_U32(skb, IWL_TM_ATTR_FW_VERSION, priv->ucode_ver);
546 status = cfg80211_testmode_reply(skb);
547 if (status < 0)
548 IWL_DEBUG_INFO(priv,
549 "Error sending msg : %d\n", status);
550 break;
551
Hsu, Kenny0bec12b2011-12-01 01:12:50 -0800552 case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID:
Emmanuel Grumbach99673ee2012-01-08 21:19:45 +0200553 devid = trans(priv)->hw_id;
Wey-Yi Guyfb6c1c62011-12-10 11:33:53 -0800554 IWL_INFO(priv, "hw version: 0x%x\n", devid);
Hsu, Kenny0bec12b2011-12-01 01:12:50 -0800555
556 skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
557 if (!skb) {
558 IWL_DEBUG_INFO(priv, "Error allocating memory\n");
559 return -ENOMEM;
560 }
561 NLA_PUT_U32(skb, IWL_TM_ATTR_DEVICE_ID, devid);
562 status = cfg80211_testmode_reply(skb);
563 if (status < 0)
564 IWL_DEBUG_INFO(priv,
565 "Error sending msg : %d\n", status);
566 break;
567
Kenny Hsuaca9b5f2011-12-24 12:12:12 +0800568 case IWL_TM_CMD_APP2DEV_GET_FW_INFO:
569 skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20 + 8);
570 if (!skb) {
571 IWL_DEBUG_INFO(priv, "Error allocating memory\n");
572 return -ENOMEM;
573 }
574 switch (priv->shrd->ucode_type) {
575 case IWL_UCODE_REGULAR:
576 inst_size = trans(priv)->ucode_rt.code.len;
577 data_size = trans(priv)->ucode_rt.data.len;
578 break;
579 case IWL_UCODE_INIT:
580 inst_size = trans(priv)->ucode_init.code.len;
581 data_size = trans(priv)->ucode_init.data.len;
582 break;
583 case IWL_UCODE_WOWLAN:
584 inst_size = trans(priv)->ucode_wowlan.code.len;
585 data_size = trans(priv)->ucode_wowlan.data.len;
586 break;
587 case IWL_UCODE_NONE:
588 IWL_DEBUG_INFO(priv, "The uCode has not been loaded\n");
589 break;
590 default:
591 IWL_DEBUG_INFO(priv, "Unsupported uCode type\n");
592 break;
593 }
594 NLA_PUT_U32(skb, IWL_TM_ATTR_FW_TYPE, priv->shrd->ucode_type);
595 NLA_PUT_U32(skb, IWL_TM_ATTR_FW_INST_SIZE, inst_size);
596 NLA_PUT_U32(skb, IWL_TM_ATTR_FW_DATA_SIZE, data_size);
597 status = cfg80211_testmode_reply(skb);
598 if (status < 0)
599 IWL_DEBUG_INFO(priv,
600 "Error sending msg : %d\n", status);
601 break;
602
Cindy H. Kao4613e722011-05-06 10:40:15 -0700603 default:
604 IWL_DEBUG_INFO(priv, "Unknown testmode driver command ID\n");
605 return -ENOSYS;
606 }
607 return status;
608
609nla_put_failure:
610 kfree_skb(skb);
611 return -EMSGSIZE;
612}
613
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700614
615/*
616 * This function handles the user application commands for uCode trace
617 *
618 * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
619 * handlers respectively.
620 *
621 * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned
622 * value of the actual command execution is replied to the user application.
623 *
624 * @hw: ieee80211_hw object that represents the device
625 * @tb: gnl message fields from the user space
626 */
627static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb)
628{
629 struct iwl_priv *priv = hw->priv;
630 struct sk_buff *skb;
631 int status = 0;
Emmanuel Grumbach1042db22012-01-03 16:56:15 +0200632 struct device *dev = trans(priv)->dev;
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700633
634 switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
635 case IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
636 if (priv->testmode_trace.trace_enabled)
637 return -EBUSY;
638
Wey-Yi Guy49b72102011-05-30 10:29:37 -0700639 if (!tb[IWL_TM_ATTR_TRACE_SIZE])
640 priv->testmode_trace.buff_size = TRACE_BUFF_SIZE_DEF;
641 else
642 priv->testmode_trace.buff_size =
643 nla_get_u32(tb[IWL_TM_ATTR_TRACE_SIZE]);
644 if (!priv->testmode_trace.buff_size)
645 return -EINVAL;
646 if (priv->testmode_trace.buff_size < TRACE_BUFF_SIZE_MIN ||
647 priv->testmode_trace.buff_size > TRACE_BUFF_SIZE_MAX)
648 return -EINVAL;
649
650 priv->testmode_trace.total_size =
651 priv->testmode_trace.buff_size + TRACE_BUFF_PADD;
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700652 priv->testmode_trace.cpu_addr =
653 dma_alloc_coherent(dev,
Wey-Yi Guy49b72102011-05-30 10:29:37 -0700654 priv->testmode_trace.total_size,
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700655 &priv->testmode_trace.dma_addr,
656 GFP_KERNEL);
657 if (!priv->testmode_trace.cpu_addr)
658 return -ENOMEM;
659 priv->testmode_trace.trace_enabled = true;
660 priv->testmode_trace.trace_addr = (u8 *)PTR_ALIGN(
661 priv->testmode_trace.cpu_addr, 0x100);
662 memset(priv->testmode_trace.trace_addr, 0x03B,
Wey-Yi Guy49b72102011-05-30 10:29:37 -0700663 priv->testmode_trace.buff_size);
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700664 skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
665 sizeof(priv->testmode_trace.dma_addr) + 20);
666 if (!skb) {
667 IWL_DEBUG_INFO(priv,
668 "Error allocating memory\n");
669 iwl_trace_cleanup(priv);
670 return -ENOMEM;
671 }
672 NLA_PUT(skb, IWL_TM_ATTR_TRACE_ADDR,
673 sizeof(priv->testmode_trace.dma_addr),
674 (u64 *)&priv->testmode_trace.dma_addr);
675 status = cfg80211_testmode_reply(skb);
676 if (status < 0) {
677 IWL_DEBUG_INFO(priv,
678 "Error sending msg : %d\n",
679 status);
680 }
Wey-Yi Guyeb64dca2011-05-31 08:03:02 -0700681 priv->testmode_trace.num_chunks =
682 DIV_ROUND_UP(priv->testmode_trace.buff_size,
Hsu, Kennye056a652011-11-22 23:05:02 -0800683 DUMP_CHUNK_SIZE);
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700684 break;
685
686 case IWL_TM_CMD_APP2DEV_END_TRACE:
687 iwl_trace_cleanup(priv);
688 break;
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700689 default:
690 IWL_DEBUG_INFO(priv, "Unknown testmode mem command ID\n");
691 return -ENOSYS;
692 }
693 return status;
694
695nla_put_failure:
696 kfree_skb(skb);
697 if (nla_get_u32(tb[IWL_TM_ATTR_COMMAND]) ==
698 IWL_TM_CMD_APP2DEV_BEGIN_TRACE)
699 iwl_trace_cleanup(priv);
700 return -EMSGSIZE;
701}
702
Wey-Yi Guyeb64dca2011-05-31 08:03:02 -0700703static int iwl_testmode_trace_dump(struct ieee80211_hw *hw, struct nlattr **tb,
704 struct sk_buff *skb,
705 struct netlink_callback *cb)
706{
707 struct iwl_priv *priv = hw->priv;
708 int idx, length;
709
710 if (priv->testmode_trace.trace_enabled &&
711 priv->testmode_trace.trace_addr) {
712 idx = cb->args[4];
713 if (idx >= priv->testmode_trace.num_chunks)
714 return -ENOENT;
Hsu, Kennye056a652011-11-22 23:05:02 -0800715 length = DUMP_CHUNK_SIZE;
Wey-Yi Guyeb64dca2011-05-31 08:03:02 -0700716 if (((idx + 1) == priv->testmode_trace.num_chunks) &&
Hsu, Kennye056a652011-11-22 23:05:02 -0800717 (priv->testmode_trace.buff_size % DUMP_CHUNK_SIZE))
Wey-Yi Guyeb64dca2011-05-31 08:03:02 -0700718 length = priv->testmode_trace.buff_size %
Hsu, Kennye056a652011-11-22 23:05:02 -0800719 DUMP_CHUNK_SIZE;
Wey-Yi Guyeb64dca2011-05-31 08:03:02 -0700720
721 NLA_PUT(skb, IWL_TM_ATTR_TRACE_DUMP, length,
722 priv->testmode_trace.trace_addr +
Hsu, Kennye056a652011-11-22 23:05:02 -0800723 (DUMP_CHUNK_SIZE * idx));
Wey-Yi Guyeb64dca2011-05-31 08:03:02 -0700724 idx++;
725 cb->args[4] = idx;
726 return 0;
727 } else
728 return -EFAULT;
729
730 nla_put_failure:
731 return -ENOBUFS;
732}
733
Wey-Yi Guye98a1932011-07-08 08:46:26 -0700734/*
735 * This function handles the user application switch ucode ownership.
736 *
737 * It retrieves the mandatory fields IWL_TM_ATTR_UCODE_OWNER and
738 * decide who the current owner of the uCode
739 *
740 * If the current owner is OWNERSHIP_TM, then the only host command
741 * can deliver to uCode is from testmode, all the other host commands
742 * will dropped.
743 *
744 * default driver is the owner of uCode in normal operational mode
745 *
746 * @hw: ieee80211_hw object that represents the device
747 * @tb: gnl message fields from the user space
748 */
749static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb)
750{
751 struct iwl_priv *priv = hw->priv;
752 u8 owner;
753
754 if (!tb[IWL_TM_ATTR_UCODE_OWNER]) {
755 IWL_DEBUG_INFO(priv, "Error finding ucode owner\n");
756 return -ENOMSG;
757 }
758
759 owner = nla_get_u8(tb[IWL_TM_ATTR_UCODE_OWNER]);
760 if ((owner == IWL_OWNERSHIP_DRIVER) || (owner == IWL_OWNERSHIP_TM))
Emmanuel Grumbachfd656932011-08-25 23:11:19 -0700761 priv->shrd->ucode_owner = owner;
Wey-Yi Guye98a1932011-07-08 08:46:26 -0700762 else {
763 IWL_DEBUG_INFO(priv, "Invalid owner\n");
764 return -EINVAL;
765 }
766 return 0;
767}
768
Hsu, Kenny306713f2011-11-22 23:03:39 -0800769/*
770 * This function handles the user application commands for SRAM data dump
771 *
772 * It retrieves the mandatory fields IWL_TM_ATTR_SRAM_ADDR and
773 * IWL_TM_ATTR_SRAM_SIZE to decide the memory area for SRAM data reading
774 *
775 * Several error will be retured, -EBUSY if the SRAM data retrieved by
776 * previous command has not been delivered to userspace, or -ENOMSG if
777 * the mandatory fields (IWL_TM_ATTR_SRAM_ADDR,IWL_TM_ATTR_SRAM_SIZE)
778 * are missing, or -ENOMEM if the buffer allocation fails.
779 *
780 * Otherwise 0 is replied indicating the success of the SRAM reading.
781 *
782 * @hw: ieee80211_hw object that represents the device
783 * @tb: gnl message fields from the user space
784 */
785static int iwl_testmode_sram(struct ieee80211_hw *hw, struct nlattr **tb)
786{
787 struct iwl_priv *priv = hw->priv;
Kenny Hsu25324ca2011-12-27 08:18:31 -0800788 u32 ofs, size, maxsize;
Hsu, Kenny306713f2011-11-22 23:03:39 -0800789
790 if (priv->testmode_sram.sram_readed)
791 return -EBUSY;
792
793 if (!tb[IWL_TM_ATTR_SRAM_ADDR]) {
794 IWL_DEBUG_INFO(priv, "Error finding SRAM offset address\n");
795 return -ENOMSG;
796 }
797 ofs = nla_get_u32(tb[IWL_TM_ATTR_SRAM_ADDR]);
798 if (!tb[IWL_TM_ATTR_SRAM_SIZE]) {
799 IWL_DEBUG_INFO(priv, "Error finding size for SRAM reading\n");
800 return -ENOMSG;
801 }
802 size = nla_get_u32(tb[IWL_TM_ATTR_SRAM_SIZE]);
Don Fry3d6acef2011-11-28 17:05:01 -0800803 switch (priv->shrd->ucode_type) {
Kenny Hsu76de2f22011-11-23 06:57:22 -0800804 case IWL_UCODE_REGULAR:
805 maxsize = trans(priv)->ucode_rt.data.len;
806 break;
807 case IWL_UCODE_INIT:
808 maxsize = trans(priv)->ucode_init.data.len;
809 break;
810 case IWL_UCODE_WOWLAN:
811 maxsize = trans(priv)->ucode_wowlan.data.len;
812 break;
813 case IWL_UCODE_NONE:
Kenny Hsu22b48082011-12-27 08:27:52 -0800814 IWL_ERR(priv, "Error, uCode does not been loaded\n");
Kenny Hsu76de2f22011-11-23 06:57:22 -0800815 return -ENOSYS;
816 default:
Kenny Hsu22b48082011-12-27 08:27:52 -0800817 IWL_ERR(priv, "Error, unsupported uCode type\n");
Kenny Hsu76de2f22011-11-23 06:57:22 -0800818 return -ENOSYS;
819 }
Kenny Hsu25324ca2011-12-27 08:18:31 -0800820 if ((ofs + size) > (maxsize + SRAM_DATA_SEG_OFFSET)) {
Kenny Hsu22b48082011-12-27 08:27:52 -0800821 IWL_ERR(priv, "Invalid offset/size: out of range\n");
Kenny Hsu76de2f22011-11-23 06:57:22 -0800822 return -EINVAL;
823 }
Hsu, Kenny306713f2011-11-22 23:03:39 -0800824 priv->testmode_sram.buff_size = (size / 4) * 4;
825 priv->testmode_sram.buff_addr =
826 kmalloc(priv->testmode_sram.buff_size, GFP_KERNEL);
827 if (priv->testmode_sram.buff_addr == NULL) {
Kenny Hsu22b48082011-12-27 08:27:52 -0800828 IWL_ERR(priv, "Error allocating memory\n");
Hsu, Kenny306713f2011-11-22 23:03:39 -0800829 return -ENOMEM;
830 }
Emmanuel Grumbach1042db22012-01-03 16:56:15 +0200831 _iwl_read_targ_mem_words(trans(priv), ofs,
Hsu, Kenny306713f2011-11-22 23:03:39 -0800832 priv->testmode_sram.buff_addr,
833 priv->testmode_sram.buff_size / 4);
834 priv->testmode_sram.num_chunks =
Hsu, Kennye056a652011-11-22 23:05:02 -0800835 DIV_ROUND_UP(priv->testmode_sram.buff_size, DUMP_CHUNK_SIZE);
Hsu, Kenny306713f2011-11-22 23:03:39 -0800836 priv->testmode_sram.sram_readed = true;
837 return 0;
838}
839
840static int iwl_testmode_sram_dump(struct ieee80211_hw *hw, struct nlattr **tb,
841 struct sk_buff *skb,
842 struct netlink_callback *cb)
843{
844 struct iwl_priv *priv = hw->priv;
845 int idx, length;
846
847 if (priv->testmode_sram.sram_readed) {
848 idx = cb->args[4];
849 if (idx >= priv->testmode_sram.num_chunks) {
850 iwl_sram_cleanup(priv);
851 return -ENOENT;
852 }
Hsu, Kennye056a652011-11-22 23:05:02 -0800853 length = DUMP_CHUNK_SIZE;
Hsu, Kenny306713f2011-11-22 23:03:39 -0800854 if (((idx + 1) == priv->testmode_sram.num_chunks) &&
Hsu, Kennye056a652011-11-22 23:05:02 -0800855 (priv->testmode_sram.buff_size % DUMP_CHUNK_SIZE))
Hsu, Kenny306713f2011-11-22 23:03:39 -0800856 length = priv->testmode_sram.buff_size %
Hsu, Kennye056a652011-11-22 23:05:02 -0800857 DUMP_CHUNK_SIZE;
Hsu, Kenny306713f2011-11-22 23:03:39 -0800858
859 NLA_PUT(skb, IWL_TM_ATTR_SRAM_DUMP, length,
860 priv->testmode_sram.buff_addr +
Hsu, Kennye056a652011-11-22 23:05:02 -0800861 (DUMP_CHUNK_SIZE * idx));
Hsu, Kenny306713f2011-11-22 23:03:39 -0800862 idx++;
863 cb->args[4] = idx;
864 return 0;
865 } else
866 return -EFAULT;
867
868 nla_put_failure:
869 return -ENOBUFS;
870}
871
Wey-Yi Guye98a1932011-07-08 08:46:26 -0700872
Cindy H. Kao4613e722011-05-06 10:40:15 -0700873/* The testmode gnl message handler that takes the gnl message from the
874 * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then
875 * invoke the corresponding handlers.
876 *
877 * This function is invoked when there is user space application sending
878 * gnl message through the testmode tunnel NL80211_CMD_TESTMODE regulated
879 * by nl80211.
880 *
881 * It retrieves the mandatory field, IWL_TM_ATTR_COMMAND, before
882 * dispatching it to the corresponding handler.
883 *
884 * If IWL_TM_ATTR_COMMAND is missing, -ENOMSG is replied to user application;
885 * -ENOSYS is replied to the user application if the command is unknown;
886 * Otherwise, the command is dispatched to the respective handler.
887 *
888 * @hw: ieee80211_hw object that represents the device
889 * @data: pointer to user space message
890 * @len: length in byte of @data
891 */
Wey-Yi Guyade4c642011-10-10 07:27:11 -0700892int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
Cindy H. Kao4613e722011-05-06 10:40:15 -0700893{
Wey-Yi Guya6779272011-07-11 10:47:39 -0700894 struct nlattr *tb[IWL_TM_ATTR_MAX];
Cindy H. Kao4613e722011-05-06 10:40:15 -0700895 struct iwl_priv *priv = hw->priv;
896 int result;
897
898 result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len,
899 iwl_testmode_gnl_msg_policy);
900 if (result != 0) {
901 IWL_DEBUG_INFO(priv,
902 "Error parsing the gnl message : %d\n", result);
903 return result;
904 }
905
906 /* IWL_TM_ATTR_COMMAND is absolutely mandatory */
907 if (!tb[IWL_TM_ATTR_COMMAND]) {
908 IWL_DEBUG_INFO(priv, "Error finding testmode command type\n");
909 return -ENOMSG;
910 }
911 /* in case multiple accesses to the device happens */
Emmanuel Grumbach6ac2f832011-08-25 23:10:44 -0700912 mutex_lock(&priv->shrd->mutex);
Cindy H. Kao4613e722011-05-06 10:40:15 -0700913
914 switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
915 case IWL_TM_CMD_APP2DEV_UCODE:
916 IWL_DEBUG_INFO(priv, "testmode cmd to uCode\n");
917 result = iwl_testmode_ucode(hw, tb);
918 break;
Hsu, Kenny72bcacc2011-11-15 19:24:32 -0800919 case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32:
920 case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32:
921 case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8:
922 case IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32:
923 case IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32:
Cindy H. Kao4613e722011-05-06 10:40:15 -0700924 IWL_DEBUG_INFO(priv, "testmode cmd to register\n");
925 result = iwl_testmode_reg(hw, tb);
926 break;
927 case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
928 case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
929 case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
930 case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
Wey-Yi Guy4babc352011-05-03 18:05:12 -0700931 case IWL_TM_CMD_APP2DEV_GET_EEPROM:
Wey-Yi Guy64898542011-05-03 18:05:13 -0700932 case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
Hsu, Kennyd4af19f2011-11-24 22:26:53 -0800933 case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW:
Hsu, Kennye1a38fe2011-11-28 00:55:38 -0800934 case IWL_TM_CMD_APP2DEV_GET_FW_VERSION:
Hsu, Kenny0bec12b2011-12-01 01:12:50 -0800935 case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID:
Kenny Hsuaca9b5f2011-12-24 12:12:12 +0800936 case IWL_TM_CMD_APP2DEV_GET_FW_INFO:
Cindy H. Kao4613e722011-05-06 10:40:15 -0700937 IWL_DEBUG_INFO(priv, "testmode cmd to driver\n");
938 result = iwl_testmode_driver(hw, tb);
939 break;
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700940
941 case IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
942 case IWL_TM_CMD_APP2DEV_END_TRACE:
943 case IWL_TM_CMD_APP2DEV_READ_TRACE:
944 IWL_DEBUG_INFO(priv, "testmode uCode trace cmd to driver\n");
945 result = iwl_testmode_trace(hw, tb);
946 break;
947
Wey-Yi Guye98a1932011-07-08 08:46:26 -0700948 case IWL_TM_CMD_APP2DEV_OWNERSHIP:
949 IWL_DEBUG_INFO(priv, "testmode change uCode ownership\n");
950 result = iwl_testmode_ownership(hw, tb);
951 break;
952
Hsu, Kenny306713f2011-11-22 23:03:39 -0800953 case IWL_TM_CMD_APP2DEV_READ_SRAM:
954 IWL_DEBUG_INFO(priv, "testmode sram read cmd to driver\n");
955 result = iwl_testmode_sram(hw, tb);
956 break;
957
Cindy H. Kao4613e722011-05-06 10:40:15 -0700958 default:
959 IWL_DEBUG_INFO(priv, "Unknown testmode command\n");
960 result = -ENOSYS;
961 break;
962 }
963
Emmanuel Grumbach6ac2f832011-08-25 23:10:44 -0700964 mutex_unlock(&priv->shrd->mutex);
Cindy H. Kao4613e722011-05-06 10:40:15 -0700965 return result;
966}
Wey-Yi Guyeb64dca2011-05-31 08:03:02 -0700967
Wey-Yi Guyade4c642011-10-10 07:27:11 -0700968int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
Wey-Yi Guyeb64dca2011-05-31 08:03:02 -0700969 struct netlink_callback *cb,
970 void *data, int len)
971{
972 struct nlattr *tb[IWL_TM_ATTR_MAX];
973 struct iwl_priv *priv = hw->priv;
974 int result;
975 u32 cmd;
976
977 if (cb->args[3]) {
978 /* offset by 1 since commands start at 0 */
979 cmd = cb->args[3] - 1;
980 } else {
981 result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len,
982 iwl_testmode_gnl_msg_policy);
983 if (result) {
984 IWL_DEBUG_INFO(priv,
985 "Error parsing the gnl message : %d\n", result);
986 return result;
987 }
988
989 /* IWL_TM_ATTR_COMMAND is absolutely mandatory */
990 if (!tb[IWL_TM_ATTR_COMMAND]) {
991 IWL_DEBUG_INFO(priv,
992 "Error finding testmode command type\n");
993 return -ENOMSG;
994 }
995 cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]);
996 cb->args[3] = cmd + 1;
997 }
998
999 /* in case multiple accesses to the device happens */
Emmanuel Grumbach6ac2f832011-08-25 23:10:44 -07001000 mutex_lock(&priv->shrd->mutex);
Wey-Yi Guyeb64dca2011-05-31 08:03:02 -07001001 switch (cmd) {
1002 case IWL_TM_CMD_APP2DEV_READ_TRACE:
1003 IWL_DEBUG_INFO(priv, "uCode trace cmd to driver\n");
1004 result = iwl_testmode_trace_dump(hw, tb, skb, cb);
1005 break;
Hsu, Kenny306713f2011-11-22 23:03:39 -08001006 case IWL_TM_CMD_APP2DEV_DUMP_SRAM:
1007 IWL_DEBUG_INFO(priv, "testmode sram dump cmd to driver\n");
1008 result = iwl_testmode_sram_dump(hw, tb, skb, cb);
1009 break;
Wey-Yi Guyeb64dca2011-05-31 08:03:02 -07001010 default:
1011 result = -EINVAL;
1012 break;
1013 }
1014
Emmanuel Grumbach6ac2f832011-08-25 23:10:44 -07001015 mutex_unlock(&priv->shrd->mutex);
Wey-Yi Guyeb64dca2011-05-31 08:03:02 -07001016 return result;
1017}