diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/iwlwifi/Kconfig | 10 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-ucode.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.h | 17 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sv-open.c | 469 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-testmode.h | 151 |
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. |
103 | endmenu | 103 | endmenu |
104 | 104 | ||
105 | config 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 | |||
105 | config IWL_P2P | 115 | config 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 | ||
17 | iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o | 17 | iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o |
18 | iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o | 18 | iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o |
19 | iwlagn-$(CONFIG_IWLWIFI_DEVICE_SVTOOL) += iwl-sv-open.o | ||
19 | 20 | ||
20 | CFLAGS_iwl-devtrace.o := -I$(src) | 21 | CFLAGS_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 | ||
272 | static int iwlagn_init_alive_start(struct iwl_priv *priv) | 272 | int 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 | */ |
2214 | static int iwl_alive_start(struct iwl_priv *priv) | 2216 | int 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 | ||
3512 | static u32 iwl_hw_detect(struct iwl_priv *priv) | 3515 | static 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, | |||
344 | void __releases(wait_entry) | 344 | void __releases(wait_entry) |
345 | iwlagn_remove_notification(struct iwl_priv *priv, | 345 | iwlagn_remove_notification(struct iwl_priv *priv, |
346 | struct iwl_notification_wait *wait_entry); | 346 | struct iwl_notification_wait *wait_entry); |
347 | extern int iwlagn_init_alive_start(struct iwl_priv *priv); | ||
348 | extern int iwl_alive_start(struct iwl_priv *priv); | ||
349 | /* svtool */ | ||
350 | #ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL | ||
351 | extern int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len); | ||
352 | extern void iwl_testmode_init(struct iwl_priv *priv); | ||
353 | #else | ||
354 | static inline | ||
355 | int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) | ||
356 | { | ||
357 | return -ENOSYS; | ||
358 | } | ||
359 | static inline | ||
360 | void 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 | */ | ||
87 | static | ||
88 | struct 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 | */ | ||
106 | static 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 | |||
136 | static 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 | |||
162 | nla_put_failure: | ||
163 | kfree_skb(skb); | ||
164 | IWL_DEBUG_INFO(priv, "Ouch, overran buffer, check allocation!\n"); | ||
165 | } | ||
166 | |||
167 | void 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 | */ | ||
186 | static 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 | */ | ||
227 | static 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 | |||
286 | nla_put_failure: | ||
287 | kfree_skb(skb); | ||
288 | return -EMSGSIZE; | ||
289 | } | ||
290 | |||
291 | |||
292 | static 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 | |||
313 | cfg_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 | */ | ||
334 | static 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 | |||
397 | nla_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 | */ | ||
421 | int 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 | */ | ||
75 | enum 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 | |||
105 | enum 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 | ||