diff options
Diffstat (limited to 'drivers/net/wireless/libertas')
-rw-r--r-- | drivers/net/wireless/libertas/cmd.c | 46 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/cmd.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/cmdresp.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/main.c | 12 |
4 files changed, 48 insertions, 18 deletions
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 9dcf967e1ee4..dbd24a4607ec 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -874,6 +874,7 @@ int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value) memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_GET); + cmd.offset = cpu_to_le16(offset); if (reg != CMD_MAC_REG_ACCESS && reg != CMD_BBP_REG_ACCESS && @@ -883,7 +884,7 @@ int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value) } ret = lbs_cmd_with_response(priv, reg, &cmd); - if (ret) { + if (!ret) { if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS) *value = cmd.value.bbp_rf; else if (reg == CMD_MAC_REG_ACCESS) @@ -916,6 +917,7 @@ int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value) memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_SET); + cmd.offset = cpu_to_le16(offset); if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS) cmd.value.bbp_rf = (u8) (value & 0xFF); @@ -1068,16 +1070,34 @@ static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv, 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) @@ -1249,7 +1269,7 @@ static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv) 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; @@ -1357,10 +1377,7 @@ int lbs_execute_next_command(struct lbs_private *priv) 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; @@ -1370,10 +1387,7 @@ int lbs_execute_next_command(struct lbs_private *priv) (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; @@ -1385,7 +1399,7 @@ int lbs_execute_next_command(struct lbs_private *priv) } } 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)); @@ -1668,7 +1682,13 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t 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; diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index 7109d6b717ea..b280ef7a0aea 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -59,6 +59,8 @@ int lbs_allocate_cmd_buffer(struct lbs_private *priv); int lbs_free_cmd_buffer(struct lbs_private *priv); int lbs_execute_next_command(struct lbs_private *priv); +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); int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len); diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 2ffe5a1ff003..178b222b3ce1 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -166,7 +166,7 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len) 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; @@ -187,7 +187,7 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len) 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; @@ -205,7 +205,7 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len) 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); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index cf3d2c8e1969..c79aac4b1dae 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -639,6 +639,14 @@ static void lbs_cmd_timeout_handler(unsigned long data) 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); @@ -995,7 +1003,7 @@ void lbs_stop_card(struct lbs_private *priv) 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 */ @@ -1003,7 +1011,7 @@ void lbs_stop_card(struct lbs_private *priv) 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); |