diff options
author | Inaky Perez-Gonzalez <inaky@linux.intel.com> | 2009-10-23 20:48:36 -0400 |
---|---|---|
committer | Inaky Perez-Gonzalez <inaky@linux.intel.com> | 2009-11-03 15:49:39 -0500 |
commit | fae92216da87d1c78aa51c4503acb312a47266e9 (patch) | |
tree | 0df0784e265e6ec55eb0ed5566b8bf99e1dd2ba7 /drivers/net/wimax | |
parent | 02eb41ef2a8631022fd90e096c57562dec9e7a9a (diff) |
wimax/i2400m: don't retry SDIO enable in probe() paths
The iwmc3200 has a quirk where retrying SDIO enable during the probe()
path causes bad interactions with the TOP function controller that
causes a reset storm. The workaround is simply not to retry an SDIO
enable in said path (and still do in the reset / reinitialization
paths).
The driver does so by checking i2400ms->debugfs_dentry to see if it
has been initialized; if not, it is in the probe() path. Document said
fact in i2400ms->debugfs_entry.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Diffstat (limited to 'drivers/net/wimax')
-rw-r--r-- | drivers/net/wimax/i2400m/i2400m-sdio.h | 8 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/sdio.c | 13 |
2 files changed, 20 insertions, 1 deletions
diff --git a/drivers/net/wimax/i2400m/i2400m-sdio.h b/drivers/net/wimax/i2400m/i2400m-sdio.h index fba482c08d66..b9c4bed3b457 100644 --- a/drivers/net/wimax/i2400m/i2400m-sdio.h +++ b/drivers/net/wimax/i2400m/i2400m-sdio.h | |||
@@ -100,6 +100,14 @@ enum { | |||
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. |
103 | * | ||
104 | * @debugfs_dentry: dentry for the SDIO specific debugfs files | ||
105 | * | ||
106 | * Note this value is set to NULL upon destruction; this is | ||
107 | * because some routinges use it to determine if we are inside the | ||
108 | * probe() path or some other path. When debugfs is disabled, | ||
109 | * creation sets the dentry to '(void*) -ENODEV', which is valid | ||
110 | * for the test. | ||
103 | */ | 111 | */ |
104 | struct i2400ms { | 112 | struct i2400ms { |
105 | struct i2400m i2400m; /* FIRST! See doc */ | 113 | struct i2400m i2400m; /* FIRST! See doc */ |
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c index 079f900e9ae5..e8ad85c7a799 100644 --- a/drivers/net/wimax/i2400m/sdio.c +++ b/drivers/net/wimax/i2400m/sdio.c | |||
@@ -159,6 +159,10 @@ function_enabled: | |||
159 | /* | 159 | /* |
160 | * Setup minimal device communication infrastructure needed to at | 160 | * Setup minimal device communication infrastructure needed to at |
161 | * least be able to update the firmware. | 161 | * least be able to update the firmware. |
162 | * | ||
163 | * Note the ugly trick: if we are in the probe path | ||
164 | * (i2400ms->debugfs_dentry == NULL), we only retry function | ||
165 | * enablement one, to avoid racing with the iwmc3200 top controller. | ||
162 | */ | 166 | */ |
163 | static | 167 | static |
164 | int i2400ms_bus_setup(struct i2400m *i2400m) | 168 | int i2400ms_bus_setup(struct i2400m *i2400m) |
@@ -168,6 +172,7 @@ int i2400ms_bus_setup(struct i2400m *i2400m) | |||
168 | container_of(i2400m, struct i2400ms, i2400m); | 172 | container_of(i2400m, struct i2400ms, i2400m); |
169 | struct device *dev = i2400m_dev(i2400m); | 173 | struct device *dev = i2400m_dev(i2400m); |
170 | struct sdio_func *func = i2400ms->func; | 174 | struct sdio_func *func = i2400ms->func; |
175 | int retries; | ||
171 | 176 | ||
172 | sdio_claim_host(func); | 177 | sdio_claim_host(func); |
173 | result = sdio_set_block_size(func, I2400MS_BLK_SIZE); | 178 | result = sdio_set_block_size(func, I2400MS_BLK_SIZE); |
@@ -177,7 +182,11 @@ int i2400ms_bus_setup(struct i2400m *i2400m) | |||
177 | goto error_set_blk_size; | 182 | goto error_set_blk_size; |
178 | } | 183 | } |
179 | 184 | ||
180 | result = i2400ms_enable_function(i2400ms, 1); | 185 | if (i2400ms->iwmc3200 && i2400ms->debugfs_dentry == NULL) |
186 | retries = 0; | ||
187 | else | ||
188 | retries = 1; | ||
189 | result = i2400ms_enable_function(i2400ms, retries); | ||
181 | if (result < 0) { | 190 | if (result < 0) { |
182 | dev_err(dev, "Cannot enable SDIO function: %d\n", result); | 191 | dev_err(dev, "Cannot enable SDIO function: %d\n", result); |
183 | goto error_func_enable; | 192 | goto error_func_enable; |
@@ -415,6 +424,7 @@ int i2400ms_debugfs_add(struct i2400ms *i2400ms) | |||
415 | 424 | ||
416 | error: | 425 | error: |
417 | debugfs_remove_recursive(i2400ms->debugfs_dentry); | 426 | debugfs_remove_recursive(i2400ms->debugfs_dentry); |
427 | i2400ms->debugfs_dentry = NULL; | ||
418 | return result; | 428 | return result; |
419 | } | 429 | } |
420 | 430 | ||
@@ -531,6 +541,7 @@ void i2400ms_remove(struct sdio_func *func) | |||
531 | 541 | ||
532 | d_fnstart(3, dev, "SDIO func %p\n", func); | 542 | d_fnstart(3, dev, "SDIO func %p\n", func); |
533 | debugfs_remove_recursive(i2400ms->debugfs_dentry); | 543 | debugfs_remove_recursive(i2400ms->debugfs_dentry); |
544 | i2400ms->debugfs_dentry = NULL; | ||
534 | i2400m_release(i2400m); | 545 | i2400m_release(i2400m); |
535 | sdio_set_drvdata(func, NULL); | 546 | sdio_set_drvdata(func, NULL); |
536 | free_netdev(net_dev); | 547 | free_netdev(net_dev); |