diff options
-rw-r--r-- | drivers/net/wimax/i2400m/i2400m-sdio.h | 7 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/sdio-fw.c | 109 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/sdio-rx.c | 47 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/sdio.c | 18 |
4 files changed, 101 insertions, 80 deletions
diff --git a/drivers/net/wimax/i2400m/i2400m-sdio.h b/drivers/net/wimax/i2400m/i2400m-sdio.h index 207172165ba2..9c4e3189f7b5 100644 --- a/drivers/net/wimax/i2400m/i2400m-sdio.h +++ b/drivers/net/wimax/i2400m/i2400m-sdio.h | |||
@@ -107,6 +107,10 @@ struct i2400ms { | |||
107 | char tx_wq_name[32]; | 107 | char tx_wq_name[32]; |
108 | 108 | ||
109 | struct dentry *debugfs_dentry; | 109 | struct dentry *debugfs_dentry; |
110 | |||
111 | wait_queue_head_t bm_wfa_wq; | ||
112 | int bm_wait_result; | ||
113 | size_t bm_ack_size; | ||
110 | }; | 114 | }; |
111 | 115 | ||
112 | 116 | ||
@@ -131,4 +135,7 @@ extern ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *, | |||
131 | extern ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *, | 135 | extern ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *, |
132 | struct i2400m_bootrom_header *, | 136 | struct i2400m_bootrom_header *, |
133 | size_t); | 137 | size_t); |
138 | extern void i2400ms_bus_bm_release(struct i2400m *); | ||
139 | extern int i2400ms_bus_bm_setup(struct i2400m *); | ||
140 | |||
134 | #endif /* #ifndef __I2400M_SDIO_H__ */ | 141 | #endif /* #ifndef __I2400M_SDIO_H__ */ |
diff --git a/drivers/net/wimax/i2400m/sdio-fw.c b/drivers/net/wimax/i2400m/sdio-fw.c index 3487205d8f50..7d6ec0f475f8 100644 --- a/drivers/net/wimax/i2400m/sdio-fw.c +++ b/drivers/net/wimax/i2400m/sdio-fw.c | |||
@@ -46,17 +46,24 @@ | |||
46 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | 46 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> |
47 | * - SDIO rehash for changes in the bus-driver model | 47 | * - SDIO rehash for changes in the bus-driver model |
48 | * | 48 | * |
49 | * Dirk Brandewie <dirk.j.brandewie@intel.com> | ||
50 | * - Make it IRQ based, not polling | ||
51 | * | ||
49 | * THE PROCEDURE | 52 | * THE PROCEDURE |
50 | * | 53 | * |
51 | * See fw.c for the generic description of this procedure. | 54 | * See fw.c for the generic description of this procedure. |
52 | * | 55 | * |
53 | * This file implements only the SDIO specifics. It boils down to how | 56 | * This file implements only the SDIO specifics. It boils down to how |
54 | * to send a command and waiting for an acknowledgement from the | 57 | * to send a command and waiting for an acknowledgement from the |
55 | * device. We do polled reads. | 58 | * device. |
59 | * | ||
60 | * All this code is sequential -- all i2400ms_bus_bm_*() functions are | ||
61 | * executed in the same thread, except i2400ms_bm_irq() [on its own by | ||
62 | * the SDIO driver]. This makes it possible to avoid locking. | ||
56 | * | 63 | * |
57 | * COMMAND EXECUTION | 64 | * COMMAND EXECUTION |
58 | * | 65 | * |
59 | * THe generic firmware upload code will call i2400m_bus_bm_cmd_send() | 66 | * The generic firmware upload code will call i2400m_bus_bm_cmd_send() |
60 | * to send commands. | 67 | * to send commands. |
61 | * | 68 | * |
62 | * The SDIO devices expects things in 256 byte blocks, so it will pad | 69 | * The SDIO devices expects things in 256 byte blocks, so it will pad |
@@ -64,12 +71,15 @@ | |||
64 | * | 71 | * |
65 | * ACK RECEPTION | 72 | * ACK RECEPTION |
66 | * | 73 | * |
67 | * This works in polling mode -- the fw loader says when to wait for | 74 | * This works in IRQ mode -- the fw loader says when to wait for data |
68 | * data and for that it calls i2400ms_bus_bm_wait_for_ack(). | 75 | * and for that it calls i2400ms_bus_bm_wait_for_ack(). |
69 | * | 76 | * |
70 | * This will poll the device for data until it is received. We need to | 77 | * This checks if there is any data available (RX size > 0); if not, |
71 | * receive at least as much bytes as where asked for (although it'll | 78 | * waits for the IRQ handler to notify about it. Once there is data, |
72 | * always be a multiple of 256 bytes). | 79 | * it is read and passed to the caller. Doing it this way we don't |
80 | * need much coordination/locking, and it makes it much more difficult | ||
81 | * for an interrupt to be lost and the wait_for_ack() function getting | ||
82 | * stuck even when data is pending. | ||
73 | */ | 83 | */ |
74 | #include <linux/mmc/sdio_func.h> | 84 | #include <linux/mmc/sdio_func.h> |
75 | #include "i2400m-sdio.h" | 85 | #include "i2400m-sdio.h" |
@@ -78,6 +88,7 @@ | |||
78 | #define D_SUBMODULE fw | 88 | #define D_SUBMODULE fw |
79 | #include "sdio-debug-levels.h" | 89 | #include "sdio-debug-levels.h" |
80 | 90 | ||
91 | |||
81 | /* | 92 | /* |
82 | * Send a boot-mode command to the SDIO function | 93 | * Send a boot-mode command to the SDIO function |
83 | * | 94 | * |
@@ -139,7 +150,7 @@ error_too_big: | |||
139 | 150 | ||
140 | 151 | ||
141 | /* | 152 | /* |
142 | * Read an ack from the device's boot-mode (polling) | 153 | * Read an ack from the device's boot-mode |
143 | * | 154 | * |
144 | * @i2400m: | 155 | * @i2400m: |
145 | * @_ack: pointer to where to store the read data | 156 | * @_ack: pointer to where to store the read data |
@@ -150,75 +161,49 @@ error_too_big: | |||
150 | * The ACK for a BM command is always at least sizeof(*ack) bytes, so | 161 | * The ACK for a BM command is always at least sizeof(*ack) bytes, so |
151 | * check for that. We don't need to check for device reboots | 162 | * check for that. We don't need to check for device reboots |
152 | * | 163 | * |
153 | * NOTE: We do an artificial timeout of 1 sec over the SDIO timeout; | ||
154 | * this way we have control over it...there is no way that I know | ||
155 | * of setting an SDIO transaction timeout. | ||
156 | */ | 164 | */ |
157 | ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *i2400m, | 165 | ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *i2400m, |
158 | struct i2400m_bootrom_header *ack, | 166 | struct i2400m_bootrom_header *ack, |
159 | size_t ack_size) | 167 | size_t ack_size) |
160 | { | 168 | { |
161 | int result; | 169 | ssize_t result; |
162 | ssize_t rx_size; | ||
163 | u64 timeout; | ||
164 | struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); | 170 | struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); |
165 | struct sdio_func *func = i2400ms->func; | 171 | struct sdio_func *func = i2400ms->func; |
166 | struct device *dev = &func->dev; | 172 | struct device *dev = &func->dev; |
173 | int size; | ||
167 | 174 | ||
168 | BUG_ON(sizeof(*ack) > ack_size); | 175 | BUG_ON(sizeof(*ack) > ack_size); |
169 | 176 | ||
170 | d_fnstart(5, dev, "(i2400m %p ack %p size %zu)\n", | 177 | d_fnstart(5, dev, "(i2400m %p ack %p size %zu)\n", |
171 | i2400m, ack, ack_size); | 178 | i2400m, ack, ack_size); |
172 | 179 | ||
173 | timeout = get_jiffies_64() + 2 * HZ; | 180 | spin_lock(&i2400m->rx_lock); |
174 | sdio_claim_host(func); | 181 | i2400ms->bm_ack_size = -EINPROGRESS; |
175 | while (1) { | 182 | spin_unlock(&i2400m->rx_lock); |
176 | if (time_after64(get_jiffies_64(), timeout)) { | ||
177 | rx_size = -ETIMEDOUT; | ||
178 | dev_err(dev, "timeout waiting for ack data\n"); | ||
179 | goto error_timedout; | ||
180 | } | ||
181 | 183 | ||
182 | /* Find the RX size, check if it fits or not -- it if | 184 | result = wait_event_timeout(i2400ms->bm_wfa_wq, |
183 | * doesn't fit, fail, as we have no way to dispose of | 185 | i2400ms->bm_ack_size != -EINPROGRESS, |
184 | * the extra data. */ | 186 | 2 * HZ); |
185 | rx_size = __i2400ms_rx_get_size(i2400ms); | 187 | if (result == 0) { |
186 | if (rx_size < 0) | 188 | result = -ETIMEDOUT; |
187 | goto error_rx_get_size; | 189 | dev_err(dev, "BM: error waiting for an ack\n"); |
188 | result = -ENOSPC; /* Check it fits */ | 190 | goto error_timeout; |
189 | if (rx_size < sizeof(*ack)) { | 191 | } |
190 | rx_size = -EIO; | ||
191 | dev_err(dev, "HW BUG? received is too small (%zu vs " | ||
192 | "%zu needed)\n", sizeof(*ack), rx_size); | ||
193 | goto error_too_small; | ||
194 | } | ||
195 | if (rx_size > I2400M_BM_ACK_BUF_SIZE) { | ||
196 | dev_err(dev, "SW BUG? BM_ACK_BUF is too small (%u vs " | ||
197 | "%zu needed)\n", I2400M_BM_ACK_BUF_SIZE, | ||
198 | rx_size); | ||
199 | goto error_too_small; | ||
200 | } | ||
201 | 192 | ||
202 | /* Read it */ | 193 | spin_lock(&i2400m->rx_lock); |
203 | result = sdio_memcpy_fromio(func, i2400m->bm_ack_buf, | 194 | result = i2400ms->bm_ack_size; |
204 | I2400MS_DATA_ADDR, rx_size); | 195 | BUG_ON(result == -EINPROGRESS); |
205 | if (result == -ETIMEDOUT || result == -ETIME) | 196 | if (result < 0) /* so we exit when rx_release() is called */ |
206 | continue; | 197 | dev_err(dev, "BM: %s failed: %zd\n", __func__, result); |
207 | if (result < 0) { | 198 | else { |
208 | dev_err(dev, "BM SDIO receive (%zu B) failed: %d\n", | 199 | size = min(ack_size, i2400ms->bm_ack_size); |
209 | rx_size, result); | 200 | memcpy(ack, i2400m->bm_ack_buf, size); |
210 | goto error_read; | ||
211 | } else | ||
212 | break; | ||
213 | } | 201 | } |
214 | rx_size = min((ssize_t)ack_size, rx_size); | 202 | i2400ms->bm_ack_size = -EINPROGRESS; |
215 | memcpy(ack, i2400m->bm_ack_buf, rx_size); | 203 | spin_unlock(&i2400m->rx_lock); |
216 | error_read: | 204 | |
217 | error_too_small: | 205 | error_timeout: |
218 | error_rx_get_size: | 206 | d_fnend(5, dev, "(i2400m %p ack %p size %zu) = %zd\n", |
219 | error_timedout: | 207 | i2400m, ack, ack_size, result); |
220 | sdio_release_host(func); | 208 | return result; |
221 | d_fnend(5, dev, "(i2400m %p ack %p size %zu) = %ld\n", | ||
222 | i2400m, ack, ack_size, (long) rx_size); | ||
223 | return rx_size; | ||
224 | } | 209 | } |
diff --git a/drivers/net/wimax/i2400m/sdio-rx.c b/drivers/net/wimax/i2400m/sdio-rx.c index a3008b904f7d..321beadf6e47 100644 --- a/drivers/net/wimax/i2400m/sdio-rx.c +++ b/drivers/net/wimax/i2400m/sdio-rx.c | |||
@@ -69,6 +69,13 @@ | |||
69 | #define D_SUBMODULE rx | 69 | #define D_SUBMODULE rx |
70 | #include "sdio-debug-levels.h" | 70 | #include "sdio-debug-levels.h" |
71 | 71 | ||
72 | static const __le32 i2400m_ACK_BARKER[4] = { | ||
73 | __constant_cpu_to_le32(I2400M_ACK_BARKER), | ||
74 | __constant_cpu_to_le32(I2400M_ACK_BARKER), | ||
75 | __constant_cpu_to_le32(I2400M_ACK_BARKER), | ||
76 | __constant_cpu_to_le32(I2400M_ACK_BARKER) | ||
77 | }; | ||
78 | |||
72 | 79 | ||
73 | /* | 80 | /* |
74 | * Read and return the amount of bytes available for RX | 81 | * Read and return the amount of bytes available for RX |
@@ -131,25 +138,35 @@ void i2400ms_rx(struct i2400ms *i2400ms) | |||
131 | ret = rx_size; | 138 | ret = rx_size; |
132 | goto error_get_size; | 139 | goto error_get_size; |
133 | } | 140 | } |
141 | |||
134 | ret = -ENOMEM; | 142 | ret = -ENOMEM; |
135 | skb = alloc_skb(rx_size, GFP_ATOMIC); | 143 | skb = alloc_skb(rx_size, GFP_ATOMIC); |
136 | if (NULL == skb) { | 144 | if (NULL == skb) { |
137 | dev_err(dev, "RX: unable to alloc skb\n"); | 145 | dev_err(dev, "RX: unable to alloc skb\n"); |
138 | goto error_alloc_skb; | 146 | goto error_alloc_skb; |
139 | } | 147 | } |
140 | |||
141 | ret = sdio_memcpy_fromio(func, skb->data, | 148 | ret = sdio_memcpy_fromio(func, skb->data, |
142 | I2400MS_DATA_ADDR, rx_size); | 149 | I2400MS_DATA_ADDR, rx_size); |
143 | if (ret < 0) { | 150 | if (ret < 0) { |
144 | dev_err(dev, "RX: SDIO data read failed: %d\n", ret); | 151 | dev_err(dev, "RX: SDIO data read failed: %d\n", ret); |
145 | goto error_memcpy_fromio; | 152 | goto error_memcpy_fromio; |
146 | } | 153 | } |
147 | /* Check if device has reset */ | 154 | |
148 | if (!memcmp(skb->data, i2400m_NBOOT_BARKER, | 155 | rmb(); /* make sure we get boot_mode from dev_reset_handle */ |
149 | sizeof(i2400m_NBOOT_BARKER)) | 156 | if (i2400m->boot_mode == 1) { |
150 | || !memcmp(skb->data, i2400m_SBOOT_BARKER, | 157 | spin_lock(&i2400m->rx_lock); |
151 | sizeof(i2400m_SBOOT_BARKER))) { | 158 | i2400ms->bm_ack_size = rx_size; |
159 | spin_unlock(&i2400m->rx_lock); | ||
160 | memcpy(i2400m->bm_ack_buf, skb->data, rx_size); | ||
161 | wake_up(&i2400ms->bm_wfa_wq); | ||
162 | dev_err(dev, "RX: SDIO boot mode message\n"); | ||
163 | kfree_skb(skb); | ||
164 | } else if (unlikely(!memcmp(skb->data, i2400m_NBOOT_BARKER, | ||
165 | sizeof(i2400m_NBOOT_BARKER)) | ||
166 | || !memcmp(skb->data, i2400m_SBOOT_BARKER, | ||
167 | sizeof(i2400m_SBOOT_BARKER)))) { | ||
152 | ret = i2400m_dev_reset_handle(i2400m); | 168 | ret = i2400m_dev_reset_handle(i2400m); |
169 | dev_err(dev, "RX: SDIO reboot barker\n"); | ||
153 | kfree_skb(skb); | 170 | kfree_skb(skb); |
154 | } else { | 171 | } else { |
155 | skb_put(skb, rx_size); | 172 | skb_put(skb, rx_size); |
@@ -179,7 +196,6 @@ void i2400ms_irq(struct sdio_func *func) | |||
179 | { | 196 | { |
180 | int ret; | 197 | int ret; |
181 | struct i2400ms *i2400ms = sdio_get_drvdata(func); | 198 | struct i2400ms *i2400ms = sdio_get_drvdata(func); |
182 | struct i2400m *i2400m = &i2400ms->i2400m; | ||
183 | struct device *dev = &func->dev; | 199 | struct device *dev = &func->dev; |
184 | int val; | 200 | int val; |
185 | 201 | ||
@@ -194,10 +210,7 @@ void i2400ms_irq(struct sdio_func *func) | |||
194 | goto error_no_irq; | 210 | goto error_no_irq; |
195 | } | 211 | } |
196 | sdio_writeb(func, 1, I2400MS_INTR_CLEAR_ADDR, &ret); | 212 | sdio_writeb(func, 1, I2400MS_INTR_CLEAR_ADDR, &ret); |
197 | if (WARN_ON(i2400m->boot_mode != 0)) | 213 | i2400ms_rx(i2400ms); |
198 | dev_err(dev, "RX: SW BUG? boot mode and IRQ is up?\n"); | ||
199 | else | ||
200 | i2400ms_rx(i2400ms); | ||
201 | error_no_irq: | 214 | error_no_irq: |
202 | d_fnend(6, dev, "(i2400ms %p) = void\n", i2400ms); | 215 | d_fnend(6, dev, "(i2400ms %p) = void\n", i2400ms); |
203 | return; | 216 | return; |
@@ -214,8 +227,15 @@ int i2400ms_rx_setup(struct i2400ms *i2400ms) | |||
214 | int result; | 227 | int result; |
215 | struct sdio_func *func = i2400ms->func; | 228 | struct sdio_func *func = i2400ms->func; |
216 | struct device *dev = &func->dev; | 229 | struct device *dev = &func->dev; |
230 | struct i2400m *i2400m = &i2400ms->i2400m; | ||
217 | 231 | ||
218 | d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms); | 232 | d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms); |
233 | |||
234 | init_waitqueue_head(&i2400ms->bm_wfa_wq); | ||
235 | spin_lock(&i2400m->rx_lock); | ||
236 | i2400ms->bm_wait_result = -EINPROGRESS; | ||
237 | spin_unlock(&i2400m->rx_lock); | ||
238 | |||
219 | sdio_claim_host(func); | 239 | sdio_claim_host(func); |
220 | result = sdio_claim_irq(func, i2400ms_irq); | 240 | result = sdio_claim_irq(func, i2400ms_irq); |
221 | if (result < 0) { | 241 | if (result < 0) { |
@@ -245,8 +265,13 @@ void i2400ms_rx_release(struct i2400ms *i2400ms) | |||
245 | int result; | 265 | int result; |
246 | struct sdio_func *func = i2400ms->func; | 266 | struct sdio_func *func = i2400ms->func; |
247 | struct device *dev = &func->dev; | 267 | struct device *dev = &func->dev; |
268 | struct i2400m *i2400m = &i2400ms->i2400m; | ||
248 | 269 | ||
249 | d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms); | 270 | d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms); |
271 | spin_lock(&i2400m->rx_lock); | ||
272 | i2400ms->bm_ack_size = -EINTR; | ||
273 | spin_unlock(&i2400m->rx_lock); | ||
274 | wake_up_all(&i2400ms->bm_wfa_wq); | ||
250 | sdio_claim_host(func); | 275 | sdio_claim_host(func); |
251 | sdio_writeb(func, 0, I2400MS_INTR_ENABLE_ADDR, &result); | 276 | sdio_writeb(func, 0, I2400MS_INTR_ENABLE_ADDR, &result); |
252 | sdio_release_irq(func); | 277 | sdio_release_irq(func); |
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c index 74de174a4c44..2538825d1c66 100644 --- a/drivers/net/wimax/i2400m/sdio.c +++ b/drivers/net/wimax/i2400m/sdio.c | |||
@@ -156,19 +156,14 @@ int i2400ms_bus_dev_start(struct i2400m *i2400m) | |||
156 | 156 | ||
157 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); | 157 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); |
158 | msleep(200); | 158 | msleep(200); |
159 | result = i2400ms_rx_setup(i2400ms); | ||
160 | if (result < 0) | ||
161 | goto error_rx_setup; | ||
162 | result = i2400ms_tx_setup(i2400ms); | 159 | result = i2400ms_tx_setup(i2400ms); |
163 | if (result < 0) | 160 | if (result < 0) |
164 | goto error_tx_setup; | 161 | goto error_tx_setup; |
165 | d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); | 162 | d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); |
166 | return result; | 163 | return result; |
167 | 164 | ||
168 | i2400ms_tx_release(i2400ms); | ||
169 | error_tx_setup: | 165 | error_tx_setup: |
170 | i2400ms_rx_release(i2400ms); | 166 | i2400ms_tx_release(i2400ms); |
171 | error_rx_setup: | ||
172 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); | 167 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); |
173 | return result; | 168 | return result; |
174 | } | 169 | } |
@@ -182,7 +177,6 @@ void i2400ms_bus_dev_stop(struct i2400m *i2400m) | |||
182 | struct device *dev = &func->dev; | 177 | struct device *dev = &func->dev; |
183 | 178 | ||
184 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); | 179 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); |
185 | i2400ms_rx_release(i2400ms); | ||
186 | i2400ms_tx_release(i2400ms); | 180 | i2400ms_tx_release(i2400ms); |
187 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); | 181 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); |
188 | } | 182 | } |
@@ -296,6 +290,7 @@ do_bus_reset: | |||
296 | if (i2400m->wimax_dev.net_dev->reg_state == NETREG_REGISTERED) | 290 | if (i2400m->wimax_dev.net_dev->reg_state == NETREG_REGISTERED) |
297 | netif_tx_disable(i2400m->wimax_dev.net_dev); | 291 | netif_tx_disable(i2400m->wimax_dev.net_dev); |
298 | 292 | ||
293 | i2400ms_rx_release(i2400ms); | ||
299 | sdio_claim_host(i2400ms->func); | 294 | sdio_claim_host(i2400ms->func); |
300 | sdio_disable_func(i2400ms->func); | 295 | sdio_disable_func(i2400ms->func); |
301 | sdio_release_host(i2400ms->func); | 296 | sdio_release_host(i2400ms->func); |
@@ -304,6 +299,8 @@ do_bus_reset: | |||
304 | msleep(40); | 299 | msleep(40); |
305 | 300 | ||
306 | result = i2400ms_enable_function(i2400ms->func); | 301 | result = i2400ms_enable_function(i2400ms->func); |
302 | if (result >= 0) | ||
303 | i2400ms_rx_setup(i2400ms); | ||
307 | } else | 304 | } else |
308 | BUG(); | 305 | BUG(); |
309 | if (result < 0 && rt != I2400M_RT_BUS) { | 306 | if (result < 0 && rt != I2400M_RT_BUS) { |
@@ -449,6 +446,10 @@ int i2400ms_probe(struct sdio_func *func, | |||
449 | goto error_func_enable; | 446 | goto error_func_enable; |
450 | } | 447 | } |
451 | 448 | ||
449 | result = i2400ms_rx_setup(i2400ms); | ||
450 | if (result < 0) | ||
451 | goto error_rx_setup; | ||
452 | |||
452 | result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT); | 453 | result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT); |
453 | if (result < 0) { | 454 | if (result < 0) { |
454 | dev_err(dev, "cannot setup device: %d\n", result); | 455 | dev_err(dev, "cannot setup device: %d\n", result); |
@@ -466,6 +467,8 @@ int i2400ms_probe(struct sdio_func *func, | |||
466 | error_debugfs_add: | 467 | error_debugfs_add: |
467 | i2400m_release(i2400m); | 468 | i2400m_release(i2400m); |
468 | error_setup: | 469 | error_setup: |
470 | i2400ms_rx_release(i2400ms); | ||
471 | error_rx_setup: | ||
469 | sdio_claim_host(func); | 472 | sdio_claim_host(func); |
470 | sdio_disable_func(func); | 473 | sdio_disable_func(func); |
471 | sdio_release_host(func); | 474 | sdio_release_host(func); |
@@ -488,6 +491,7 @@ void i2400ms_remove(struct sdio_func *func) | |||
488 | 491 | ||
489 | d_fnstart(3, dev, "SDIO func %p\n", func); | 492 | d_fnstart(3, dev, "SDIO func %p\n", func); |
490 | debugfs_remove_recursive(i2400ms->debugfs_dentry); | 493 | debugfs_remove_recursive(i2400ms->debugfs_dentry); |
494 | i2400ms_rx_release(i2400ms); | ||
491 | i2400m_release(i2400m); | 495 | i2400m_release(i2400m); |
492 | sdio_set_drvdata(func, NULL); | 496 | sdio_set_drvdata(func, NULL); |
493 | sdio_claim_host(func); | 497 | sdio_claim_host(func); |