- patches.arch/x86_mce_intel_decode_physical_address.patch:
[linux-flexiantxendom0-3.2.10.git] / drivers / net / wimax / i2400m / sdio-tx.c
index de66d06..b53cd1c 100644 (file)
@@ -98,6 +98,10 @@ void i2400ms_tx_submit(struct work_struct *ws)
                                tx_msg_size, result);
                }
 
+               if (result == -ETIMEDOUT) {
+                       i2400m_error_recovery(i2400m);
+                       break;
+               }
                d_printf(2, dev, "TX: %zub submitted\n", tx_msg_size);
        }
 
@@ -114,13 +118,17 @@ void i2400ms_bus_tx_kick(struct i2400m *i2400m)
 {
        struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
        struct device *dev = &i2400ms->func->dev;
+       unsigned long flags;
 
        d_fnstart(3, dev, "(i2400m %p) = void\n", i2400m);
 
        /* schedule tx work, this is because tx may block, therefore
         * it has to run in a thread context.
         */
-       queue_work(i2400ms->tx_workqueue, &i2400ms->tx_worker);
+       spin_lock_irqsave(&i2400m->tx_lock, flags);
+       if (i2400ms->tx_workqueue != NULL)
+               queue_work(i2400ms->tx_workqueue, &i2400ms->tx_worker);
+       spin_unlock_irqrestore(&i2400m->tx_lock, flags);
 
        d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
 }
@@ -130,27 +138,40 @@ int i2400ms_tx_setup(struct i2400ms *i2400ms)
        int result;
        struct device *dev = &i2400ms->func->dev;
        struct i2400m *i2400m = &i2400ms->i2400m;
+       struct workqueue_struct *tx_workqueue;
+       unsigned long flags;
 
        d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms);
 
        INIT_WORK(&i2400ms->tx_worker, i2400ms_tx_submit);
        snprintf(i2400ms->tx_wq_name, sizeof(i2400ms->tx_wq_name),
                 "%s-tx", i2400m->wimax_dev.name);
-       i2400ms->tx_workqueue =
+       tx_workqueue =
                create_singlethread_workqueue(i2400ms->tx_wq_name);
-       if (NULL == i2400ms->tx_workqueue) {
+       if (tx_workqueue == NULL) {
                dev_err(dev, "TX: failed to create workqueue\n");
                result = -ENOMEM;
        } else
                result = 0;
+       spin_lock_irqsave(&i2400m->tx_lock, flags);
+       i2400ms->tx_workqueue = tx_workqueue;
+       spin_unlock_irqrestore(&i2400m->tx_lock, flags);
        d_fnend(5, dev, "(i2400ms %p) = %d\n", i2400ms, result);
        return result;
 }
 
 void i2400ms_tx_release(struct i2400ms *i2400ms)
 {
-       if (i2400ms->tx_workqueue) {
-               destroy_workqueue(i2400ms->tx_workqueue);
-               i2400ms->tx_workqueue = NULL;
-       }
+       struct i2400m *i2400m = &i2400ms->i2400m;
+       struct workqueue_struct *tx_workqueue;
+       unsigned long flags;
+
+       tx_workqueue = i2400ms->tx_workqueue;
+
+       spin_lock_irqsave(&i2400m->tx_lock, flags);
+       i2400ms->tx_workqueue = NULL;
+       spin_unlock_irqrestore(&i2400m->tx_lock, flags);
+
+       if (tx_workqueue)
+               destroy_workqueue(tx_workqueue);
 }