[ 143/167] [PATCH] ipw2200: Fix race condition in the command completionacknowledge

From: Ben Hutchings
Date: Wed May 09 2012 - 01:57:15 EST

3.2-stable review patch. If anyone has any objections, please let me know.


From: Stanislav Yakovlev <stas.yakovlev@xxxxxxxxx>

commit dd447319895d0c0af423e483d9b63f84f3f8869a upstream.

Driver incorrectly validates command completion: instead of waiting
for a command to be acknowledged it continues execution. Most of the
time driver gets acknowledge of the command completion in a tasklet
before it executes the next one. But sometimes it sends the next
command before it gets acknowledge for the previous one. In such a
case one of the following error messages appear in the log:

Failed to send SYSTEM_CONFIG: Already sending a command.
Failed to send ASSOCIATE: Already sending a command.
Failed to send TX_POWER: Already sending a command.

After that you need to reload the driver to get it working again.

This bug occurs during roaming (reported by Sam Varshavchik)
and machine booting (reported by Tom Gundersen and Mads Kiilerich)

This patch doesn't fix the delay issue during firmware load.
But at least device now works as usual after boot.

Signed-off-by: Stanislav Yakovlev <stas.yakovlev@xxxxxxxxx>
Signed-off-by: John W. Linville <linville@xxxxxxxxxxxxx>
Signed-off-by: Ben Hutchings <ben@xxxxxxxxxxxxxxx>
drivers/net/wireless/ipw2x00/ipw2200.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 2b02257..1779db3 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -2191,6 +2191,7 @@ static int __ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd)
int rc = 0;
unsigned long flags;
+ unsigned long now, end;

spin_lock_irqsave(&priv->lock, flags);
if (priv->status & STATUS_HCMD_ACTIVE) {
@@ -2232,10 +2233,20 @@ static int __ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd)
spin_unlock_irqrestore(&priv->lock, flags);

+ now = jiffies;
rc = wait_event_interruptible_timeout(priv->wait_command_queue,
+ end - now);
+ if (rc < 0) {
+ now = jiffies;
+ if (time_before(now, end))
+ goto again;
+ rc = 0;
+ }
if (rc == 0) {
spin_lock_irqsave(&priv->lock, flags);
if (priv->status & STATUS_HCMD_ACTIVE) {

To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/