libertas: don't retry commands
[safe/jmp/linux-2.6] / drivers / net / wireless / libertas / cmdresp.c
1 /**
2   * This file contains the handling of command
3   * responses as well as events generated by firmware.
4   */
5 #include <linux/delay.h>
6 #include <linux/sched.h>
7 #include <linux/if_arp.h>
8 #include <linux/netdevice.h>
9 #include <asm/unaligned.h>
10 #include <net/iw_handler.h>
11
12 #include "host.h"
13 #include "decl.h"
14 #include "cmd.h"
15 #include "defs.h"
16 #include "dev.h"
17 #include "assoc.h"
18 #include "wext.h"
19
20 /**
21  *  @brief This function handles disconnect event. it
22  *  reports disconnect to upper layer, clean tx/rx packets,
23  *  reset link state etc.
24  *
25  *  @param priv    A pointer to struct lbs_private structure
26  *  @return        n/a
27  */
28 void lbs_mac_event_disconnected(struct lbs_private *priv)
29 {
30         if (priv->connect_status != LBS_CONNECTED)
31                 return;
32
33         lbs_deb_enter(LBS_DEB_ASSOC);
34
35         /*
36          * Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
37          * It causes problem in the Supplicant
38          */
39         msleep_interruptible(1000);
40         lbs_send_disconnect_notification(priv);
41
42         /* report disconnect to upper layer */
43         netif_stop_queue(priv->dev);
44         netif_carrier_off(priv->dev);
45
46         /* Free Tx and Rx packets */
47         kfree_skb(priv->currenttxskb);
48         priv->currenttxskb = NULL;
49         priv->tx_pending_len = 0;
50
51         /* reset SNR/NF/RSSI values */
52         memset(priv->SNR, 0x00, sizeof(priv->SNR));
53         memset(priv->NF, 0x00, sizeof(priv->NF));
54         memset(priv->RSSI, 0x00, sizeof(priv->RSSI));
55         memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
56         memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
57         priv->nextSNRNF = 0;
58         priv->numSNRNF = 0;
59         priv->connect_status = LBS_DISCONNECTED;
60
61         /* Clear out associated SSID and BSSID since connection is
62          * no longer valid.
63          */
64         memset(&priv->curbssparams.bssid, 0, ETH_ALEN);
65         memset(&priv->curbssparams.ssid, 0, IEEE80211_MAX_SSID_LEN);
66         priv->curbssparams.ssid_len = 0;
67
68         if (priv->psstate != PS_STATE_FULL_POWER) {
69                 /* make firmware to exit PS mode */
70                 lbs_deb_cmd("disconnected, so exit PS mode\n");
71                 lbs_ps_wakeup(priv, 0);
72         }
73         lbs_deb_leave(LBS_DEB_ASSOC);
74 }
75
76 static int lbs_ret_reg_access(struct lbs_private *priv,
77                                u16 type, struct cmd_ds_command *resp)
78 {
79         int ret = 0;
80
81         lbs_deb_enter(LBS_DEB_CMD);
82
83         switch (type) {
84         case CMD_RET(CMD_MAC_REG_ACCESS):
85                 {
86                         struct cmd_ds_mac_reg_access *reg = &resp->params.macreg;
87
88                         priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
89                         priv->offsetvalue.value = le32_to_cpu(reg->value);
90                         break;
91                 }
92
93         case CMD_RET(CMD_BBP_REG_ACCESS):
94                 {
95                         struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg;
96
97                         priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
98                         priv->offsetvalue.value = reg->value;
99                         break;
100                 }
101
102         case CMD_RET(CMD_RF_REG_ACCESS):
103                 {
104                         struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg;
105
106                         priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
107                         priv->offsetvalue.value = reg->value;
108                         break;
109                 }
110
111         default:
112                 ret = -1;
113         }
114
115         lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
116         return ret;
117 }
118
119 static inline int handle_cmd_response(struct lbs_private *priv,
120                                       struct cmd_header *cmd_response)
121 {
122         struct cmd_ds_command *resp = (struct cmd_ds_command *) cmd_response;
123         int ret = 0;
124         unsigned long flags;
125         uint16_t respcmd = le16_to_cpu(resp->command);
126
127         lbs_deb_enter(LBS_DEB_HOST);
128
129         switch (respcmd) {
130         case CMD_RET(CMD_MAC_REG_ACCESS):
131         case CMD_RET(CMD_BBP_REG_ACCESS):
132         case CMD_RET(CMD_RF_REG_ACCESS):
133                 ret = lbs_ret_reg_access(priv, respcmd, resp);
134                 break;
135
136         case CMD_RET(CMD_802_11_SET_AFC):
137         case CMD_RET(CMD_802_11_GET_AFC):
138                 spin_lock_irqsave(&priv->driver_lock, flags);
139                 memmove((void *)priv->cur_cmd->callback_arg, &resp->params.afc,
140                         sizeof(struct cmd_ds_802_11_afc));
141                 spin_unlock_irqrestore(&priv->driver_lock, flags);
142
143                 break;
144
145         case CMD_RET(CMD_802_11_BEACON_STOP):
146                 break;
147
148         case CMD_RET(CMD_802_11_RSSI):
149                 ret = lbs_ret_802_11_rssi(priv, resp);
150                 break;
151
152         case CMD_RET(CMD_802_11_TPC_CFG):
153                 spin_lock_irqsave(&priv->driver_lock, flags);
154                 memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg,
155                         sizeof(struct cmd_ds_802_11_tpc_cfg));
156                 spin_unlock_irqrestore(&priv->driver_lock, flags);
157                 break;
158
159         case CMD_RET(CMD_BT_ACCESS):
160                 spin_lock_irqsave(&priv->driver_lock, flags);
161                 if (priv->cur_cmd->callback_arg)
162                         memcpy((void *)priv->cur_cmd->callback_arg,
163                                &resp->params.bt.addr1, 2 * ETH_ALEN);
164                 spin_unlock_irqrestore(&priv->driver_lock, flags);
165                 break;
166         case CMD_RET(CMD_FWT_ACCESS):
167                 spin_lock_irqsave(&priv->driver_lock, flags);
168                 if (priv->cur_cmd->callback_arg)
169                         memcpy((void *)priv->cur_cmd->callback_arg, &resp->params.fwt,
170                                sizeof(resp->params.fwt));
171                 spin_unlock_irqrestore(&priv->driver_lock, flags);
172                 break;
173         case CMD_RET(CMD_802_11_BEACON_CTRL):
174                 ret = lbs_ret_802_11_bcn_ctrl(priv, resp);
175                 break;
176
177         default:
178                 lbs_pr_err("CMD_RESP: unknown cmd response 0x%04x\n",
179                            le16_to_cpu(resp->command));
180                 break;
181         }
182         lbs_deb_leave(LBS_DEB_HOST);
183         return ret;
184 }
185
186 int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
187 {
188         uint16_t respcmd, curcmd;
189         struct cmd_header *resp;
190         int ret = 0;
191         unsigned long flags;
192         uint16_t result;
193
194         lbs_deb_enter(LBS_DEB_HOST);
195
196         mutex_lock(&priv->lock);
197         spin_lock_irqsave(&priv->driver_lock, flags);
198
199         if (!priv->cur_cmd) {
200                 lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
201                 ret = -1;
202                 spin_unlock_irqrestore(&priv->driver_lock, flags);
203                 goto done;
204         }
205
206         resp = (void *)data;
207         curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
208         respcmd = le16_to_cpu(resp->command);
209         result = le16_to_cpu(resp->result);
210
211         lbs_deb_cmd("CMD_RESP: response 0x%04x, seq %d, size %d\n",
212                      respcmd, le16_to_cpu(resp->seqnum), len);
213         lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len);
214
215         if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
216                 lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
217                             le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
218                 spin_unlock_irqrestore(&priv->driver_lock, flags);
219                 ret = -1;
220                 goto done;
221         }
222         if (respcmd != CMD_RET(curcmd) &&
223             respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_802_11_ASSOCIATE) {
224                 lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd);
225                 spin_unlock_irqrestore(&priv->driver_lock, flags);
226                 ret = -1;
227                 goto done;
228         }
229
230         if (resp->result == cpu_to_le16(0x0004)) {
231                 /* 0x0004 means -EAGAIN. Drop the response, let it time out
232                    and be resubmitted */
233                 lbs_pr_info("Firmware returns DEFER to command %x. Will let it time out...\n",
234                             le16_to_cpu(resp->command));
235                 spin_unlock_irqrestore(&priv->driver_lock, flags);
236                 ret = -1;
237                 goto done;
238         }
239
240         /* Now we got response from FW, cancel the command timer */
241         del_timer(&priv->command_timer);
242         priv->cmd_timed_out = 0;
243
244         /* Store the response code to cur_cmd_retcode. */
245         priv->cur_cmd_retcode = result;
246
247         if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
248                 struct cmd_ds_802_11_ps_mode *psmode = (void *) &resp[1];
249                 u16 action = le16_to_cpu(psmode->action);
250
251                 lbs_deb_host(
252                        "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n",
253                        result, action);
254
255                 if (result) {
256                         lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n",
257                                     result);
258                         /*
259                          * We should not re-try enter-ps command in
260                          * ad-hoc mode. It takes place in
261                          * lbs_execute_next_command().
262                          */
263                         if (priv->mode == IW_MODE_ADHOC &&
264                             action == CMD_SUBCMD_ENTER_PS)
265                                 priv->psmode = LBS802_11POWERMODECAM;
266                 } else if (action == CMD_SUBCMD_ENTER_PS) {
267                         priv->needtowakeup = 0;
268                         priv->psstate = PS_STATE_AWAKE;
269
270                         lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
271                         if (priv->connect_status != LBS_CONNECTED) {
272                                 /*
273                                  * When Deauth Event received before Enter_PS command
274                                  * response, We need to wake up the firmware.
275                                  */
276                                 lbs_deb_host(
277                                        "disconnected, invoking lbs_ps_wakeup\n");
278
279                                 spin_unlock_irqrestore(&priv->driver_lock, flags);
280                                 mutex_unlock(&priv->lock);
281                                 lbs_ps_wakeup(priv, 0);
282                                 mutex_lock(&priv->lock);
283                                 spin_lock_irqsave(&priv->driver_lock, flags);
284                         }
285                 } else if (action == CMD_SUBCMD_EXIT_PS) {
286                         priv->needtowakeup = 0;
287                         priv->psstate = PS_STATE_FULL_POWER;
288                         lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
289                 } else {
290                         lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
291                 }
292
293                 lbs_complete_command(priv, priv->cur_cmd, result);
294                 spin_unlock_irqrestore(&priv->driver_lock, flags);
295
296                 ret = 0;
297                 goto done;
298         }
299
300         /* If the command is not successful, cleanup and return failure */
301         if ((result != 0 || !(respcmd & 0x8000))) {
302                 lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
303                        result, respcmd);
304                 /*
305                  * Handling errors here
306                  */
307                 switch (respcmd) {
308                 case CMD_RET(CMD_GET_HW_SPEC):
309                 case CMD_RET(CMD_802_11_RESET):
310                         lbs_deb_host("CMD_RESP: reset failed\n");
311                         break;
312
313                 }
314                 lbs_complete_command(priv, priv->cur_cmd, result);
315                 spin_unlock_irqrestore(&priv->driver_lock, flags);
316
317                 ret = -1;
318                 goto done;
319         }
320
321         spin_unlock_irqrestore(&priv->driver_lock, flags);
322
323         if (priv->cur_cmd && priv->cur_cmd->callback) {
324                 ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
325                                 resp);
326         } else
327                 ret = handle_cmd_response(priv, resp);
328
329         spin_lock_irqsave(&priv->driver_lock, flags);
330
331         if (priv->cur_cmd) {
332                 /* Clean up and Put current command back to cmdfreeq */
333                 lbs_complete_command(priv, priv->cur_cmd, result);
334         }
335         spin_unlock_irqrestore(&priv->driver_lock, flags);
336
337 done:
338         mutex_unlock(&priv->lock);
339         lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
340         return ret;
341 }
342
343 static int lbs_send_confirmwake(struct lbs_private *priv)
344 {
345         struct cmd_header cmd;
346         int ret = 0;
347
348         lbs_deb_enter(LBS_DEB_HOST);
349
350         cmd.command = cpu_to_le16(CMD_802_11_WAKEUP_CONFIRM);
351         cmd.size = cpu_to_le16(sizeof(cmd));
352         cmd.seqnum = cpu_to_le16(++priv->seqnum);
353         cmd.result = 0;
354
355         lbs_deb_hex(LBS_DEB_HOST, "wake confirm", (u8 *) &cmd,
356                 sizeof(cmd));
357
358         ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &cmd, sizeof(cmd));
359         if (ret)
360                 lbs_pr_alert("SEND_WAKEC_CMD: Host to Card failed for Confirm Wake\n");
361
362         lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
363         return ret;
364 }
365
366 int lbs_process_event(struct lbs_private *priv, u32 event)
367 {
368         int ret = 0;
369
370         lbs_deb_enter(LBS_DEB_CMD);
371
372         switch (event) {
373         case MACREG_INT_CODE_LINK_SENSED:
374                 lbs_deb_cmd("EVENT: link sensed\n");
375                 break;
376
377         case MACREG_INT_CODE_DEAUTHENTICATED:
378                 lbs_deb_cmd("EVENT: deauthenticated\n");
379                 lbs_mac_event_disconnected(priv);
380                 break;
381
382         case MACREG_INT_CODE_DISASSOCIATED:
383                 lbs_deb_cmd("EVENT: disassociated\n");
384                 lbs_mac_event_disconnected(priv);
385                 break;
386
387         case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
388                 lbs_deb_cmd("EVENT: link lost\n");
389                 lbs_mac_event_disconnected(priv);
390                 break;
391
392         case MACREG_INT_CODE_PS_SLEEP:
393                 lbs_deb_cmd("EVENT: ps sleep\n");
394
395                 /* handle unexpected PS SLEEP event */
396                 if (priv->psstate == PS_STATE_FULL_POWER) {
397                         lbs_deb_cmd(
398                                "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n");
399                         break;
400                 }
401                 priv->psstate = PS_STATE_PRE_SLEEP;
402
403                 lbs_ps_confirm_sleep(priv);
404
405                 break;
406
407         case MACREG_INT_CODE_HOST_AWAKE:
408                 lbs_deb_cmd("EVENT: host awake\n");
409                 if (priv->reset_deep_sleep_wakeup)
410                         priv->reset_deep_sleep_wakeup(priv);
411                 priv->is_deep_sleep = 0;
412                 lbs_send_confirmwake(priv);
413                 break;
414
415         case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
416                 if (priv->reset_deep_sleep_wakeup)
417                         priv->reset_deep_sleep_wakeup(priv);
418                 lbs_deb_cmd("EVENT: ds awake\n");
419                 priv->is_deep_sleep = 0;
420                 priv->wakeup_dev_required = 0;
421                 wake_up_interruptible(&priv->ds_awake_q);
422                 break;
423
424         case MACREG_INT_CODE_PS_AWAKE:
425                 lbs_deb_cmd("EVENT: ps awake\n");
426                 /* handle unexpected PS AWAKE event */
427                 if (priv->psstate == PS_STATE_FULL_POWER) {
428                         lbs_deb_cmd(
429                                "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
430                         break;
431                 }
432
433                 priv->psstate = PS_STATE_AWAKE;
434
435                 if (priv->needtowakeup) {
436                         /*
437                          * wait for the command processing to finish
438                          * before resuming sending
439                          * priv->needtowakeup will be set to FALSE
440                          * in lbs_ps_wakeup()
441                          */
442                         lbs_deb_cmd("waking up ...\n");
443                         lbs_ps_wakeup(priv, 0);
444                 }
445                 break;
446
447         case MACREG_INT_CODE_MIC_ERR_UNICAST:
448                 lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n");
449                 lbs_send_mic_failureevent(priv, event);
450                 break;
451
452         case MACREG_INT_CODE_MIC_ERR_MULTICAST:
453                 lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n");
454                 lbs_send_mic_failureevent(priv, event);
455                 break;
456
457         case MACREG_INT_CODE_MIB_CHANGED:
458                 lbs_deb_cmd("EVENT: MIB CHANGED\n");
459                 break;
460         case MACREG_INT_CODE_INIT_DONE:
461                 lbs_deb_cmd("EVENT: INIT DONE\n");
462                 break;
463         case MACREG_INT_CODE_ADHOC_BCN_LOST:
464                 lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
465                 break;
466         case MACREG_INT_CODE_RSSI_LOW:
467                 lbs_pr_alert("EVENT: rssi low\n");
468                 break;
469         case MACREG_INT_CODE_SNR_LOW:
470                 lbs_pr_alert("EVENT: snr low\n");
471                 break;
472         case MACREG_INT_CODE_MAX_FAIL:
473                 lbs_pr_alert("EVENT: max fail\n");
474                 break;
475         case MACREG_INT_CODE_RSSI_HIGH:
476                 lbs_pr_alert("EVENT: rssi high\n");
477                 break;
478         case MACREG_INT_CODE_SNR_HIGH:
479                 lbs_pr_alert("EVENT: snr high\n");
480                 break;
481
482         case MACREG_INT_CODE_MESH_AUTO_STARTED:
483                 /* Ignore spurious autostart events */
484                 lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
485                 break;
486
487         default:
488                 lbs_pr_alert("EVENT: unknown event id %d\n", event);
489                 break;
490         }
491
492         lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
493         return ret;
494 }