blob: e63777b2f6e9ae3c1e0a107e4c2f545f64f38c6c [file] [log] [blame]
Wey-Yi Guybe663ab2011-02-21 11:27:26 -08001/******************************************************************************
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"
35#include "iwl-debug.h"
36#include "iwl-eeprom.h"
37#include "iwl-core.h"
38
39
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +020040const char *il_get_cmd_string(u8 cmd)
Wey-Yi Guybe663ab2011-02-21 11:27:26 -080041{
42 switch (cmd) {
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +020043 IL_CMD(REPLY_ALIVE);
44 IL_CMD(REPLY_ERROR);
45 IL_CMD(REPLY_RXON);
46 IL_CMD(REPLY_RXON_ASSOC);
47 IL_CMD(REPLY_QOS_PARAM);
48 IL_CMD(REPLY_RXON_TIMING);
49 IL_CMD(REPLY_ADD_STA);
50 IL_CMD(REPLY_REMOVE_STA);
51 IL_CMD(REPLY_WEPKEY);
52 IL_CMD(REPLY_3945_RX);
53 IL_CMD(REPLY_TX);
54 IL_CMD(REPLY_RATE_SCALE);
55 IL_CMD(REPLY_LEDS_CMD);
56 IL_CMD(REPLY_TX_LINK_QUALITY_CMD);
57 IL_CMD(REPLY_CHANNEL_SWITCH);
58 IL_CMD(CHANNEL_SWITCH_NOTIFICATION);
59 IL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD);
60 IL_CMD(SPECTRUM_MEASURE_NOTIFICATION);
61 IL_CMD(POWER_TABLE_CMD);
62 IL_CMD(PM_SLEEP_NOTIFICATION);
63 IL_CMD(PM_DEBUG_STATISTIC_NOTIFIC);
64 IL_CMD(REPLY_SCAN_CMD);
65 IL_CMD(REPLY_SCAN_ABORT_CMD);
66 IL_CMD(SCAN_START_NOTIFICATION);
67 IL_CMD(SCAN_RESULTS_NOTIFICATION);
68 IL_CMD(SCAN_COMPLETE_NOTIFICATION);
69 IL_CMD(BEACON_NOTIFICATION);
70 IL_CMD(REPLY_TX_BEACON);
71 IL_CMD(REPLY_TX_PWR_TABLE_CMD);
72 IL_CMD(REPLY_BT_CONFIG);
73 IL_CMD(REPLY_STATISTICS_CMD);
74 IL_CMD(STATISTICS_NOTIFICATION);
75 IL_CMD(CARD_STATE_NOTIFICATION);
76 IL_CMD(MISSED_BEACONS_NOTIFICATION);
77 IL_CMD(REPLY_CT_KILL_CONFIG_CMD);
78 IL_CMD(SENSITIVITY_CMD);
79 IL_CMD(REPLY_PHY_CALIBRATION_CMD);
80 IL_CMD(REPLY_RX_PHY_CMD);
81 IL_CMD(REPLY_RX_MPDU_CMD);
82 IL_CMD(REPLY_RX);
83 IL_CMD(REPLY_COMPRESSED_BA);
Wey-Yi Guybe663ab2011-02-21 11:27:26 -080084 default:
85 return "UNKNOWN";
86
87 }
88}
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +020089EXPORT_SYMBOL(il_get_cmd_string);
Wey-Yi Guybe663ab2011-02-21 11:27:26 -080090
91#define HOST_COMPLETE_TIMEOUT (HZ / 2)
92
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +020093static void il_generic_cmd_callback(struct il_priv *il,
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +020094 struct il_device_cmd *cmd,
Stanislaw Gruszkadcae1c62011-08-26 14:36:21 +020095 struct il_rx_pkt *pkt)
Wey-Yi Guybe663ab2011-02-21 11:27:26 -080096{
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +020097 if (pkt->hdr.flags & IL_CMD_FAILED_MSK) {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +020098 IL_ERR("Bad return from %s (0x%08X)\n",
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +020099 il_get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800100 return;
101 }
102
Stanislaw Gruszkad3175162011-11-15 11:25:42 +0100103#ifdef CONFIG_IWLEGACY_DEBUG
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800104 switch (cmd->hdr.cmd) {
105 case REPLY_TX_LINK_QUALITY_CMD:
106 case SENSITIVITY_CMD:
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +0100107 D_HC_DUMP("back from %s (0x%08X)\n",
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200108 il_get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800109 break;
110 default:
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +0100111 D_HC("back from %s (0x%08X)\n",
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200112 il_get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800113 }
114#endif
115}
116
117static int
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200118il_send_cmd_async(struct il_priv *il, struct il_host_cmd *cmd)
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800119{
120 int ret;
121
122 BUG_ON(!(cmd->flags & CMD_ASYNC));
123
124 /* An asynchronous command can not expect an SKB to be set. */
125 BUG_ON(cmd->flags & CMD_WANT_SKB);
126
127 /* Assign a generic callback if one is not provided */
128 if (!cmd->callback)
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200129 cmd->callback = il_generic_cmd_callback;
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800130
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200131 if (test_bit(STATUS_EXIT_PENDING, &il->status))
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800132 return -EBUSY;
133
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200134 ret = il_enqueue_hcmd(il, cmd);
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800135 if (ret < 0) {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +0200136 IL_ERR("Error sending %s: enqueue_hcmd failed: %d\n",
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200137 il_get_cmd_string(cmd->id), ret);
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800138 return ret;
139 }
140 return 0;
141}
142
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200143int il_send_cmd_sync(struct il_priv *il, struct il_host_cmd *cmd)
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800144{
145 int cmd_idx;
146 int ret;
147
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200148 lockdep_assert_held(&il->mutex);
Stanislaw Gruszka224509022011-04-28 11:51:33 +0200149
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800150 BUG_ON(cmd->flags & CMD_ASYNC);
151
152 /* A synchronous command can not have a callback set. */
153 BUG_ON(cmd->callback);
154
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +0100155 D_INFO("Attempting to send sync command %s\n",
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200156 il_get_cmd_string(cmd->id));
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800157
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200158 set_bit(STATUS_HCMD_ACTIVE, &il->status);
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +0100159 D_INFO("Setting HCMD_ACTIVE for command %s\n",
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200160 il_get_cmd_string(cmd->id));
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800161
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200162 cmd_idx = il_enqueue_hcmd(il, cmd);
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800163 if (cmd_idx < 0) {
164 ret = cmd_idx;
Stanislaw Gruszka9406f792011-08-18 22:07:57 +0200165 IL_ERR("Error sending %s: enqueue_hcmd failed: %d\n",
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200166 il_get_cmd_string(cmd->id), ret);
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800167 goto out;
168 }
169
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200170 ret = wait_event_timeout(il->wait_command_queue,
171 !test_bit(STATUS_HCMD_ACTIVE, &il->status),
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800172 HOST_COMPLETE_TIMEOUT);
173 if (!ret) {
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200174 if (test_bit(STATUS_HCMD_ACTIVE, &il->status)) {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +0200175 IL_ERR(
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800176 "Error sending %s: time out after %dms.\n",
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200177 il_get_cmd_string(cmd->id),
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800178 jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
179
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200180 clear_bit(STATUS_HCMD_ACTIVE, &il->status);
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +0100181 D_INFO(
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800182 "Clearing HCMD_ACTIVE for command %s\n",
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200183 il_get_cmd_string(cmd->id));
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800184 ret = -ETIMEDOUT;
185 goto cancel;
186 }
187 }
188
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200189 if (test_bit(STATUS_RF_KILL_HW, &il->status)) {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +0200190 IL_ERR("Command %s aborted: RF KILL Switch\n",
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200191 il_get_cmd_string(cmd->id));
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800192 ret = -ECANCELED;
193 goto fail;
194 }
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200195 if (test_bit(STATUS_FW_ERROR, &il->status)) {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +0200196 IL_ERR("Command %s failed: FW Error\n",
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200197 il_get_cmd_string(cmd->id));
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800198 ret = -EIO;
199 goto fail;
200 }
201 if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_page) {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +0200202 IL_ERR("Error: Response NULL in '%s'\n",
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200203 il_get_cmd_string(cmd->id));
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800204 ret = -EIO;
205 goto cancel;
206 }
207
208 ret = 0;
209 goto out;
210
211cancel:
212 if (cmd->flags & CMD_WANT_SKB) {
213 /*
214 * Cancel the CMD_WANT_SKB flag for the cmd in the
215 * TX cmd queue. Otherwise in case the cmd comes
216 * in later, it will possibly set an invalid
217 * address (cmd->meta.source).
218 */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200219 il->txq[il->cmd_queue].meta[cmd_idx].flags &=
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800220 ~CMD_WANT_SKB;
221 }
222fail:
223 if (cmd->reply_page) {
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200224 il_free_pages(il, cmd->reply_page);
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800225 cmd->reply_page = 0;
226 }
227out:
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800228 return ret;
229}
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200230EXPORT_SYMBOL(il_send_cmd_sync);
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800231
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200232int il_send_cmd(struct il_priv *il, struct il_host_cmd *cmd)
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800233{
234 if (cmd->flags & CMD_ASYNC)
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200235 return il_send_cmd_async(il, cmd);
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800236
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200237 return il_send_cmd_sync(il, cmd);
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800238}
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200239EXPORT_SYMBOL(il_send_cmd);
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800240
241int
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200242il_send_cmd_pdu(struct il_priv *il, u8 id, u16 len, const void *data)
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800243{
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200244 struct il_host_cmd cmd = {
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800245 .id = id,
246 .len = len,
247 .data = data,
248 };
249
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200250 return il_send_cmd_sync(il, &cmd);
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800251}
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200252EXPORT_SYMBOL(il_send_cmd_pdu);
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800253
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200254int il_send_cmd_pdu_async(struct il_priv *il,
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800255 u8 id, u16 len, const void *data,
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200256 void (*callback)(struct il_priv *il,
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200257 struct il_device_cmd *cmd,
Stanislaw Gruszkadcae1c62011-08-26 14:36:21 +0200258 struct il_rx_pkt *pkt))
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800259{
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200260 struct il_host_cmd cmd = {
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800261 .id = id,
262 .len = len,
263 .data = data,
264 };
265
266 cmd.flags |= CMD_ASYNC;
267 cmd.callback = callback;
268
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200269 return il_send_cmd_async(il, &cmd);
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800270}
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200271EXPORT_SYMBOL(il_send_cmd_pdu_async);