~ubuntu-branches/ubuntu/natty/linux-backports-modules-2.6.38/natty-updates

« back to all changes in this revision

Viewing changes to updates/cw-2.6.39/drivers/net/wireless/iwlwifi/iwl-hcmd.c

  • Committer: Bazaar Package Importer
  • Author(s): Tim Gardner, Tim Gardner
  • Date: 2011-06-08 10:44:09 UTC
  • Revision ID: james.westby@ubuntu.com-20110608104409-fnl8carkdo15bwsz
Tags: 2.6.38-10.6
[ Tim Gardner ]

Shorten compat-wireless package name to cw to accomodate
CDROM file name length restrictions.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************************************
 
2
 *
 
3
 * GPL LICENSE SUMMARY
 
4
 *
 
5
 * Copyright(c) 2008 - 2010 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_3945_RX);
 
55
                IWL_CMD(REPLY_TX);
 
56
                IWL_CMD(REPLY_RATE_SCALE);
 
57
                IWL_CMD(REPLY_LEDS_CMD);
 
58
                IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
 
59
                IWL_CMD(COEX_PRIORITY_TABLE_CMD);
 
60
                IWL_CMD(COEX_MEDIUM_NOTIFICATION);
 
61
                IWL_CMD(COEX_EVENT_CMD);
 
62
                IWL_CMD(REPLY_QUIET_CMD);
 
63
                IWL_CMD(REPLY_CHANNEL_SWITCH);
 
64
                IWL_CMD(CHANNEL_SWITCH_NOTIFICATION);
 
65
                IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD);
 
66
                IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION);
 
67
                IWL_CMD(POWER_TABLE_CMD);
 
68
                IWL_CMD(PM_SLEEP_NOTIFICATION);
 
69
                IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC);
 
70
                IWL_CMD(REPLY_SCAN_CMD);
 
71
                IWL_CMD(REPLY_SCAN_ABORT_CMD);
 
72
                IWL_CMD(SCAN_START_NOTIFICATION);
 
73
                IWL_CMD(SCAN_RESULTS_NOTIFICATION);
 
74
                IWL_CMD(SCAN_COMPLETE_NOTIFICATION);
 
75
                IWL_CMD(BEACON_NOTIFICATION);
 
76
                IWL_CMD(REPLY_TX_BEACON);
 
77
                IWL_CMD(WHO_IS_AWAKE_NOTIFICATION);
 
78
                IWL_CMD(QUIET_NOTIFICATION);
 
79
                IWL_CMD(REPLY_TX_PWR_TABLE_CMD);
 
80
                IWL_CMD(MEASURE_ABORT_NOTIFICATION);
 
81
                IWL_CMD(REPLY_BT_CONFIG);
 
82
                IWL_CMD(REPLY_STATISTICS_CMD);
 
83
                IWL_CMD(STATISTICS_NOTIFICATION);
 
84
                IWL_CMD(REPLY_CARD_STATE_CMD);
 
85
                IWL_CMD(CARD_STATE_NOTIFICATION);
 
86
                IWL_CMD(MISSED_BEACONS_NOTIFICATION);
 
87
                IWL_CMD(REPLY_CT_KILL_CONFIG_CMD);
 
88
                IWL_CMD(SENSITIVITY_CMD);
 
89
                IWL_CMD(REPLY_PHY_CALIBRATION_CMD);
 
90
                IWL_CMD(REPLY_RX_PHY_CMD);
 
91
                IWL_CMD(REPLY_RX_MPDU_CMD);
 
92
                IWL_CMD(REPLY_RX);
 
93
                IWL_CMD(REPLY_COMPRESSED_BA);
 
94
                IWL_CMD(CALIBRATION_CFG_CMD);
 
95
                IWL_CMD(CALIBRATION_RES_NOTIFICATION);
 
96
                IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION);
 
97
                IWL_CMD(REPLY_TX_POWER_DBM_CMD);
 
98
                IWL_CMD(TEMPERATURE_NOTIFICATION);
 
99
                IWL_CMD(TX_ANT_CONFIGURATION_CMD);
 
100
                IWL_CMD(REPLY_BT_COEX_PROFILE_NOTIF);
 
101
                IWL_CMD(REPLY_BT_COEX_PRIO_TABLE);
 
102
                IWL_CMD(REPLY_BT_COEX_PROT_ENV);
 
103
                IWL_CMD(REPLY_WIPAN_PARAMS);
 
104
                IWL_CMD(REPLY_WIPAN_RXON);
 
105
                IWL_CMD(REPLY_WIPAN_RXON_TIMING);
 
106
                IWL_CMD(REPLY_WIPAN_RXON_ASSOC);
 
107
                IWL_CMD(REPLY_WIPAN_QOS_PARAM);
 
108
                IWL_CMD(REPLY_WIPAN_WEPKEY);
 
109
                IWL_CMD(REPLY_WIPAN_P2P_CHANNEL_SWITCH);
 
110
                IWL_CMD(REPLY_WIPAN_NOA_NOTIFICATION);
 
111
                IWL_CMD(REPLY_WIPAN_DEACTIVATION_COMPLETE);
 
112
        default:
 
113
                return "UNKNOWN";
 
114
 
 
115
        }
 
116
}
 
117
 
 
118
#define HOST_COMPLETE_TIMEOUT (HZ / 2)
 
119
 
 
120
static void iwl_generic_cmd_callback(struct iwl_priv *priv,
 
121
                                     struct iwl_device_cmd *cmd,
 
122
                                     struct iwl_rx_packet *pkt)
 
123
{
 
124
        if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
 
125
                IWL_ERR(priv, "Bad return from %s (0x%08X)\n",
 
126
                        get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
 
127
                return;
 
128
        }
 
129
 
 
130
#ifdef CONFIG_IWLWIFI_DEBUG
 
131
        switch (cmd->hdr.cmd) {
 
132
        case REPLY_TX_LINK_QUALITY_CMD:
 
133
        case SENSITIVITY_CMD:
 
134
                IWL_DEBUG_HC_DUMP(priv, "back from %s (0x%08X)\n",
 
135
                                get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
 
136
                break;
 
137
        default:
 
138
                IWL_DEBUG_HC(priv, "back from %s (0x%08X)\n",
 
139
                                get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
 
140
        }
 
141
#endif
 
142
}
 
143
 
 
144
static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 
145
{
 
146
        int ret;
 
147
 
 
148
        BUG_ON(!(cmd->flags & CMD_ASYNC));
 
149
 
 
150
        /* An asynchronous command can not expect an SKB to be set. */
 
151
        BUG_ON(cmd->flags & CMD_WANT_SKB);
 
152
 
 
153
        /* Assign a generic callback if one is not provided */
 
154
        if (!cmd->callback)
 
155
                cmd->callback = iwl_generic_cmd_callback;
 
156
 
 
157
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 
158
                return -EBUSY;
 
159
 
 
160
        ret = iwl_enqueue_hcmd(priv, cmd);
 
161
        if (ret < 0) {
 
162
                IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n",
 
163
                          get_cmd_string(cmd->id), ret);
 
164
                return ret;
 
165
        }
 
166
        return 0;
 
167
}
 
168
 
 
169
int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 
170
{
 
171
        int cmd_idx;
 
172
        int ret;
 
173
 
 
174
        BUG_ON(cmd->flags & CMD_ASYNC);
 
175
 
 
176
         /* A synchronous command can not have a callback set. */
 
177
        BUG_ON(cmd->callback);
 
178
 
 
179
        IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n",
 
180
                        get_cmd_string(cmd->id));
 
181
        mutex_lock(&priv->sync_cmd_mutex);
 
182
 
 
183
        set_bit(STATUS_HCMD_ACTIVE, &priv->status);
 
184
        IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n",
 
185
                        get_cmd_string(cmd->id));
 
186
 
 
187
        cmd_idx = iwl_enqueue_hcmd(priv, cmd);
 
188
        if (cmd_idx < 0) {
 
189
                ret = cmd_idx;
 
190
                IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n",
 
191
                          get_cmd_string(cmd->id), ret);
 
192
                goto out;
 
193
        }
 
194
 
 
195
        ret = wait_event_interruptible_timeout(priv->wait_command_queue,
 
196
                        !test_bit(STATUS_HCMD_ACTIVE, &priv->status),
 
197
                        HOST_COMPLETE_TIMEOUT);
 
198
        if (!ret) {
 
199
                if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) {
 
200
                        IWL_ERR(priv,
 
201
                                "Error sending %s: time out after %dms.\n",
 
202
                                get_cmd_string(cmd->id),
 
203
                                jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
 
204
 
 
205
                        clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
 
206
                        IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s\n",
 
207
                                       get_cmd_string(cmd->id));
 
208
                        ret = -ETIMEDOUT;
 
209
                        goto cancel;
 
210
                }
 
211
        }
 
212
 
 
213
        if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
 
214
                IWL_ERR(priv, "Command %s aborted: RF KILL Switch\n",
 
215
                               get_cmd_string(cmd->id));
 
216
                ret = -ECANCELED;
 
217
                goto fail;
 
218
        }
 
219
        if (test_bit(STATUS_FW_ERROR, &priv->status)) {
 
220
                IWL_ERR(priv, "Command %s failed: FW Error\n",
 
221
                               get_cmd_string(cmd->id));
 
222
                ret = -EIO;
 
223
                goto fail;
 
224
        }
 
225
        if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_page) {
 
226
                IWL_ERR(priv, "Error: Response NULL in '%s'\n",
 
227
                          get_cmd_string(cmd->id));
 
228
                ret = -EIO;
 
229
                goto cancel;
 
230
        }
 
231
 
 
232
        ret = 0;
 
233
        goto out;
 
234
 
 
235
cancel:
 
236
        if (cmd->flags & CMD_WANT_SKB) {
 
237
                /*
 
238
                 * Cancel the CMD_WANT_SKB flag for the cmd in the
 
239
                 * TX cmd queue. Otherwise in case the cmd comes
 
240
                 * in later, it will possibly set an invalid
 
241
                 * address (cmd->meta.source).
 
242
                 */
 
243
                priv->txq[priv->cmd_queue].meta[cmd_idx].flags &=
 
244
                                                        ~CMD_WANT_SKB;
 
245
        }
 
246
fail:
 
247
        if (cmd->reply_page) {
 
248
                iwl_free_pages(priv, cmd->reply_page);
 
249
                cmd->reply_page = 0;
 
250
        }
 
251
out:
 
252
        mutex_unlock(&priv->sync_cmd_mutex);
 
253
        return ret;
 
254
}
 
255
 
 
256
int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 
257
{
 
258
        if (cmd->flags & CMD_ASYNC)
 
259
                return iwl_send_cmd_async(priv, cmd);
 
260
 
 
261
        return iwl_send_cmd_sync(priv, cmd);
 
262
}
 
263
 
 
264
int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data)
 
265
{
 
266
        struct iwl_host_cmd cmd = {
 
267
                .id = id,
 
268
                .len = len,
 
269
                .data = data,
 
270
        };
 
271
 
 
272
        return iwl_send_cmd_sync(priv, &cmd);
 
273
}
 
274
 
 
275
int iwl_send_cmd_pdu_async(struct iwl_priv *priv,
 
276
                           u8 id, u16 len, const void *data,
 
277
                           void (*callback)(struct iwl_priv *priv,
 
278
                                            struct iwl_device_cmd *cmd,
 
279
                                            struct iwl_rx_packet *pkt))
 
280
{
 
281
        struct iwl_host_cmd cmd = {
 
282
                .id = id,
 
283
                .len = len,
 
284
                .data = data,
 
285
        };
 
286
 
 
287
        cmd.flags |= CMD_ASYNC;
 
288
        cmd.callback = callback;
 
289
 
 
290
        return iwl_send_cmd_async(priv, &cmd);
 
291
}