Commit e1258177 authored by David Woodhouse's avatar David Woodhouse Committed by David S. Miller

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: default avatarDavid Woodhouse <dwmw2@infradead.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 06113c1c
...@@ -1216,8 +1216,8 @@ static int DownloadcommandToStation(struct lbs_private *priv, ...@@ -1216,8 +1216,8 @@ static int DownloadcommandToStation(struct lbs_private *priv,
cmdsize = le16_to_cpu(cmd->size); cmdsize = le16_to_cpu(cmd->size);
command = le16_to_cpu(cmd->command); command = le16_to_cpu(cmd->command);
lbs_deb_host("DNLD_CMD: command 0x%04x, size %d, jiffies %lu\n", lbs_deb_host("DNLD_CMD: command 0x%04x, seq %d, size %d, jiffies %lu\n",
command, cmdsize, jiffies); command, le16_to_cpu(cmd->seqnum), cmdsize, jiffies);
lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize); lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
cmdnode->cmdwaitqwoken = 0; cmdnode->cmdwaitqwoken = 0;
......
...@@ -611,7 +611,7 @@ static inline int handle_cmd_response(struct lbs_private *priv, ...@@ -611,7 +611,7 @@ static inline int handle_cmd_response(struct lbs_private *priv,
default: default:
lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n", lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n",
resp->command); le16_to_cpu(resp->command));
break; break;
} }
lbs_deb_leave(LBS_DEB_HOST); lbs_deb_leave(LBS_DEB_HOST);
...@@ -620,17 +620,14 @@ static inline int handle_cmd_response(struct lbs_private *priv, ...@@ -620,17 +620,14 @@ static inline int handle_cmd_response(struct lbs_private *priv,
int lbs_process_rx_command(struct lbs_private *priv) int lbs_process_rx_command(struct lbs_private *priv)
{ {
u16 respcmd; uint16_t respcmd, curcmd;
struct cmd_header *resp; struct cmd_header *resp;
int ret = 0; int ret = 0;
ulong flags; unsigned long flags;
u16 result; uint16_t result;
lbs_deb_enter(LBS_DEB_HOST); lbs_deb_enter(LBS_DEB_HOST);
/* Now we got response from FW, cancel the command timer */
del_timer(&priv->command_timer);
mutex_lock(&priv->lock); mutex_lock(&priv->lock);
spin_lock_irqsave(&priv->driver_lock, flags); spin_lock_irqsave(&priv->driver_lock, flags);
...@@ -640,24 +637,35 @@ int lbs_process_rx_command(struct lbs_private *priv) ...@@ -640,24 +637,35 @@ int lbs_process_rx_command(struct lbs_private *priv)
spin_unlock_irqrestore(&priv->driver_lock, flags); spin_unlock_irqrestore(&priv->driver_lock, flags);
goto done; goto done;
} }
curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
resp = priv->cur_cmd->cmdbuf; resp = priv->cur_cmd->cmdbuf;
respcmd = le16_to_cpu(resp->command); respcmd = le16_to_cpu(resp->command);
result = le16_to_cpu(resp->result); result = le16_to_cpu(resp->result);
lbs_deb_host("CMD_RESP: response 0x%04x, size %d, jiffies %lu\n", lbs_deb_host("CMD_RESP: response 0x%04x, seq %d, size %d, jiffies %lu\n",
respcmd, priv->upld_len, jiffies); respcmd, le16_to_cpu(resp->seqnum), priv->upld_len, jiffies);
lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", (void *) resp, priv->upld_len); lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", (void *) resp, priv->upld_len);
if (!(respcmd & 0x8000)) { if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
lbs_deb_host("invalid response!\n"); lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
priv->cur_cmd_retcode = -1; le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
__lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
priv->cur_cmd = NULL;
spin_unlock_irqrestore(&priv->driver_lock, flags); spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = -1; ret = -1;
goto done; goto done;
} }
if (respcmd != CMD_RET(curcmd) &&
respcmd != CMD_802_11_ASSOCIATE && curcmd != CMD_RET_802_11_ASSOCIATE) {
lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd);
spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = -1;
goto done;
}
/* Now we got response from FW, cancel the command timer */
del_timer(&priv->command_timer);
/* Store the response code to cur_cmd_retcode. */ /* Store the response code to cur_cmd_retcode. */
priv->cur_cmd_retcode = result; priv->cur_cmd_retcode = result;
......
...@@ -643,6 +643,7 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff, ...@@ -643,6 +643,7 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff,
/* take care of cur_cmd = NULL case by reading the /* take care of cur_cmd = NULL case by reading the
* data to clear the interrupt */ * data to clear the interrupt */
if (!priv->cur_cmd) { if (!priv->cur_cmd) {
lbs_deb_hex(LBS_DEB_HOST, "Unsolicited CMD_RESP", (void *) recvbuff + MESSAGE_HEADER_LEN, priv->upld_len);
cmdbuf = priv->upld_buf; cmdbuf = priv->upld_buf;
priv->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY; priv->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY;
} else } else
......
...@@ -893,7 +893,7 @@ static void command_timer_fn(unsigned long data) ...@@ -893,7 +893,7 @@ static void command_timer_fn(unsigned long data)
return; return;
} }
lbs_deb_fw("command_timer_fn fired, cmd %x\n", node->cmdbuf->command); lbs_pr_info("command %x timed out\n", le16_to_cpu(node->cmdbuf->command));
if (!priv->fw_ready) if (!priv->fw_ready)
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment