diff options
author | David Woodhouse <dwmw2@infradead.org> | 2007-12-11 23:42:49 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 18:06:59 -0500 |
commit | e1258177e437cb8b892622f2b7beedd4701540ac (patch) | |
tree | 35addee654285e88ec1b49526cf3473427500f1e | |
parent | 06113c1c70349f5f888436ac2af28c707f4602ef (diff) |
libertas: be more careful about command responses matching cur_cmd
Especially in the light of OLPC trac #5461, in which the firmware starts
sending us seemingly random command responses which bear little relation
to the command we sent it.
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/libertas/cmd.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/cmdresp.c | 36 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/if_usb.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/main.c | 2 |
4 files changed, 26 insertions, 17 deletions
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 1cb42dc90010..5ddb46a477a4 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c | |||
@@ -1216,8 +1216,8 @@ static int DownloadcommandToStation(struct lbs_private *priv, | |||
1216 | cmdsize = le16_to_cpu(cmd->size); | 1216 | cmdsize = le16_to_cpu(cmd->size); |
1217 | command = le16_to_cpu(cmd->command); | 1217 | command = le16_to_cpu(cmd->command); |
1218 | 1218 | ||
1219 | lbs_deb_host("DNLD_CMD: command 0x%04x, size %d, jiffies %lu\n", | 1219 | lbs_deb_host("DNLD_CMD: command 0x%04x, seq %d, size %d, jiffies %lu\n", |
1220 | command, cmdsize, jiffies); | 1220 | command, le16_to_cpu(cmd->seqnum), cmdsize, jiffies); |
1221 | lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize); | 1221 | lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize); |
1222 | 1222 | ||
1223 | cmdnode->cmdwaitqwoken = 0; | 1223 | cmdnode->cmdwaitqwoken = 0; |
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index bf9941ecc239..53f73c4abdd0 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c | |||
@@ -611,7 +611,7 @@ static inline int handle_cmd_response(struct lbs_private *priv, | |||
611 | 611 | ||
612 | default: | 612 | default: |
613 | lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n", | 613 | lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n", |
614 | resp->command); | 614 | le16_to_cpu(resp->command)); |
615 | break; | 615 | break; |
616 | } | 616 | } |
617 | lbs_deb_leave(LBS_DEB_HOST); | 617 | lbs_deb_leave(LBS_DEB_HOST); |
@@ -620,17 +620,14 @@ static inline int handle_cmd_response(struct lbs_private *priv, | |||
620 | 620 | ||
621 | int lbs_process_rx_command(struct lbs_private *priv) | 621 | int lbs_process_rx_command(struct lbs_private *priv) |
622 | { | 622 | { |
623 | u16 respcmd; | 623 | uint16_t respcmd, curcmd; |
624 | struct cmd_header *resp; | 624 | struct cmd_header *resp; |
625 | int ret = 0; | 625 | int ret = 0; |
626 | ulong flags; | 626 | unsigned long flags; |
627 | u16 result; | 627 | uint16_t result; |
628 | 628 | ||
629 | lbs_deb_enter(LBS_DEB_HOST); | 629 | lbs_deb_enter(LBS_DEB_HOST); |
630 | 630 | ||
631 | /* Now we got response from FW, cancel the command timer */ | ||
632 | del_timer(&priv->command_timer); | ||
633 | |||
634 | mutex_lock(&priv->lock); | 631 | mutex_lock(&priv->lock); |
635 | spin_lock_irqsave(&priv->driver_lock, flags); | 632 | spin_lock_irqsave(&priv->driver_lock, flags); |
636 | 633 | ||
@@ -640,24 +637,35 @@ int lbs_process_rx_command(struct lbs_private *priv) | |||
640 | spin_unlock_irqrestore(&priv->driver_lock, flags); | 637 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
641 | goto done; | 638 | goto done; |
642 | } | 639 | } |
640 | |||
641 | curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command); | ||
642 | |||
643 | resp = priv->cur_cmd->cmdbuf; | 643 | resp = priv->cur_cmd->cmdbuf; |
644 | 644 | ||
645 | respcmd = le16_to_cpu(resp->command); | 645 | respcmd = le16_to_cpu(resp->command); |
646 | result = le16_to_cpu(resp->result); | 646 | result = le16_to_cpu(resp->result); |
647 | 647 | ||
648 | lbs_deb_host("CMD_RESP: response 0x%04x, size %d, jiffies %lu\n", | 648 | lbs_deb_host("CMD_RESP: response 0x%04x, seq %d, size %d, jiffies %lu\n", |
649 | respcmd, priv->upld_len, jiffies); | 649 | respcmd, le16_to_cpu(resp->seqnum), priv->upld_len, jiffies); |
650 | lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", (void *) resp, priv->upld_len); | 650 | lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", (void *) resp, priv->upld_len); |
651 | 651 | ||
652 | if (!(respcmd & 0x8000)) { | 652 | if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) { |
653 | lbs_deb_host("invalid response!\n"); | 653 | lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n", |
654 | priv->cur_cmd_retcode = -1; | 654 | le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum)); |
655 | __lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd); | ||
656 | priv->cur_cmd = NULL; | ||
657 | spin_unlock_irqrestore(&priv->driver_lock, flags); | 655 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
658 | ret = -1; | 656 | ret = -1; |
659 | goto done; | 657 | goto done; |
660 | } | 658 | } |
659 | if (respcmd != CMD_RET(curcmd) && | ||
660 | respcmd != CMD_802_11_ASSOCIATE && curcmd != CMD_RET_802_11_ASSOCIATE) { | ||
661 | lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd); | ||
662 | spin_unlock_irqrestore(&priv->driver_lock, flags); | ||
663 | ret = -1; | ||
664 | goto done; | ||
665 | } | ||
666 | |||
667 | /* Now we got response from FW, cancel the command timer */ | ||
668 | del_timer(&priv->command_timer); | ||
661 | 669 | ||
662 | /* Store the response code to cur_cmd_retcode. */ | 670 | /* Store the response code to cur_cmd_retcode. */ |
663 | priv->cur_cmd_retcode = result; | 671 | priv->cur_cmd_retcode = result; |
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 02192e8a15ea..6b8ac62e6f9a 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c | |||
@@ -643,6 +643,7 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff, | |||
643 | /* take care of cur_cmd = NULL case by reading the | 643 | /* take care of cur_cmd = NULL case by reading the |
644 | * data to clear the interrupt */ | 644 | * data to clear the interrupt */ |
645 | if (!priv->cur_cmd) { | 645 | if (!priv->cur_cmd) { |
646 | lbs_deb_hex(LBS_DEB_HOST, "Unsolicited CMD_RESP", (void *) recvbuff + MESSAGE_HEADER_LEN, priv->upld_len); | ||
646 | cmdbuf = priv->upld_buf; | 647 | cmdbuf = priv->upld_buf; |
647 | priv->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY; | 648 | priv->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY; |
648 | } else | 649 | } else |
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index bb685ac8e15e..cdf5934aaf8b 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c | |||
@@ -893,7 +893,7 @@ static void command_timer_fn(unsigned long data) | |||
893 | return; | 893 | return; |
894 | } | 894 | } |
895 | 895 | ||
896 | lbs_deb_fw("command_timer_fn fired, cmd %x\n", node->cmdbuf->command); | 896 | lbs_pr_info("command %x timed out\n", le16_to_cpu(node->cmdbuf->command)); |
897 | 897 | ||
898 | if (!priv->fw_ready) | 898 | if (!priv->fw_ready) |
899 | return; | 899 | return; |