diff options
-rw-r--r-- | drivers/net/wireless/iwlwifi/Makefile | 6 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.h | 16 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-hcmd.c | 271 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans-int-pcie.h | 20 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c (renamed from drivers/net/wireless/iwlwifi/iwl-tx.c) | 244 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans.h | 4 |
7 files changed, 265 insertions, 299 deletions
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index d3c8e37ec153..1468e16855ec 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile | |||
@@ -5,8 +5,8 @@ iwlagn-objs += iwl-agn-ucode.o iwl-agn-tx.o | |||
5 | iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o | 5 | iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o |
6 | iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o | 6 | iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o |
7 | 7 | ||
8 | iwlagn-objs += iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o | 8 | iwlagn-objs += iwl-core.o iwl-eeprom.o iwl-power.o |
9 | iwlagn-objs += iwl-rx.o iwl-tx.o iwl-sta.o | 9 | iwlagn-objs += iwl-rx.o iwl-sta.o |
10 | iwlagn-objs += iwl-scan.o iwl-led.o | 10 | iwlagn-objs += iwl-scan.o iwl-led.o |
11 | iwlagn-objs += iwl-agn-rxon.o iwl-agn-ict.o | 11 | iwlagn-objs += iwl-agn-rxon.o iwl-agn-ict.o |
12 | iwlagn-objs += iwl-5000.o | 12 | iwlagn-objs += iwl-5000.o |
@@ -14,7 +14,7 @@ iwlagn-objs += iwl-6000.o | |||
14 | iwlagn-objs += iwl-1000.o | 14 | iwlagn-objs += iwl-1000.o |
15 | iwlagn-objs += iwl-2000.o | 15 | iwlagn-objs += iwl-2000.o |
16 | iwlagn-objs += iwl-pci.o | 16 | iwlagn-objs += iwl-pci.o |
17 | iwlagn-objs += iwl-trans.o iwl-trans-rx-pcie.o | 17 | iwlagn-objs += iwl-trans.o iwl-trans-rx-pcie.o iwl-trans-tx-pcie.o |
18 | 18 | ||
19 | iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o | 19 | iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o |
20 | iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o | 20 | iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 1655e5943694..0c4e14527df0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h | |||
@@ -189,9 +189,6 @@ void iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); | |||
189 | /* tx */ | 189 | /* tx */ |
190 | void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq, | 190 | void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq, |
191 | int index); | 191 | int index); |
192 | int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv, | ||
193 | struct iwl_tx_queue *txq, | ||
194 | dma_addr_t addr, u16 len, u8 reset); | ||
195 | void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, | 192 | void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, |
196 | struct ieee80211_tx_info *info); | 193 | struct ieee80211_tx_info *info); |
197 | int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb); | 194 | int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 711d2f61e2e6..c10ced58d357 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -336,18 +336,8 @@ static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx, | |||
336 | /***************************************************** | 336 | /***************************************************** |
337 | * RX | 337 | * RX |
338 | ******************************************************/ | 338 | ******************************************************/ |
339 | void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); | ||
340 | |||
341 | void iwl_chswitch_done(struct iwl_priv *priv, bool is_success); | 339 | void iwl_chswitch_done(struct iwl_priv *priv, bool is_success); |
342 | 340 | ||
343 | /* TX helpers */ | ||
344 | |||
345 | /***************************************************** | ||
346 | * TX | ||
347 | ******************************************************/ | ||
348 | void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); | ||
349 | int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, | ||
350 | int count, int slots_num, u32 id); | ||
351 | void iwl_setup_watchdog(struct iwl_priv *priv); | 341 | void iwl_setup_watchdog(struct iwl_priv *priv); |
352 | /***************************************************** | 342 | /***************************************************** |
353 | * TX power | 343 | * TX power |
@@ -398,12 +388,6 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv, | |||
398 | *****************************************************/ | 388 | *****************************************************/ |
399 | 389 | ||
400 | const char *get_cmd_string(u8 cmd); | 390 | const char *get_cmd_string(u8 cmd); |
401 | int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); | ||
402 | int __must_check iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u32 flags, | ||
403 | u16 len, const void *data); | ||
404 | |||
405 | int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); | ||
406 | |||
407 | void iwl_bg_watchdog(unsigned long data); | 391 | void iwl_bg_watchdog(unsigned long data); |
408 | u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval); | 392 | u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval); |
409 | __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base, | 393 | __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c deleted file mode 100644 index 6cff8c165ce9..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ /dev/null | |||
@@ -1,271 +0,0 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * GPL LICENSE SUMMARY | ||
4 | * | ||
5 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of version 2 of the GNU General Public License as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
19 | * USA | ||
20 | * | ||
21 | * The full GNU General Public License is included in this distribution | ||
22 | * in the file called LICENSE.GPL. | ||
23 | * | ||
24 | * Contact Information: | ||
25 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
26 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
27 | *****************************************************************************/ | ||
28 | |||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/sched.h> | ||
32 | #include <net/mac80211.h> | ||
33 | |||
34 | #include "iwl-dev.h" /* FIXME: remove */ | ||
35 | #include "iwl-debug.h" | ||
36 | #include "iwl-eeprom.h" | ||
37 | #include "iwl-core.h" | ||
38 | |||
39 | |||
40 | const char *get_cmd_string(u8 cmd) | ||
41 | { | ||
42 | switch (cmd) { | ||
43 | IWL_CMD(REPLY_ALIVE); | ||
44 | IWL_CMD(REPLY_ERROR); | ||
45 | IWL_CMD(REPLY_RXON); | ||
46 | IWL_CMD(REPLY_RXON_ASSOC); | ||
47 | IWL_CMD(REPLY_QOS_PARAM); | ||
48 | IWL_CMD(REPLY_RXON_TIMING); | ||
49 | IWL_CMD(REPLY_ADD_STA); | ||
50 | IWL_CMD(REPLY_REMOVE_STA); | ||
51 | IWL_CMD(REPLY_REMOVE_ALL_STA); | ||
52 | IWL_CMD(REPLY_TXFIFO_FLUSH); | ||
53 | IWL_CMD(REPLY_WEPKEY); | ||
54 | IWL_CMD(REPLY_TX); | ||
55 | IWL_CMD(REPLY_LEDS_CMD); | ||
56 | IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); | ||
57 | IWL_CMD(COEX_PRIORITY_TABLE_CMD); | ||
58 | IWL_CMD(COEX_MEDIUM_NOTIFICATION); | ||
59 | IWL_CMD(COEX_EVENT_CMD); | ||
60 | IWL_CMD(REPLY_QUIET_CMD); | ||
61 | IWL_CMD(REPLY_CHANNEL_SWITCH); | ||
62 | IWL_CMD(CHANNEL_SWITCH_NOTIFICATION); | ||
63 | IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD); | ||
64 | IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION); | ||
65 | IWL_CMD(POWER_TABLE_CMD); | ||
66 | IWL_CMD(PM_SLEEP_NOTIFICATION); | ||
67 | IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC); | ||
68 | IWL_CMD(REPLY_SCAN_CMD); | ||
69 | IWL_CMD(REPLY_SCAN_ABORT_CMD); | ||
70 | IWL_CMD(SCAN_START_NOTIFICATION); | ||
71 | IWL_CMD(SCAN_RESULTS_NOTIFICATION); | ||
72 | IWL_CMD(SCAN_COMPLETE_NOTIFICATION); | ||
73 | IWL_CMD(BEACON_NOTIFICATION); | ||
74 | IWL_CMD(REPLY_TX_BEACON); | ||
75 | IWL_CMD(WHO_IS_AWAKE_NOTIFICATION); | ||
76 | IWL_CMD(QUIET_NOTIFICATION); | ||
77 | IWL_CMD(REPLY_TX_PWR_TABLE_CMD); | ||
78 | IWL_CMD(MEASURE_ABORT_NOTIFICATION); | ||
79 | IWL_CMD(REPLY_BT_CONFIG); | ||
80 | IWL_CMD(REPLY_STATISTICS_CMD); | ||
81 | IWL_CMD(STATISTICS_NOTIFICATION); | ||
82 | IWL_CMD(REPLY_CARD_STATE_CMD); | ||
83 | IWL_CMD(CARD_STATE_NOTIFICATION); | ||
84 | IWL_CMD(MISSED_BEACONS_NOTIFICATION); | ||
85 | IWL_CMD(REPLY_CT_KILL_CONFIG_CMD); | ||
86 | IWL_CMD(SENSITIVITY_CMD); | ||
87 | IWL_CMD(REPLY_PHY_CALIBRATION_CMD); | ||
88 | IWL_CMD(REPLY_RX_PHY_CMD); | ||
89 | IWL_CMD(REPLY_RX_MPDU_CMD); | ||
90 | IWL_CMD(REPLY_RX); | ||
91 | IWL_CMD(REPLY_COMPRESSED_BA); | ||
92 | IWL_CMD(CALIBRATION_CFG_CMD); | ||
93 | IWL_CMD(CALIBRATION_RES_NOTIFICATION); | ||
94 | IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION); | ||
95 | IWL_CMD(REPLY_TX_POWER_DBM_CMD); | ||
96 | IWL_CMD(TEMPERATURE_NOTIFICATION); | ||
97 | IWL_CMD(TX_ANT_CONFIGURATION_CMD); | ||
98 | IWL_CMD(REPLY_BT_COEX_PROFILE_NOTIF); | ||
99 | IWL_CMD(REPLY_BT_COEX_PRIO_TABLE); | ||
100 | IWL_CMD(REPLY_BT_COEX_PROT_ENV); | ||
101 | IWL_CMD(REPLY_WIPAN_PARAMS); | ||
102 | IWL_CMD(REPLY_WIPAN_RXON); | ||
103 | IWL_CMD(REPLY_WIPAN_RXON_TIMING); | ||
104 | IWL_CMD(REPLY_WIPAN_RXON_ASSOC); | ||
105 | IWL_CMD(REPLY_WIPAN_QOS_PARAM); | ||
106 | IWL_CMD(REPLY_WIPAN_WEPKEY); | ||
107 | IWL_CMD(REPLY_WIPAN_P2P_CHANNEL_SWITCH); | ||
108 | IWL_CMD(REPLY_WIPAN_NOA_NOTIFICATION); | ||
109 | IWL_CMD(REPLY_WIPAN_DEACTIVATION_COMPLETE); | ||
110 | default: | ||
111 | return "UNKNOWN"; | ||
112 | |||
113 | } | ||
114 | } | ||
115 | |||
116 | #define HOST_COMPLETE_TIMEOUT (2 * HZ) | ||
117 | |||
118 | static void iwl_generic_cmd_callback(struct iwl_priv *priv, | ||
119 | struct iwl_device_cmd *cmd, | ||
120 | struct iwl_rx_packet *pkt) | ||
121 | { | ||
122 | if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { | ||
123 | IWL_ERR(priv, "Bad return from %s (0x%08X)\n", | ||
124 | get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); | ||
125 | return; | ||
126 | } | ||
127 | |||
128 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
129 | switch (cmd->hdr.cmd) { | ||
130 | case REPLY_TX_LINK_QUALITY_CMD: | ||
131 | case SENSITIVITY_CMD: | ||
132 | IWL_DEBUG_HC_DUMP(priv, "back from %s (0x%08X)\n", | ||
133 | get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); | ||
134 | break; | ||
135 | default: | ||
136 | IWL_DEBUG_HC(priv, "back from %s (0x%08X)\n", | ||
137 | get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); | ||
138 | } | ||
139 | #endif | ||
140 | } | ||
141 | |||
142 | static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | ||
143 | { | ||
144 | int ret; | ||
145 | |||
146 | /* An asynchronous command can not expect an SKB to be set. */ | ||
147 | if (WARN_ON(cmd->flags & CMD_WANT_SKB)) | ||
148 | return -EINVAL; | ||
149 | |||
150 | /* Assign a generic callback if one is not provided */ | ||
151 | if (!cmd->callback) | ||
152 | cmd->callback = iwl_generic_cmd_callback; | ||
153 | |||
154 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | ||
155 | return -EBUSY; | ||
156 | |||
157 | ret = iwl_enqueue_hcmd(priv, cmd); | ||
158 | if (ret < 0) { | ||
159 | IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n", | ||
160 | get_cmd_string(cmd->id), ret); | ||
161 | return ret; | ||
162 | } | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | ||
167 | { | ||
168 | int cmd_idx; | ||
169 | int ret; | ||
170 | |||
171 | lockdep_assert_held(&priv->mutex); | ||
172 | |||
173 | /* A synchronous command can not have a callback set. */ | ||
174 | if (WARN_ON(cmd->callback)) | ||
175 | return -EINVAL; | ||
176 | |||
177 | IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n", | ||
178 | get_cmd_string(cmd->id)); | ||
179 | |||
180 | set_bit(STATUS_HCMD_ACTIVE, &priv->status); | ||
181 | IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n", | ||
182 | get_cmd_string(cmd->id)); | ||
183 | |||
184 | cmd_idx = iwl_enqueue_hcmd(priv, cmd); | ||
185 | if (cmd_idx < 0) { | ||
186 | ret = cmd_idx; | ||
187 | clear_bit(STATUS_HCMD_ACTIVE, &priv->status); | ||
188 | IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n", | ||
189 | get_cmd_string(cmd->id), ret); | ||
190 | return ret; | ||
191 | } | ||
192 | |||
193 | ret = wait_event_interruptible_timeout(priv->wait_command_queue, | ||
194 | !test_bit(STATUS_HCMD_ACTIVE, &priv->status), | ||
195 | HOST_COMPLETE_TIMEOUT); | ||
196 | if (!ret) { | ||
197 | if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) { | ||
198 | IWL_ERR(priv, | ||
199 | "Error sending %s: time out after %dms.\n", | ||
200 | get_cmd_string(cmd->id), | ||
201 | jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); | ||
202 | |||
203 | clear_bit(STATUS_HCMD_ACTIVE, &priv->status); | ||
204 | IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s\n", | ||
205 | get_cmd_string(cmd->id)); | ||
206 | ret = -ETIMEDOUT; | ||
207 | goto cancel; | ||
208 | } | ||
209 | } | ||
210 | |||
211 | if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { | ||
212 | IWL_ERR(priv, "Command %s aborted: RF KILL Switch\n", | ||
213 | get_cmd_string(cmd->id)); | ||
214 | ret = -ECANCELED; | ||
215 | goto fail; | ||
216 | } | ||
217 | if (test_bit(STATUS_FW_ERROR, &priv->status)) { | ||
218 | IWL_ERR(priv, "Command %s failed: FW Error\n", | ||
219 | get_cmd_string(cmd->id)); | ||
220 | ret = -EIO; | ||
221 | goto fail; | ||
222 | } | ||
223 | if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_page) { | ||
224 | IWL_ERR(priv, "Error: Response NULL in '%s'\n", | ||
225 | get_cmd_string(cmd->id)); | ||
226 | ret = -EIO; | ||
227 | goto cancel; | ||
228 | } | ||
229 | |||
230 | return 0; | ||
231 | |||
232 | cancel: | ||
233 | if (cmd->flags & CMD_WANT_SKB) { | ||
234 | /* | ||
235 | * Cancel the CMD_WANT_SKB flag for the cmd in the | ||
236 | * TX cmd queue. Otherwise in case the cmd comes | ||
237 | * in later, it will possibly set an invalid | ||
238 | * address (cmd->meta.source). | ||
239 | */ | ||
240 | priv->txq[priv->cmd_queue].meta[cmd_idx].flags &= | ||
241 | ~CMD_WANT_SKB; | ||
242 | } | ||
243 | fail: | ||
244 | if (cmd->reply_page) { | ||
245 | iwl_free_pages(priv, cmd->reply_page); | ||
246 | cmd->reply_page = 0; | ||
247 | } | ||
248 | |||
249 | return ret; | ||
250 | } | ||
251 | |||
252 | int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | ||
253 | { | ||
254 | if (cmd->flags & CMD_ASYNC) | ||
255 | return iwl_send_cmd_async(priv, cmd); | ||
256 | |||
257 | return iwl_send_cmd_sync(priv, cmd); | ||
258 | } | ||
259 | |||
260 | int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u32 flags, u16 len, | ||
261 | const void *data) | ||
262 | { | ||
263 | struct iwl_host_cmd cmd = { | ||
264 | .id = id, | ||
265 | .len = { len, }, | ||
266 | .data = { data, }, | ||
267 | .flags = flags, | ||
268 | }; | ||
269 | |||
270 | return iwl_send_cmd(priv, &cmd); | ||
271 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-int-pcie.h b/drivers/net/wireless/iwlwifi/iwl-trans-int-pcie.h index 6c56a3f75411..8307064182e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-int-pcie.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans-int-pcie.h | |||
@@ -32,11 +32,31 @@ | |||
32 | /*This file includes the declaration that are internal to the | 32 | /*This file includes the declaration that are internal to the |
33 | * trans_pcie layer */ | 33 | * trans_pcie layer */ |
34 | 34 | ||
35 | /***************************************************** | ||
36 | * RX | ||
37 | ******************************************************/ | ||
35 | void iwl_bg_rx_replenish(struct work_struct *data); | 38 | void iwl_bg_rx_replenish(struct work_struct *data); |
36 | void iwl_irq_tasklet(struct iwl_priv *priv); | 39 | void iwl_irq_tasklet(struct iwl_priv *priv); |
37 | void iwlagn_rx_replenish(struct iwl_priv *priv); | 40 | void iwlagn_rx_replenish(struct iwl_priv *priv); |
38 | void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, | 41 | void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, |
39 | struct iwl_rx_queue *q); | 42 | struct iwl_rx_queue *q); |
40 | 43 | ||
44 | /***************************************************** | ||
45 | * TX / HCMD | ||
46 | ******************************************************/ | ||
47 | void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); | ||
48 | void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq, | ||
49 | int index); | ||
50 | int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv, | ||
51 | struct iwl_tx_queue *txq, | ||
52 | dma_addr_t addr, u16 len, u8 reset); | ||
53 | int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, | ||
54 | int count, int slots_num, u32 id); | ||
55 | int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); | ||
56 | int __must_check iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u32 flags, | ||
57 | u16 len, const void *data); | ||
58 | void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); | ||
59 | |||
60 | |||
41 | #endif /* __iwl_trans_int_pcie_h__ */ | 61 | #endif /* __iwl_trans_int_pcie_h__ */ |
42 | 62 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c index 9b07e07f1689..f3b531b34475 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c | |||
@@ -26,18 +26,17 @@ | |||
26 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | 26 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 |
27 | * | 27 | * |
28 | *****************************************************************************/ | 28 | *****************************************************************************/ |
29 | |||
30 | #include <linux/etherdevice.h> | 29 | #include <linux/etherdevice.h> |
31 | #include <linux/sched.h> | ||
32 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | #include <linux/sched.h> | ||
33 | #include <net/mac80211.h> | 32 | #include <net/mac80211.h> |
34 | #include "iwl-eeprom.h" | 33 | |
35 | #include "iwl-agn.h" | 34 | #include "iwl-agn.h" |
36 | #include "iwl-dev.h" | 35 | #include "iwl-dev.h" |
37 | #include "iwl-core.h" | 36 | #include "iwl-core.h" |
38 | #include "iwl-sta.h" | ||
39 | #include "iwl-io.h" | 37 | #include "iwl-io.h" |
40 | #include "iwl-helpers.h" | 38 | #include "iwl-helpers.h" |
39 | #include "iwl-trans-int-pcie.h" | ||
41 | 40 | ||
42 | /** | 41 | /** |
43 | * iwl_txq_update_write_ptr - Send new write index to hardware | 42 | * iwl_txq_update_write_ptr - Send new write index to hardware |
@@ -126,7 +125,7 @@ static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd) | |||
126 | } | 125 | } |
127 | 126 | ||
128 | static void iwlagn_unmap_tfd(struct iwl_priv *priv, struct iwl_cmd_meta *meta, | 127 | static void iwlagn_unmap_tfd(struct iwl_priv *priv, struct iwl_cmd_meta *meta, |
129 | struct iwl_tfd *tfd, enum dma_data_direction dma_dir) | 128 | struct iwl_tfd *tfd, enum dma_data_direction dma_dir) |
130 | { | 129 | { |
131 | int i; | 130 | int i; |
132 | int num_tbs; | 131 | int num_tbs; |
@@ -303,7 +302,7 @@ int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, | |||
303 | * failed. On success, it turns the index (> 0) of command in the | 302 | * failed. On success, it turns the index (> 0) of command in the |
304 | * command queue. | 303 | * command queue. |
305 | */ | 304 | */ |
306 | int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | 305 | static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) |
307 | { | 306 | { |
308 | struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; | 307 | struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; |
309 | struct iwl_queue *q = &txq->q; | 308 | struct iwl_queue *q = &txq->q; |
@@ -574,3 +573,236 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) | |||
574 | 573 | ||
575 | spin_unlock_irqrestore(&priv->hcmd_lock, flags); | 574 | spin_unlock_irqrestore(&priv->hcmd_lock, flags); |
576 | } | 575 | } |
576 | |||
577 | const char *get_cmd_string(u8 cmd) | ||
578 | { | ||
579 | switch (cmd) { | ||
580 | IWL_CMD(REPLY_ALIVE); | ||
581 | IWL_CMD(REPLY_ERROR); | ||
582 | IWL_CMD(REPLY_RXON); | ||
583 | IWL_CMD(REPLY_RXON_ASSOC); | ||
584 | IWL_CMD(REPLY_QOS_PARAM); | ||
585 | IWL_CMD(REPLY_RXON_TIMING); | ||
586 | IWL_CMD(REPLY_ADD_STA); | ||
587 | IWL_CMD(REPLY_REMOVE_STA); | ||
588 | IWL_CMD(REPLY_REMOVE_ALL_STA); | ||
589 | IWL_CMD(REPLY_TXFIFO_FLUSH); | ||
590 | IWL_CMD(REPLY_WEPKEY); | ||
591 | IWL_CMD(REPLY_TX); | ||
592 | IWL_CMD(REPLY_LEDS_CMD); | ||
593 | IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); | ||
594 | IWL_CMD(COEX_PRIORITY_TABLE_CMD); | ||
595 | IWL_CMD(COEX_MEDIUM_NOTIFICATION); | ||
596 | IWL_CMD(COEX_EVENT_CMD); | ||
597 | IWL_CMD(REPLY_QUIET_CMD); | ||
598 | IWL_CMD(REPLY_CHANNEL_SWITCH); | ||
599 | IWL_CMD(CHANNEL_SWITCH_NOTIFICATION); | ||
600 | IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD); | ||
601 | IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION); | ||
602 | IWL_CMD(POWER_TABLE_CMD); | ||
603 | IWL_CMD(PM_SLEEP_NOTIFICATION); | ||
604 | IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC); | ||
605 | IWL_CMD(REPLY_SCAN_CMD); | ||
606 | IWL_CMD(REPLY_SCAN_ABORT_CMD); | ||
607 | IWL_CMD(SCAN_START_NOTIFICATION); | ||
608 | IWL_CMD(SCAN_RESULTS_NOTIFICATION); | ||
609 | IWL_CMD(SCAN_COMPLETE_NOTIFICATION); | ||
610 | IWL_CMD(BEACON_NOTIFICATION); | ||
611 | IWL_CMD(REPLY_TX_BEACON); | ||
612 | IWL_CMD(WHO_IS_AWAKE_NOTIFICATION); | ||
613 | IWL_CMD(QUIET_NOTIFICATION); | ||
614 | IWL_CMD(REPLY_TX_PWR_TABLE_CMD); | ||
615 | IWL_CMD(MEASURE_ABORT_NOTIFICATION); | ||
616 | IWL_CMD(REPLY_BT_CONFIG); | ||
617 | IWL_CMD(REPLY_STATISTICS_CMD); | ||
618 | IWL_CMD(STATISTICS_NOTIFICATION); | ||
619 | IWL_CMD(REPLY_CARD_STATE_CMD); | ||
620 | IWL_CMD(CARD_STATE_NOTIFICATION); | ||
621 | IWL_CMD(MISSED_BEACONS_NOTIFICATION); | ||
622 | IWL_CMD(REPLY_CT_KILL_CONFIG_CMD); | ||
623 | IWL_CMD(SENSITIVITY_CMD); | ||
624 | IWL_CMD(REPLY_PHY_CALIBRATION_CMD); | ||
625 | IWL_CMD(REPLY_RX_PHY_CMD); | ||
626 | IWL_CMD(REPLY_RX_MPDU_CMD); | ||
627 | IWL_CMD(REPLY_RX); | ||
628 | IWL_CMD(REPLY_COMPRESSED_BA); | ||
629 | IWL_CMD(CALIBRATION_CFG_CMD); | ||
630 | IWL_CMD(CALIBRATION_RES_NOTIFICATION); | ||
631 | IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION); | ||
632 | IWL_CMD(REPLY_TX_POWER_DBM_CMD); | ||
633 | IWL_CMD(TEMPERATURE_NOTIFICATION); | ||
634 | IWL_CMD(TX_ANT_CONFIGURATION_CMD); | ||
635 | IWL_CMD(REPLY_BT_COEX_PROFILE_NOTIF); | ||
636 | IWL_CMD(REPLY_BT_COEX_PRIO_TABLE); | ||
637 | IWL_CMD(REPLY_BT_COEX_PROT_ENV); | ||
638 | IWL_CMD(REPLY_WIPAN_PARAMS); | ||
639 | IWL_CMD(REPLY_WIPAN_RXON); | ||
640 | IWL_CMD(REPLY_WIPAN_RXON_TIMING); | ||
641 | IWL_CMD(REPLY_WIPAN_RXON_ASSOC); | ||
642 | IWL_CMD(REPLY_WIPAN_QOS_PARAM); | ||
643 | IWL_CMD(REPLY_WIPAN_WEPKEY); | ||
644 | IWL_CMD(REPLY_WIPAN_P2P_CHANNEL_SWITCH); | ||
645 | IWL_CMD(REPLY_WIPAN_NOA_NOTIFICATION); | ||
646 | IWL_CMD(REPLY_WIPAN_DEACTIVATION_COMPLETE); | ||
647 | default: | ||
648 | return "UNKNOWN"; | ||
649 | |||
650 | } | ||
651 | } | ||
652 | |||
653 | #define HOST_COMPLETE_TIMEOUT (2 * HZ) | ||
654 | |||
655 | static void iwl_generic_cmd_callback(struct iwl_priv *priv, | ||
656 | struct iwl_device_cmd *cmd, | ||
657 | struct iwl_rx_packet *pkt) | ||
658 | { | ||
659 | if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { | ||
660 | IWL_ERR(priv, "Bad return from %s (0x%08X)\n", | ||
661 | get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); | ||
662 | return; | ||
663 | } | ||
664 | |||
665 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
666 | switch (cmd->hdr.cmd) { | ||
667 | case REPLY_TX_LINK_QUALITY_CMD: | ||
668 | case SENSITIVITY_CMD: | ||
669 | IWL_DEBUG_HC_DUMP(priv, "back from %s (0x%08X)\n", | ||
670 | get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); | ||
671 | break; | ||
672 | default: | ||
673 | IWL_DEBUG_HC(priv, "back from %s (0x%08X)\n", | ||
674 | get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); | ||
675 | } | ||
676 | #endif | ||
677 | } | ||
678 | |||
679 | static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | ||
680 | { | ||
681 | int ret; | ||
682 | |||
683 | /* An asynchronous command can not expect an SKB to be set. */ | ||
684 | if (WARN_ON(cmd->flags & CMD_WANT_SKB)) | ||
685 | return -EINVAL; | ||
686 | |||
687 | /* Assign a generic callback if one is not provided */ | ||
688 | if (!cmd->callback) | ||
689 | cmd->callback = iwl_generic_cmd_callback; | ||
690 | |||
691 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | ||
692 | return -EBUSY; | ||
693 | |||
694 | ret = iwl_enqueue_hcmd(priv, cmd); | ||
695 | if (ret < 0) { | ||
696 | IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n", | ||
697 | get_cmd_string(cmd->id), ret); | ||
698 | return ret; | ||
699 | } | ||
700 | return 0; | ||
701 | } | ||
702 | |||
703 | static int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | ||
704 | { | ||
705 | int cmd_idx; | ||
706 | int ret; | ||
707 | |||
708 | lockdep_assert_held(&priv->mutex); | ||
709 | |||
710 | /* A synchronous command can not have a callback set. */ | ||
711 | if (WARN_ON(cmd->callback)) | ||
712 | return -EINVAL; | ||
713 | |||
714 | IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n", | ||
715 | get_cmd_string(cmd->id)); | ||
716 | |||
717 | set_bit(STATUS_HCMD_ACTIVE, &priv->status); | ||
718 | IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n", | ||
719 | get_cmd_string(cmd->id)); | ||
720 | |||
721 | cmd_idx = iwl_enqueue_hcmd(priv, cmd); | ||
722 | if (cmd_idx < 0) { | ||
723 | ret = cmd_idx; | ||
724 | clear_bit(STATUS_HCMD_ACTIVE, &priv->status); | ||
725 | IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n", | ||
726 | get_cmd_string(cmd->id), ret); | ||
727 | return ret; | ||
728 | } | ||
729 | |||
730 | ret = wait_event_interruptible_timeout(priv->wait_command_queue, | ||
731 | !test_bit(STATUS_HCMD_ACTIVE, &priv->status), | ||
732 | HOST_COMPLETE_TIMEOUT); | ||
733 | if (!ret) { | ||
734 | if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) { | ||
735 | IWL_ERR(priv, | ||
736 | "Error sending %s: time out after %dms.\n", | ||
737 | get_cmd_string(cmd->id), | ||
738 | jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); | ||
739 | |||
740 | clear_bit(STATUS_HCMD_ACTIVE, &priv->status); | ||
741 | IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command" | ||
742 | "%s\n", get_cmd_string(cmd->id)); | ||
743 | ret = -ETIMEDOUT; | ||
744 | goto cancel; | ||
745 | } | ||
746 | } | ||
747 | |||
748 | if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { | ||
749 | IWL_ERR(priv, "Command %s aborted: RF KILL Switch\n", | ||
750 | get_cmd_string(cmd->id)); | ||
751 | ret = -ECANCELED; | ||
752 | goto fail; | ||
753 | } | ||
754 | if (test_bit(STATUS_FW_ERROR, &priv->status)) { | ||
755 | IWL_ERR(priv, "Command %s failed: FW Error\n", | ||
756 | get_cmd_string(cmd->id)); | ||
757 | ret = -EIO; | ||
758 | goto fail; | ||
759 | } | ||
760 | if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_page) { | ||
761 | IWL_ERR(priv, "Error: Response NULL in '%s'\n", | ||
762 | get_cmd_string(cmd->id)); | ||
763 | ret = -EIO; | ||
764 | goto cancel; | ||
765 | } | ||
766 | |||
767 | return 0; | ||
768 | |||
769 | cancel: | ||
770 | if (cmd->flags & CMD_WANT_SKB) { | ||
771 | /* | ||
772 | * Cancel the CMD_WANT_SKB flag for the cmd in the | ||
773 | * TX cmd queue. Otherwise in case the cmd comes | ||
774 | * in later, it will possibly set an invalid | ||
775 | * address (cmd->meta.source). | ||
776 | */ | ||
777 | priv->txq[priv->cmd_queue].meta[cmd_idx].flags &= | ||
778 | ~CMD_WANT_SKB; | ||
779 | } | ||
780 | fail: | ||
781 | if (cmd->reply_page) { | ||
782 | iwl_free_pages(priv, cmd->reply_page); | ||
783 | cmd->reply_page = 0; | ||
784 | } | ||
785 | |||
786 | return ret; | ||
787 | } | ||
788 | |||
789 | int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | ||
790 | { | ||
791 | if (cmd->flags & CMD_ASYNC) | ||
792 | return iwl_send_cmd_async(priv, cmd); | ||
793 | |||
794 | return iwl_send_cmd_sync(priv, cmd); | ||
795 | } | ||
796 | |||
797 | int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u32 flags, u16 len, | ||
798 | const void *data) | ||
799 | { | ||
800 | struct iwl_host_cmd cmd = { | ||
801 | .id = id, | ||
802 | .len = { len, }, | ||
803 | .data = { data, }, | ||
804 | .flags = flags, | ||
805 | }; | ||
806 | |||
807 | return iwl_send_cmd(priv, &cmd); | ||
808 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 886730ecf309..8293f54e0390 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h | |||
@@ -60,6 +60,10 @@ | |||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
61 | * | 61 | * |
62 | *****************************************************************************/ | 62 | *****************************************************************************/ |
63 | |||
64 | /*This file includes the declaration that are exported from the transport | ||
65 | * layer */ | ||
66 | |||
63 | static inline int trans_rx_init(struct iwl_priv *priv) | 67 | static inline int trans_rx_init(struct iwl_priv *priv) |
64 | { | 68 | { |
65 | return priv->trans.ops->rx_init(priv); | 69 | return priv->trans.ops->rx_init(priv); |