diff options
author | Inaky Perez-Gonzalez <inaky@linux.intel.com> | 2009-10-07 23:36:03 -0400 |
---|---|---|
committer | Inaky Perez-Gonzalez <inaky@linux.intel.com> | 2009-10-19 02:56:25 -0400 |
commit | a8ee303cae6fbdaa639afa50b9d03ce6f0c7d7da (patch) | |
tree | 91c3a39faff5efe635e31be76dbce03609695a4d | |
parent | 097acbeff98178e01c2f6adb2259ab4d811340cc (diff) |
wimax/i2400m: SDIO: fix oops on reset when TXing on uninitialized data
Currently the SDIO part of the TX resources were initialized/released
with bus_dev_{start,stop}.
The generic code's TX subsystem is destroyed afterwards, so there is a
window from the bus-TX destruction to the generic-TX destruction where
the generic-TX code might call into bus-TX to do transactions.
The SDIO code cannot really cope with this (whereas in USB, how it is
laid out, it correctly ignores it). In any case, it made no sense for
the SDIO TX code to be in i2400m->bus_dev_start/stop(), so moved to
i2400m->bus_setup/release(), which also takes care of the oops.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
-rw-r--r-- | drivers/net/wimax/i2400m/sdio.c | 43 |
1 files changed, 9 insertions, 34 deletions
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c index 14e66f06f235..ec178928914e 100644 --- a/drivers/net/wimax/i2400m/sdio.c +++ b/drivers/net/wimax/i2400m/sdio.c | |||
@@ -46,15 +46,6 @@ | |||
46 | * i2400ms_bus_reset() Called by i2400m->bus_reset | 46 | * i2400ms_bus_reset() Called by i2400m->bus_reset |
47 | * __i2400ms_reset() | 47 | * __i2400ms_reset() |
48 | * __i2400ms_send_barker() | 48 | * __i2400ms_send_barker() |
49 | * | ||
50 | * i2400ms_bus_dev_start() Called by i2400m_dev_start() [who is | ||
51 | * i2400ms_tx_setup() called by i2400m_setup()] | ||
52 | * i2400ms_rx_setup() | ||
53 | * | ||
54 | * i2400ms_bus_dev_stop() Called by i2400m_dev_stop() [who is | ||
55 | * i2400ms_rx_release() is called by i2400m_release()] | ||
56 | * i2400ms_tx_release() | ||
57 | * | ||
58 | */ | 49 | */ |
59 | 50 | ||
60 | #include <linux/debugfs.h> | 51 | #include <linux/debugfs.h> |
@@ -191,12 +182,17 @@ int i2400ms_bus_setup(struct i2400m *i2400m) | |||
191 | goto error_func_enable; | 182 | goto error_func_enable; |
192 | } | 183 | } |
193 | 184 | ||
185 | result = i2400ms_tx_setup(i2400ms); | ||
186 | if (result < 0) | ||
187 | goto error_tx_setup; | ||
194 | result = i2400ms_rx_setup(i2400ms); | 188 | result = i2400ms_rx_setup(i2400ms); |
195 | if (result < 0) | 189 | if (result < 0) |
196 | goto error_rx_setup; | 190 | goto error_rx_setup; |
197 | return 0; | 191 | return 0; |
198 | 192 | ||
199 | error_rx_setup: | 193 | error_rx_setup: |
194 | i2400ms_tx_release(i2400ms); | ||
195 | error_tx_setup: | ||
200 | sdio_claim_host(func); | 196 | sdio_claim_host(func); |
201 | sdio_disable_func(func); | 197 | sdio_disable_func(func); |
202 | sdio_release_host(func); | 198 | sdio_release_host(func); |
@@ -218,6 +214,7 @@ void i2400ms_bus_release(struct i2400m *i2400m) | |||
218 | struct sdio_func *func = i2400ms->func; | 214 | struct sdio_func *func = i2400ms->func; |
219 | 215 | ||
220 | i2400ms_rx_release(i2400ms); | 216 | i2400ms_rx_release(i2400ms); |
217 | i2400ms_tx_release(i2400ms); | ||
221 | sdio_claim_host(func); | 218 | sdio_claim_host(func); |
222 | sdio_disable_func(func); | 219 | sdio_disable_func(func); |
223 | sdio_release_host(func); | 220 | sdio_release_host(func); |
@@ -235,36 +232,14 @@ void i2400ms_bus_release(struct i2400m *i2400m) | |||
235 | static | 232 | static |
236 | int i2400ms_bus_dev_start(struct i2400m *i2400m) | 233 | int i2400ms_bus_dev_start(struct i2400m *i2400m) |
237 | { | 234 | { |
238 | int result; | ||
239 | struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); | 235 | struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); |
240 | struct sdio_func *func = i2400ms->func; | 236 | struct sdio_func *func = i2400ms->func; |
241 | struct device *dev = &func->dev; | 237 | struct device *dev = &func->dev; |
242 | 238 | ||
243 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); | 239 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); |
244 | msleep(200); | 240 | msleep(200); |
245 | result = i2400ms_tx_setup(i2400ms); | 241 | d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, 0); |
246 | if (result < 0) | 242 | return 0; |
247 | goto error_tx_setup; | ||
248 | d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); | ||
249 | return result; | ||
250 | |||
251 | error_tx_setup: | ||
252 | i2400ms_tx_release(i2400ms); | ||
253 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); | ||
254 | return result; | ||
255 | } | ||
256 | |||
257 | |||
258 | static | ||
259 | void i2400ms_bus_dev_stop(struct i2400m *i2400m) | ||
260 | { | ||
261 | struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); | ||
262 | struct sdio_func *func = i2400ms->func; | ||
263 | struct device *dev = &func->dev; | ||
264 | |||
265 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); | ||
266 | i2400ms_tx_release(i2400ms); | ||
267 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); | ||
268 | } | 243 | } |
269 | 244 | ||
270 | 245 | ||
@@ -506,7 +481,7 @@ int i2400ms_probe(struct sdio_func *func, | |||
506 | i2400m->bus_pl_size_max = I2400MS_PL_SIZE_MAX; | 481 | i2400m->bus_pl_size_max = I2400MS_PL_SIZE_MAX; |
507 | i2400m->bus_setup = i2400ms_bus_setup; | 482 | i2400m->bus_setup = i2400ms_bus_setup; |
508 | i2400m->bus_dev_start = i2400ms_bus_dev_start; | 483 | i2400m->bus_dev_start = i2400ms_bus_dev_start; |
509 | i2400m->bus_dev_stop = i2400ms_bus_dev_stop; | 484 | i2400m->bus_dev_stop = NULL; |
510 | i2400m->bus_release = i2400ms_bus_release; | 485 | i2400m->bus_release = i2400ms_bus_release; |
511 | i2400m->bus_tx_kick = i2400ms_bus_tx_kick; | 486 | i2400m->bus_tx_kick = i2400ms_bus_tx_kick; |
512 | i2400m->bus_reset = i2400ms_bus_reset; | 487 | i2400m->bus_reset = i2400ms_bus_reset; |