aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorCindy H. Kao <cindy.h.kao@intel.com>2011-05-06 13:40:15 -0400
committerWey-Yi Guy <wey-yi.w.guy@intel.com>2011-05-06 13:44:46 -0400
commit4613e72dbdc9a44bfc4625d835511264121c4244 (patch)
tree88d0c44ced77fccf71adf9c25c0a0c2219db0fb4 /drivers
parentd6d023a1948d13652d719238f8039c09acceda8c (diff)
iwlwifi: support the svtool messages interactions through nl80211 test mode
This patch adds the feature to support the test mode operation through the generic netlink channel NL80211_CMD_TESTMODE between intel wireless device iwlwifi and the user space application svtool. The main purpose is to create a transportation layer between the iwlwifi device and the user space application so that the interaction between the user space application svtool and the iwlwifi device in the kernel space is in a way of generic netlink messaging. The detail specific functions are: 1. The function iwl_testmode_cmd() is added to digest the svtool test command from the user space application. The svtool test commands are categorized to three types : commands to be processed by the device ucode, commands to access the registers, and commands to be processed at the driver level(such as reload the ucode). iwl_testmode_cmd() dispatches the commands the corresponding handlers and reply to user space regarding the command execution status. Extra data is returned to the user space application if there's any. 2. The function iwl_testmode_ucode_rx_pkt() is added to multicast all the spontaneous messages from the iwlwifi device to the user space. Regardless the message types, whenever there is a valid spontaneous message received by the iwlwifi ISR, iwl_testmode_ucode_rx_pkt() is invoked to multicast the message content to user space. The message content is not attacked and the message parsing is left to the user space application. Implementation guidelines: 1. The generic netlink messaging for iwliwif test mode is through NL80211_CMD_TESTMODE channel, therefore, the codes need to follow the regulations set by cfg80211.ko to get the actual device instance ieee80211_ops via cfg80211.ko, so that the iwlwifi device is indicated with ieee80211_ops and can be actually accessed. Therefore, a callback iwl_testmode_cmd() is added to the structure iwlagn_hw_ops in iwl-agn.c. 2. It intends to utilize those low level device access APIs from iwlwifi device driver (ie. iwlagn.ko) rather than creating it's own set of device access functions. For example, iwl_send_cmd(), iwl_read32(), iwl_write8(), and iwl_write32() are reused. 3. The main functions are maintained in new files instead of spreading all over the existing iwlwifi driver files. The new files added are : drivers/net/wireless/iwlwifi/iwl-sv-open.c - to handle the user space test mode application command and reply the respective command status to the user space application. - to multicast the spontaneous messages from device to user space. drivers/net/wireless/iwlwifi/iwl-testmode.h - the commonly referenced definitions for the TLVs used in the generic netlink messages Signed-off-by: Cindy H. Kao <cindy.h.kao@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig10
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-ucode.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.h17
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sv-open.c469
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-testmode.h151
8 files changed, 656 insertions, 2 deletions
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index 17d555f2215a..ad3bdba6beed 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -102,6 +102,16 @@ config IWLWIFI_DEVICE_TRACING
102 occur. 102 occur.
103endmenu 103endmenu
104 104
105config IWLWIFI_DEVICE_SVTOOL
106 bool "iwlwifi device svtool support"
107 depends on IWLAGN
108 select NL80211_TESTMODE
109 help
110 This option enables the svtool support for iwlwifi device through
111 NL80211_TESTMODE. svtool is a software validation tool that runs in
112 the user space and interacts with the device in the kernel space
113 through the generic netlink message via NL80211_TESTMODE channel.
114
105config IWL_P2P 115config IWL_P2P
106 bool "iwlwifi experimental P2P support" 116 bool "iwlwifi experimental P2P support"
107 depends on IWLAGN 117 depends on IWLAGN
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 89a41d320c36..822660483f9f 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -16,6 +16,7 @@ iwlagn-objs += iwl-2000.o
16 16
17iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o 17iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
18iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o 18iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
19iwlagn-$(CONFIG_IWLWIFI_DEVICE_SVTOOL) += iwl-sv-open.o
19 20
20CFLAGS_iwl-devtrace.o := -I$(src) 21CFLAGS_iwl-devtrace.o := -I$(src)
21 22
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
index c3ae2e44fcc9..8bda0e8d6661 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
@@ -269,7 +269,7 @@ void iwlagn_rx_calib_result(struct iwl_priv *priv,
269 iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len); 269 iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len);
270} 270}
271 271
272static int iwlagn_init_alive_start(struct iwl_priv *priv) 272int iwlagn_init_alive_start(struct iwl_priv *priv)
273{ 273{
274 int ret; 274 int ret;
275 275
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 003d5243542b..09fe841f0281 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -776,6 +776,8 @@ static void iwl_rx_handle(struct iwl_priv *priv)
776 776
777 wake_up_all(&priv->_agn.notif_waitq); 777 wake_up_all(&priv->_agn.notif_waitq);
778 } 778 }
779 if (priv->pre_rx_handler)
780 priv->pre_rx_handler(priv, rxb);
779 781
780 /* Based on type of command response or notification, 782 /* Based on type of command response or notification,
781 * handle those that need handling via function in 783 * handle those that need handling via function in
@@ -2211,7 +2213,7 @@ static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg)
2211 * from protocol/runtime uCode (initialization uCode's 2213 * from protocol/runtime uCode (initialization uCode's
2212 * Alive gets handled by iwl_init_alive_start()). 2214 * Alive gets handled by iwl_init_alive_start()).
2213 */ 2215 */
2214static int iwl_alive_start(struct iwl_priv *priv) 2216int iwl_alive_start(struct iwl_priv *priv)
2215{ 2217{
2216 int ret = 0; 2218 int ret = 0;
2217 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; 2219 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
@@ -3507,6 +3509,7 @@ struct ieee80211_ops iwlagn_hw_ops = {
3507 .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel, 3509 .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel,
3508 .offchannel_tx = iwl_mac_offchannel_tx, 3510 .offchannel_tx = iwl_mac_offchannel_tx,
3509 .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait, 3511 .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait,
3512 CFG80211_TESTMODE_CMD(iwl_testmode_cmd)
3510}; 3513};
3511 3514
3512static u32 iwl_hw_detect(struct iwl_priv *priv) 3515static u32 iwl_hw_detect(struct iwl_priv *priv)
@@ -3816,6 +3819,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
3816 3819
3817 iwl_setup_deferred_work(priv); 3820 iwl_setup_deferred_work(priv);
3818 iwl_setup_rx_handlers(priv); 3821 iwl_setup_rx_handlers(priv);
3822 iwl_testmode_init(priv);
3819 3823
3820 /********************************************* 3824 /*********************************************
3821 * 8. Enable interrupts and read RFKILL state 3825 * 8. Enable interrupts and read RFKILL state
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index b477336ff53a..aa398b6dab1f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -344,5 +344,22 @@ iwlagn_wait_notification(struct iwl_priv *priv,
344void __releases(wait_entry) 344void __releases(wait_entry)
345iwlagn_remove_notification(struct iwl_priv *priv, 345iwlagn_remove_notification(struct iwl_priv *priv,
346 struct iwl_notification_wait *wait_entry); 346 struct iwl_notification_wait *wait_entry);
347extern int iwlagn_init_alive_start(struct iwl_priv *priv);
348extern int iwl_alive_start(struct iwl_priv *priv);
349/* svtool */
350#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL
351extern int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len);
352extern void iwl_testmode_init(struct iwl_priv *priv);
353#else
354static inline
355int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
356{
357 return -ENOSYS;
358}
359static inline
360void iwl_testmode_init(struct iwl_priv *priv)
361{
362}
363#endif
347 364
348#endif /* __iwl_agn_h__ */ 365#endif /* __iwl_agn_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index f098eff263f8..3d28ad258077 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1194,6 +1194,8 @@ struct iwl_priv {
1194 1194
1195 enum ieee80211_band band; 1195 enum ieee80211_band band;
1196 1196
1197 void (*pre_rx_handler)(struct iwl_priv *priv,
1198 struct iwl_rx_mem_buffer *rxb);
1197 void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, 1199 void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
1198 struct iwl_rx_mem_buffer *rxb); 1200 struct iwl_rx_mem_buffer *rxb);
1199 1201
diff --git a/drivers/net/wireless/iwlwifi/iwl-sv-open.c b/drivers/net/wireless/iwlwifi/iwl-sv-open.c
new file mode 100644
index 000000000000..89b6696622c1
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-sv-open.c
@@ -0,0 +1,469 @@
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 - 2011 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 - 2011 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#include <linux/init.h>
64#include <linux/kernel.h>
65#include <linux/module.h>
66#include <net/net_namespace.h>
67#include <linux/netdevice.h>
68#include <net/cfg80211.h>
69#include <net/mac80211.h>
70#include <net/netlink.h>
71
72
73#include "iwl-dev.h"
74#include "iwl-core.h"
75#include "iwl-debug.h"
76#include "iwl-fh.h"
77#include "iwl-io.h"
78#include "iwl-agn.h"
79#include "iwl-testmode.h"
80
81
82/* The TLVs used in the gnl message policy between the kernel module and
83 * user space application. iwl_testmode_gnl_msg_policy is to be carried
84 * through the NL80211_CMD_TESTMODE channel regulated by nl80211.
85 * See iwl-testmode.h
86 */
87static
88struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = {
89 [IWL_TM_ATTR_COMMAND] = { .type = NLA_U32, },
90
91 [IWL_TM_ATTR_UCODE_CMD_ID] = { .type = NLA_U8, },
92 [IWL_TM_ATTR_UCODE_CMD_DATA] = { .type = NLA_UNSPEC, },
93
94 [IWL_TM_ATTR_REG_OFFSET] = { .type = NLA_U32, },
95 [IWL_TM_ATTR_REG_VALUE8] = { .type = NLA_U8, },
96 [IWL_TM_ATTR_REG_VALUE32] = { .type = NLA_U32, },
97
98 [IWL_TM_ATTR_SYNC_RSP] = { .type = NLA_UNSPEC, },
99 [IWL_TM_ATTR_UCODE_RX_PKT] = { .type = NLA_UNSPEC, },
100};
101
102/*
103 * See the struct iwl_rx_packet in iwl-commands.h for the format of the
104 * received events from the device
105 */
106static inline int get_event_length(struct iwl_rx_mem_buffer *rxb)
107{
108 struct iwl_rx_packet *pkt = rxb_addr(rxb);
109 if (pkt)
110 return le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
111 else
112 return 0;
113}
114
115
116/*
117 * This function multicasts the spontaneous messages from the device to the
118 * user space. It is invoked whenever there is a received messages
119 * from the device. This function is called within the ISR of the rx handlers
120 * in iwlagn driver.
121 *
122 * The parsing of the message content is left to the user space application,
123 * The message content is treated as unattacked raw data and is encapsulated
124 * with IWL_TM_ATTR_UCODE_RX_PKT multicasting to the user space.
125 *
126 * @priv: the instance of iwlwifi device
127 * @rxb: pointer to rx data content received by the ISR
128 *
129 * See the message policies and TLVs in iwl_testmode_gnl_msg_policy[].
130 * For the messages multicasting to the user application, the mandatory
131 * TLV fields are :
132 * IWL_TM_ATTR_COMMAND must be IWL_TM_CMD_DEV2APP_UCODE_RX_PKT
133 * IWL_TM_ATTR_UCODE_RX_PKT for carrying the message content
134 */
135
136static void iwl_testmode_ucode_rx_pkt(struct iwl_priv *priv,
137 struct iwl_rx_mem_buffer *rxb)
138{
139 struct ieee80211_hw *hw = priv->hw;
140 struct sk_buff *skb;
141 void *data;
142 int length;
143
144 data = (void *)rxb_addr(rxb);
145 length = get_event_length(rxb);
146
147 if (!data || length == 0)
148 return;
149
150 skb = cfg80211_testmode_alloc_event_skb(hw->wiphy, 20 + length,
151 GFP_ATOMIC);
152 if (skb == NULL) {
153 IWL_DEBUG_INFO(priv,
154 "Run out of memory for messages to user space ?\n");
155 return;
156 }
157 NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT);
158 NLA_PUT(skb, IWL_TM_ATTR_UCODE_RX_PKT, length, data);
159 cfg80211_testmode_event(skb, GFP_ATOMIC);
160 return;
161
162nla_put_failure:
163 kfree_skb(skb);
164 IWL_DEBUG_INFO(priv, "Ouch, overran buffer, check allocation!\n");
165}
166
167void iwl_testmode_init(struct iwl_priv *priv)
168{
169 priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;
170}
171
172/*
173 * This function handles the user application commands to the ucode.
174 *
175 * It retrieves the mandatory fields IWL_TM_ATTR_UCODE_CMD_ID and
176 * IWL_TM_ATTR_UCODE_CMD_DATA and calls to the handler to send the
177 * host command to the ucode.
178 *
179 * If any mandatory field is missing, -ENOMSG is replied to the user space
180 * application; otherwise, the actual execution result of the host command to
181 * ucode is replied.
182 *
183 * @hw: ieee80211_hw object that represents the device
184 * @tb: gnl message fields from the user space
185 */
186static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb)
187{
188 struct iwl_priv *priv = hw->priv;
189 struct iwl_host_cmd cmd;
190
191 memset(&cmd, 0, sizeof(struct iwl_host_cmd));
192
193 if (!tb[IWL_TM_ATTR_UCODE_CMD_ID] ||
194 !tb[IWL_TM_ATTR_UCODE_CMD_DATA]) {
195 IWL_DEBUG_INFO(priv,
196 "Error finding ucode command mandatory fields\n");
197 return -ENOMSG;
198 }
199
200 cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]);
201 cmd.data = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
202 cmd.len = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
203 IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x,"
204 " len %d\n", cmd.id, cmd.flags, cmd.len);
205 /* ok, let's submit the command to ucode */
206 return iwl_send_cmd(priv, &cmd);
207}
208
209
210/*
211 * This function handles the user application commands for register access.
212 *
213 * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
214 * handlers respectively.
215 *
216 * If it's an unknown commdn ID, -ENOSYS is returned; or -ENOMSG if the
217 * mandatory fields(IWL_TM_ATTR_REG_OFFSET,IWL_TM_ATTR_REG_VALUE32,
218 * IWL_TM_ATTR_REG_VALUE8) are missing; Otherwise 0 is replied indicating
219 * the success of the command execution.
220 *
221 * If IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_REG_READ32, the register read
222 * value is returned with IWL_TM_ATTR_REG_VALUE32.
223 *
224 * @hw: ieee80211_hw object that represents the device
225 * @tb: gnl message fields from the user space
226 */
227static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
228{
229 struct iwl_priv *priv = hw->priv;
230 u32 ofs, val32;
231 u8 val8;
232 struct sk_buff *skb;
233 int status = 0;
234
235 if (!tb[IWL_TM_ATTR_REG_OFFSET]) {
236 IWL_DEBUG_INFO(priv, "Error finding register offset\n");
237 return -ENOMSG;
238 }
239 ofs = nla_get_u32(tb[IWL_TM_ATTR_REG_OFFSET]);
240 IWL_INFO(priv, "testmode register access command offset 0x%x\n", ofs);
241
242 switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
243 case IWL_TM_CMD_APP2DEV_REG_READ32:
244 val32 = iwl_read32(priv, ofs);
245 IWL_INFO(priv, "32bit value to read 0x%x\n", val32);
246
247 skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
248 if (!skb) {
249 IWL_DEBUG_INFO(priv, "Error allocating memory\n");
250 return -ENOMEM;
251 }
252 NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32);
253 status = cfg80211_testmode_reply(skb);
254 if (status < 0)
255 IWL_DEBUG_INFO(priv,
256 "Error sending msg : %d\n", status);
257 break;
258 case IWL_TM_CMD_APP2DEV_REG_WRITE32:
259 if (!tb[IWL_TM_ATTR_REG_VALUE32]) {
260 IWL_DEBUG_INFO(priv,
261 "Error finding value to write\n");
262 return -ENOMSG;
263 } else {
264 val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]);
265 IWL_INFO(priv, "32bit value to write 0x%x\n", val32);
266 iwl_write32(priv, ofs, val32);
267 }
268 break;
269 case IWL_TM_CMD_APP2DEV_REG_WRITE8:
270 if (!tb[IWL_TM_ATTR_REG_VALUE8]) {
271 IWL_DEBUG_INFO(priv, "Error finding value to write\n");
272 return -ENOMSG;
273 } else {
274 val8 = nla_get_u8(tb[IWL_TM_ATTR_REG_VALUE8]);
275 IWL_INFO(priv, "8bit value to write 0x%x\n", val8);
276 iwl_write8(priv, ofs, val8);
277 }
278 break;
279 default:
280 IWL_DEBUG_INFO(priv, "Unknown testmode register command ID\n");
281 return -ENOSYS;
282 }
283
284 return status;
285
286nla_put_failure:
287 kfree_skb(skb);
288 return -EMSGSIZE;
289}
290
291
292static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv)
293{
294 struct iwl_notification_wait calib_wait;
295 int ret;
296
297 iwlagn_init_notification_wait(priv, &calib_wait,
298 CALIBRATION_COMPLETE_NOTIFICATION,
299 NULL, NULL);
300 ret = iwlagn_init_alive_start(priv);
301 if (ret) {
302 IWL_DEBUG_INFO(priv,
303 "Error configuring init calibration: %d\n", ret);
304 goto cfg_init_calib_error;
305 }
306
307 ret = iwlagn_wait_notification(priv, &calib_wait, 2 * HZ);
308 if (ret)
309 IWL_DEBUG_INFO(priv, "Error detecting"
310 " CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret);
311 return ret;
312
313cfg_init_calib_error:
314 iwlagn_remove_notification(priv, &calib_wait);
315 return ret;
316}
317
318/*
319 * This function handles the user application commands for driver.
320 *
321 * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
322 * handlers respectively.
323 *
324 * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned
325 * value of the actual command execution is replied to the user application.
326 *
327 * If there's any message responding to the user space, IWL_TM_ATTR_SYNC_RSP
328 * is used for carry the message while IWL_TM_ATTR_COMMAND must set to
329 * IWL_TM_CMD_DEV2APP_SYNC_RSP.
330 *
331 * @hw: ieee80211_hw object that represents the device
332 * @tb: gnl message fields from the user space
333 */
334static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
335{
336 struct iwl_priv *priv = hw->priv;
337 struct sk_buff *skb;
338 unsigned char *rsp_data_ptr = NULL;
339 int status = 0, rsp_data_len = 0;
340
341 switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
342 case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
343 rsp_data_ptr = (unsigned char *)priv->cfg->name;
344 rsp_data_len = strlen(priv->cfg->name);
345 skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
346 rsp_data_len + 20);
347 if (!skb) {
348 IWL_DEBUG_INFO(priv,
349 "Error allocating memory\n");
350 return -ENOMEM;
351 }
352 NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND,
353 IWL_TM_CMD_DEV2APP_SYNC_RSP);
354 NLA_PUT(skb, IWL_TM_ATTR_SYNC_RSP,
355 rsp_data_len, rsp_data_ptr);
356 status = cfg80211_testmode_reply(skb);
357 if (status < 0)
358 IWL_DEBUG_INFO(priv, "Error sending msg : %d\n",
359 status);
360 break;
361
362 case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
363 status = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init,
364 UCODE_SUBTYPE_INIT, -1);
365 if (status)
366 IWL_DEBUG_INFO(priv,
367 "Error loading init ucode: %d\n", status);
368 break;
369
370 case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
371 iwl_testmode_cfg_init_calib(priv);
372 iwlagn_stop_device(priv);
373 break;
374
375 case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
376 status = iwlagn_load_ucode_wait_alive(priv,
377 &priv->ucode_rt,
378 UCODE_SUBTYPE_REGULAR,
379 UCODE_SUBTYPE_REGULAR_NEW);
380 if (status) {
381 IWL_DEBUG_INFO(priv,
382 "Error loading runtime ucode: %d\n", status);
383 break;
384 }
385 status = iwl_alive_start(priv);
386 if (status)
387 IWL_DEBUG_INFO(priv,
388 "Error starting the device: %d\n", status);
389 break;
390
391 default:
392 IWL_DEBUG_INFO(priv, "Unknown testmode driver command ID\n");
393 return -ENOSYS;
394 }
395 return status;
396
397nla_put_failure:
398 kfree_skb(skb);
399 return -EMSGSIZE;
400}
401
402/* The testmode gnl message handler that takes the gnl message from the
403 * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then
404 * invoke the corresponding handlers.
405 *
406 * This function is invoked when there is user space application sending
407 * gnl message through the testmode tunnel NL80211_CMD_TESTMODE regulated
408 * by nl80211.
409 *
410 * It retrieves the mandatory field, IWL_TM_ATTR_COMMAND, before
411 * dispatching it to the corresponding handler.
412 *
413 * If IWL_TM_ATTR_COMMAND is missing, -ENOMSG is replied to user application;
414 * -ENOSYS is replied to the user application if the command is unknown;
415 * Otherwise, the command is dispatched to the respective handler.
416 *
417 * @hw: ieee80211_hw object that represents the device
418 * @data: pointer to user space message
419 * @len: length in byte of @data
420 */
421int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
422{
423 struct nlattr *tb[IWL_TM_ATTR_MAX - 1];
424 struct iwl_priv *priv = hw->priv;
425 int result;
426
427 result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len,
428 iwl_testmode_gnl_msg_policy);
429 if (result != 0) {
430 IWL_DEBUG_INFO(priv,
431 "Error parsing the gnl message : %d\n", result);
432 return result;
433 }
434
435 /* IWL_TM_ATTR_COMMAND is absolutely mandatory */
436 if (!tb[IWL_TM_ATTR_COMMAND]) {
437 IWL_DEBUG_INFO(priv, "Error finding testmode command type\n");
438 return -ENOMSG;
439 }
440 /* in case multiple accesses to the device happens */
441 mutex_lock(&priv->mutex);
442
443 switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
444 case IWL_TM_CMD_APP2DEV_UCODE:
445 IWL_DEBUG_INFO(priv, "testmode cmd to uCode\n");
446 result = iwl_testmode_ucode(hw, tb);
447 break;
448 case IWL_TM_CMD_APP2DEV_REG_READ32:
449 case IWL_TM_CMD_APP2DEV_REG_WRITE32:
450 case IWL_TM_CMD_APP2DEV_REG_WRITE8:
451 IWL_DEBUG_INFO(priv, "testmode cmd to register\n");
452 result = iwl_testmode_reg(hw, tb);
453 break;
454 case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
455 case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
456 case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
457 case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
458 IWL_DEBUG_INFO(priv, "testmode cmd to driver\n");
459 result = iwl_testmode_driver(hw, tb);
460 break;
461 default:
462 IWL_DEBUG_INFO(priv, "Unknown testmode command\n");
463 result = -ENOSYS;
464 break;
465 }
466
467 mutex_unlock(&priv->mutex);
468 return result;
469}
diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.h b/drivers/net/wireless/iwlwifi/iwl-testmode.h
new file mode 100644
index 000000000000..31f8949f2801
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-testmode.h
@@ -0,0 +1,151 @@
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 - 2011 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 - 2011 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#ifndef __IWL_TESTMODE_H__
64#define __IWL_TESTMODE_H__
65
66#include <linux/types.h>
67
68
69/* Commands from user space to kernel space(IWL_TM_CMD_ID_APP2DEV_XX) and
70 * from and kernel space to user space(IWL_TM_CMD_ID_DEV2APP_XX).
71 * The command ID is carried with IWL_TM_ATTR_COMMAND. There are three types of
72 * of command from user space and two types of command from kernel space.
73 * See below.
74 */
75enum iwl_tm_cmd_t {
76 /* commands from user application to the uCode,
77 * the actual uCode host command ID is carried with
78 * IWL_TM_ATTR_UCODE_CMD_ID */
79 IWL_TM_CMD_APP2DEV_UCODE = 1,
80
81 /* commands from user applicaiton to access register */
82 IWL_TM_CMD_APP2DEV_REG_READ32,
83 IWL_TM_CMD_APP2DEV_REG_WRITE32,
84 IWL_TM_CMD_APP2DEV_REG_WRITE8,
85
86 /* commands fom user space for pure driver level operations */
87 IWL_TM_CMD_APP2DEV_GET_DEVICENAME,
88 IWL_TM_CMD_APP2DEV_LOAD_INIT_FW,
89 IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB,
90 IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW,
91 /* if there is other new command for the driver layer operation,
92 * append them here */
93
94
95 /* commands from kernel space to carry the synchronous response
96 * to user application */
97 IWL_TM_CMD_DEV2APP_SYNC_RSP,
98
99 /* commands from kernel space to multicast the spontaneous messages
100 * to user application */
101 IWL_TM_CMD_DEV2APP_UCODE_RX_PKT,
102 IWL_TM_CMD_MAX,
103};
104
105enum iwl_tm_attr_t {
106 IWL_TM_ATTR_NOT_APPLICABLE = 0,
107
108 /* From user space to kernel space:
109 * the command either destines to ucode, driver, or register;
110 * See enum iwl_tm_cmd_t.
111 *
112 * From kernel space to user space:
113 * the command either carries synchronous response,
114 * or the spontaneous message multicast from the device;
115 * See enum iwl_tm_cmd_t. */
116 IWL_TM_ATTR_COMMAND,
117
118 /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE,
119 * The mandatory fields are :
120 * IWL_TM_ATTR_UCODE_CMD_ID for recognizable command ID;
121 * IWL_TM_ATTR_COMMAND_FLAG for the flags of the commands;
122 * The optional fields are:
123 * IWL_TM_ATTR_UCODE_CMD_DATA for the actual command payload
124 * to the ucode */
125 IWL_TM_ATTR_UCODE_CMD_ID,
126 IWL_TM_ATTR_UCODE_CMD_DATA,
127
128 /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_REG_XXX,
129 * The mandatory fields are:
130 * IWL_TM_ATTR_REG_OFFSET for the offset of the target register;
131 * IWL_TM_ATTR_REG_VALUE8 or IWL_TM_ATTR_REG_VALUE32 for value */
132 IWL_TM_ATTR_REG_OFFSET,
133 IWL_TM_ATTR_REG_VALUE8,
134 IWL_TM_ATTR_REG_VALUE32,
135
136 /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_SYNC_RSP,
137 * The mandatory fields are:
138 * IWL_TM_ATTR_SYNC_RSP for the data content responding to the user
139 * application command */
140 IWL_TM_ATTR_SYNC_RSP,
141 /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_UCODE_RX_PKT,
142 * The mandatory fields are:
143 * IWL_TM_ATTR_UCODE_RX_PKT for the data content multicast to the user
144 * application */
145 IWL_TM_ATTR_UCODE_RX_PKT,
146
147 IWL_TM_ATTR_MAX,
148};
149
150
151#endif