spin_unlock_irqrestore(&priv->driver_lock, flags);
 }
 
-void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
-                         int result)
+void __lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
+                           int result)
 {
+       /*
+        * Normally, commands are removed from cmdpendingq before being
+        * submitted. However, we can arrive here on alternative codepaths
+        * where the command is still pending. Make sure the command really
+        * isn't part of a list at this point.
+        */
+       list_del_init(&cmd->list);
+
        cmd->result = result;
        cmd->cmdwaitqwoken = 1;
-       wake_up_interruptible(&cmd->cmdwait_q);
+       wake_up(&cmd->cmdwait_q);
 
        if (!cmd->callback || cmd->callback == lbs_cmd_async_callback)
                __lbs_cleanup_and_insert_cmd(priv, cmd);
        priv->cur_cmd = NULL;
+       wake_up_interruptible(&priv->waitq);
+}
+
+void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
+                         int result)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&priv->driver_lock, flags);
+       __lbs_complete_command(priv, cmd, result);
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
 }
 
 int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)
        if (!list_empty(&priv->cmdfreeq)) {
                tempnode = list_first_entry(&priv->cmdfreeq,
                                            struct cmd_ctrl_node, list);
-               list_del(&tempnode->list);
+               list_del_init(&tempnode->list);
        } else {
                lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
                tempnode = NULL;
                                    cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
                                        lbs_deb_host(
                                               "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
-                                       spin_lock_irqsave(&priv->driver_lock, flags);
-                                       list_del(&cmdnode->list);
                                        lbs_complete_command(priv, cmdnode, 0);
-                                       spin_unlock_irqrestore(&priv->driver_lock, flags);
 
                                        ret = 0;
                                        goto done;
                                    (priv->psstate == PS_STATE_PRE_SLEEP)) {
                                        lbs_deb_host(
                                               "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
-                                       spin_lock_irqsave(&priv->driver_lock, flags);
-                                       list_del(&cmdnode->list);
                                        lbs_complete_command(priv, cmdnode, 0);
-                                       spin_unlock_irqrestore(&priv->driver_lock, flags);
                                        priv->needtowakeup = 1;
 
                                        ret = 0;
                        }
                }
                spin_lock_irqsave(&priv->driver_lock, flags);
-               list_del(&cmdnode->list);
+               list_del_init(&cmdnode->list);
                spin_unlock_irqrestore(&priv->driver_lock, flags);
                lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
                            le16_to_cpu(cmd->command));
        }
 
        might_sleep();
-       wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);
+
+       /*
+        * Be careful with signals here. A signal may be received as the system
+        * goes into suspend or resume. We do not want this to interrupt the
+        * command, so we perform an uninterruptible sleep.
+        */
+       wait_event(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);
 
        spin_lock_irqsave(&priv->driver_lock, flags);
        ret = cmdnode->result;
 
                        lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
                }
 
-               lbs_complete_command(priv, priv->cur_cmd, result);
+               __lbs_complete_command(priv, priv->cur_cmd, result);
                spin_unlock_irqrestore(&priv->driver_lock, flags);
 
                ret = 0;
                        break;
 
                }
-               lbs_complete_command(priv, priv->cur_cmd, result);
+               __lbs_complete_command(priv, priv->cur_cmd, result);
                spin_unlock_irqrestore(&priv->driver_lock, flags);
 
                ret = -1;
 
        if (priv->cur_cmd) {
                /* Clean up and Put current command back to cmdfreeq */
-               lbs_complete_command(priv, priv->cur_cmd, result);
+               __lbs_complete_command(priv, priv->cur_cmd, result);
        }
        spin_unlock_irqrestore(&priv->driver_lock, flags);
 
 
                    le16_to_cpu(priv->cur_cmd->cmdbuf->command));
 
        priv->cmd_timed_out = 1;
+
+       /*
+        * If the device didn't even acknowledge the command, reset the state
+        * so that we don't block all future commands due to this one timeout.
+        */
+       if (priv->dnld_sent == DNLD_CMD_SENT)
+               priv->dnld_sent = DNLD_RES_RECEIVED;
+
        wake_up_interruptible(&priv->waitq);
 out:
        spin_unlock_irqrestore(&priv->driver_lock, flags);
        list_for_each_entry(cmdnode, &priv->cmdpendingq, list) {
                cmdnode->result = -ENOENT;
                cmdnode->cmdwaitqwoken = 1;
-               wake_up_interruptible(&cmdnode->cmdwait_q);
+               wake_up(&cmdnode->cmdwait_q);
        }
 
        /* Flush the command the card is currently processing */
                lbs_deb_main("clearing current command\n");
                priv->cur_cmd->result = -ENOENT;
                priv->cur_cmd->cmdwaitqwoken = 1;
-               wake_up_interruptible(&priv->cur_cmd->cmdwait_q);
+               wake_up(&priv->cur_cmd->cmdwait_q);
        }
        lbs_deb_main("done clearing commands\n");
        spin_unlock_irqrestore(&priv->driver_lock, flags);