diff options
author | Inaky Perez-Gonzalez <inaky@linux.intel.com> | 2009-10-06 23:34:13 -0400 |
---|---|---|
committer | Inaky Perez-Gonzalez <inaky@linux.intel.com> | 2009-10-19 02:56:18 -0400 |
commit | b9ee95010bee6c0e17d18bc9d9c0cfab6e8cb73a (patch) | |
tree | d1fd6706e054bb337d3ac79e96e32d2ec5145047 /drivers/net/wimax/i2400m/driver.c | |
parent | 5eeae35b9a2e304fc4ae3d9eed63afeea23b482c (diff) |
wimax/i2400m: fix deadlock: don't do BUS reset under i2400m->init_mutex
Since the addition of the pre/post reset handlers, it became clear
that we cannot do a I2400M-RT-BUS type reset while holding the
init_mutex, as in the case of USB, it will deadlock when trying to
call i2400m_pre_reset().
Thus, the following changes:
- clarify the fact that calling bus_reset() w/ I2400M_RT_BUS while
holding init_mutex is a no-no.
- i2400m_dev_reset_handle() will do a BUS reset to recover a gone
device after unlocking init_mutex.
- in the USB reset implementation, when cold and warm reset fails,
fallback to QUEUING a usb reset, not executing a USB reset, so it
happens from another context and does not deadlock.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Diffstat (limited to 'drivers/net/wimax/i2400m/driver.c')
-rw-r--r-- | drivers/net/wimax/i2400m/driver.c | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index 810eda7dbdba..10673af5a7f0 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c | |||
@@ -765,9 +765,7 @@ void __i2400m_dev_reset_handle(struct work_struct *ws) | |||
765 | wmb(); /* see i2400m->updown's documentation */ | 765 | wmb(); /* see i2400m->updown's documentation */ |
766 | dev_err(dev, "%s: cannot start the device: %d\n", | 766 | dev_err(dev, "%s: cannot start the device: %d\n", |
767 | reason, result); | 767 | reason, result); |
768 | result = i2400m->bus_reset(i2400m, I2400M_RT_BUS); | 768 | result = -EUCLEAN; |
769 | if (result >= 0) | ||
770 | result = -ENODEV; | ||
771 | } | 769 | } |
772 | out_unlock: | 770 | out_unlock: |
773 | if (i2400m->reset_ctx) { | 771 | if (i2400m->reset_ctx) { |
@@ -775,6 +773,12 @@ out_unlock: | |||
775 | complete(&ctx->completion); | 773 | complete(&ctx->completion); |
776 | } | 774 | } |
777 | mutex_unlock(&i2400m->init_mutex); | 775 | mutex_unlock(&i2400m->init_mutex); |
776 | if (result == -EUCLEAN) { | ||
777 | /* ops, need to clean up [w/ init_mutex not held] */ | ||
778 | result = i2400m->bus_reset(i2400m, I2400M_RT_BUS); | ||
779 | if (result >= 0) | ||
780 | result = -ENODEV; | ||
781 | } | ||
778 | out: | 782 | out: |
779 | i2400m_put(i2400m); | 783 | i2400m_put(i2400m); |
780 | kfree(iw); | 784 | kfree(iw); |