diff options
Diffstat (limited to 'drivers/net/wimax/i2400m/sdio-rx.c')
-rw-r--r-- | drivers/net/wimax/i2400m/sdio-rx.c | 47 |
1 files changed, 36 insertions, 11 deletions
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); |