aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wimax/i2400m/i2400m-sdio.h5
-rw-r--r--drivers/net/wimax/i2400m/sdio-tx.c31
2 files changed, 28 insertions, 8 deletions
diff --git a/drivers/net/wimax/i2400m/i2400m-sdio.h b/drivers/net/wimax/i2400m/i2400m-sdio.h
index b9c4bed3b457..360d4fb195f4 100644
--- a/drivers/net/wimax/i2400m/i2400m-sdio.h
+++ b/drivers/net/wimax/i2400m/i2400m-sdio.h
@@ -99,7 +99,10 @@ enum {
99 * 99 *
100 * @tx_workqueue: workqeueue used for data TX; we don't use the 100 * @tx_workqueue: workqeueue used for data TX; we don't use the
101 * system's workqueue as that might cause deadlocks with code in 101 * system's workqueue as that might cause deadlocks with code in
102 * the bus-generic driver. 102 * the bus-generic driver. The read/write operation to the queue
103 * is protected with spinlock (tx_lock in struct i2400m) to avoid
104 * the queue being destroyed in the middle of a the queue read/write
105 * operation.
103 * 106 *
104 * @debugfs_dentry: dentry for the SDIO specific debugfs files 107 * @debugfs_dentry: dentry for the SDIO specific debugfs files
105 * 108 *
diff --git a/drivers/net/wimax/i2400m/sdio-tx.c b/drivers/net/wimax/i2400m/sdio-tx.c
index de66d068c9cb..412b6a8eaef2 100644
--- a/drivers/net/wimax/i2400m/sdio-tx.c
+++ b/drivers/net/wimax/i2400m/sdio-tx.c
@@ -114,13 +114,17 @@ void i2400ms_bus_tx_kick(struct i2400m *i2400m)
114{ 114{
115 struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); 115 struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
116 struct device *dev = &i2400ms->func->dev; 116 struct device *dev = &i2400ms->func->dev;
117 unsigned long flags;
117 118
118 d_fnstart(3, dev, "(i2400m %p) = void\n", i2400m); 119 d_fnstart(3, dev, "(i2400m %p) = void\n", i2400m);
119 120
120 /* schedule tx work, this is because tx may block, therefore 121 /* schedule tx work, this is because tx may block, therefore
121 * it has to run in a thread context. 122 * it has to run in a thread context.
122 */ 123 */
123 queue_work(i2400ms->tx_workqueue, &i2400ms->tx_worker); 124 spin_lock_irqsave(&i2400m->tx_lock, flags);
125 if (i2400ms->tx_workqueue != NULL)
126 queue_work(i2400ms->tx_workqueue, &i2400ms->tx_worker);
127 spin_unlock_irqrestore(&i2400m->tx_lock, flags);
124 128
125 d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); 129 d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
126} 130}
@@ -130,27 +134,40 @@ int i2400ms_tx_setup(struct i2400ms *i2400ms)
130 int result; 134 int result;
131 struct device *dev = &i2400ms->func->dev; 135 struct device *dev = &i2400ms->func->dev;
132 struct i2400m *i2400m = &i2400ms->i2400m; 136 struct i2400m *i2400m = &i2400ms->i2400m;
137 struct workqueue_struct *tx_workqueue;
138 unsigned long flags;
133 139
134 d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms); 140 d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms);
135 141
136 INIT_WORK(&i2400ms->tx_worker, i2400ms_tx_submit); 142 INIT_WORK(&i2400ms->tx_worker, i2400ms_tx_submit);
137 snprintf(i2400ms->tx_wq_name, sizeof(i2400ms->tx_wq_name), 143 snprintf(i2400ms->tx_wq_name, sizeof(i2400ms->tx_wq_name),
138 "%s-tx", i2400m->wimax_dev.name); 144 "%s-tx", i2400m->wimax_dev.name);
139 i2400ms->tx_workqueue = 145 tx_workqueue =
140 create_singlethread_workqueue(i2400ms->tx_wq_name); 146 create_singlethread_workqueue(i2400ms->tx_wq_name);
141 if (NULL == i2400ms->tx_workqueue) { 147 if (tx_workqueue == NULL) {
142 dev_err(dev, "TX: failed to create workqueue\n"); 148 dev_err(dev, "TX: failed to create workqueue\n");
143 result = -ENOMEM; 149 result = -ENOMEM;
144 } else 150 } else
145 result = 0; 151 result = 0;
152 spin_lock_irqsave(&i2400m->tx_lock, flags);
153 i2400ms->tx_workqueue = tx_workqueue;
154 spin_unlock_irqrestore(&i2400m->tx_lock, flags);
146 d_fnend(5, dev, "(i2400ms %p) = %d\n", i2400ms, result); 155 d_fnend(5, dev, "(i2400ms %p) = %d\n", i2400ms, result);
147 return result; 156 return result;
148} 157}
149 158
150void i2400ms_tx_release(struct i2400ms *i2400ms) 159void i2400ms_tx_release(struct i2400ms *i2400ms)
151{ 160{
152 if (i2400ms->tx_workqueue) { 161 struct i2400m *i2400m = &i2400ms->i2400m;
153 destroy_workqueue(i2400ms->tx_workqueue); 162 struct workqueue_struct *tx_workqueue;
154 i2400ms->tx_workqueue = NULL; 163 unsigned long flags;
155 } 164
165 tx_workqueue = i2400ms->tx_workqueue;
166
167 spin_lock_irqsave(&i2400m->tx_lock, flags);
168 i2400ms->tx_workqueue = NULL;
169 spin_unlock_irqrestore(&i2400m->tx_lock, flags);
170
171 if (tx_workqueue)
172 destroy_workqueue(tx_workqueue);
156} 173}