diff options
Diffstat (limited to 'drivers/net/wireless/mwifiex/sdio.c')
-rw-r--r-- | drivers/net/wireless/mwifiex/sdio.c | 1754 |
1 files changed, 1754 insertions, 0 deletions
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c new file mode 100644 index 000000000000..d425dbd91d19 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sdio.c | |||
@@ -0,0 +1,1754 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: SDIO specific handling | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include <linux/firmware.h> | ||
21 | |||
22 | #include "decl.h" | ||
23 | #include "ioctl.h" | ||
24 | #include "util.h" | ||
25 | #include "fw.h" | ||
26 | #include "main.h" | ||
27 | #include "wmm.h" | ||
28 | #include "11n.h" | ||
29 | #include "sdio.h" | ||
30 | |||
31 | |||
32 | #define SDIO_VERSION "1.0" | ||
33 | |||
34 | static struct mwifiex_if_ops sdio_ops; | ||
35 | |||
36 | static struct semaphore add_remove_card_sem; | ||
37 | |||
38 | /* | ||
39 | * SDIO probe. | ||
40 | * | ||
41 | * This function probes an mwifiex device and registers it. It allocates | ||
42 | * the card structure, enables SDIO function number and initiates the | ||
43 | * device registration and initialization procedure by adding a logical | ||
44 | * interface. | ||
45 | */ | ||
46 | static int | ||
47 | mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) | ||
48 | { | ||
49 | int ret; | ||
50 | struct sdio_mmc_card *card = NULL; | ||
51 | |||
52 | pr_debug("info: vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n", | ||
53 | func->vendor, func->device, func->class, func->num); | ||
54 | |||
55 | card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL); | ||
56 | if (!card) { | ||
57 | pr_err("%s: failed to alloc memory\n", __func__); | ||
58 | return -ENOMEM; | ||
59 | } | ||
60 | |||
61 | card->func = func; | ||
62 | |||
63 | func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; | ||
64 | |||
65 | sdio_claim_host(func); | ||
66 | ret = sdio_enable_func(func); | ||
67 | sdio_release_host(func); | ||
68 | |||
69 | if (ret) { | ||
70 | pr_err("%s: failed to enable function\n", __func__); | ||
71 | kfree(card); | ||
72 | return -EIO; | ||
73 | } | ||
74 | |||
75 | if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops)) { | ||
76 | pr_err("%s: add card failed\n", __func__); | ||
77 | kfree(card); | ||
78 | sdio_claim_host(func); | ||
79 | ret = sdio_disable_func(func); | ||
80 | sdio_release_host(func); | ||
81 | ret = -1; | ||
82 | } | ||
83 | |||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | /* | ||
88 | * SDIO remove. | ||
89 | * | ||
90 | * This function removes the interface and frees up the card structure. | ||
91 | */ | ||
92 | static void | ||
93 | mwifiex_sdio_remove(struct sdio_func *func) | ||
94 | { | ||
95 | struct sdio_mmc_card *card; | ||
96 | |||
97 | pr_debug("info: SDIO func num=%d\n", func->num); | ||
98 | |||
99 | if (func) { | ||
100 | card = sdio_get_drvdata(func); | ||
101 | if (card) { | ||
102 | mwifiex_remove_card(card->adapter, | ||
103 | &add_remove_card_sem); | ||
104 | kfree(card); | ||
105 | } | ||
106 | } | ||
107 | } | ||
108 | |||
109 | /* | ||
110 | * SDIO suspend. | ||
111 | * | ||
112 | * Kernel needs to suspend all functions separately. Therefore all | ||
113 | * registered functions must have drivers with suspend and resume | ||
114 | * methods. Failing that the kernel simply removes the whole card. | ||
115 | * | ||
116 | * If already not suspended, this function allocates and sends a host | ||
117 | * sleep activate request to the firmware and turns off the traffic. | ||
118 | */ | ||
119 | static int mwifiex_sdio_suspend(struct device *dev) | ||
120 | { | ||
121 | struct sdio_func *func = dev_to_sdio_func(dev); | ||
122 | struct sdio_mmc_card *card; | ||
123 | struct mwifiex_adapter *adapter; | ||
124 | mmc_pm_flag_t pm_flag = 0; | ||
125 | int hs_actived = 0; | ||
126 | int i; | ||
127 | int ret = 0; | ||
128 | |||
129 | if (func) { | ||
130 | pm_flag = sdio_get_host_pm_caps(func); | ||
131 | pr_debug("cmd: %s: suspend: PM flag = 0x%x\n", | ||
132 | sdio_func_id(func), pm_flag); | ||
133 | if (!(pm_flag & MMC_PM_KEEP_POWER)) { | ||
134 | pr_err("%s: cannot remain alive while host is" | ||
135 | " suspended\n", sdio_func_id(func)); | ||
136 | return -ENOSYS; | ||
137 | } | ||
138 | |||
139 | card = sdio_get_drvdata(func); | ||
140 | if (!card || !card->adapter) { | ||
141 | pr_err("suspend: invalid card or adapter\n"); | ||
142 | return 0; | ||
143 | } | ||
144 | } else { | ||
145 | pr_err("suspend: sdio_func is not specified\n"); | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | adapter = card->adapter; | ||
150 | |||
151 | /* Enable the Host Sleep */ | ||
152 | hs_actived = mwifiex_enable_hs(adapter); | ||
153 | if (hs_actived) { | ||
154 | pr_debug("cmd: suspend with MMC_PM_KEEP_POWER\n"); | ||
155 | ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); | ||
156 | } | ||
157 | |||
158 | /* Indicate device suspended */ | ||
159 | adapter->is_suspended = true; | ||
160 | |||
161 | for (i = 0; i < adapter->priv_num; i++) | ||
162 | netif_carrier_off(adapter->priv[i]->netdev); | ||
163 | |||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | /* | ||
168 | * SDIO resume. | ||
169 | * | ||
170 | * Kernel needs to suspend all functions separately. Therefore all | ||
171 | * registered functions must have drivers with suspend and resume | ||
172 | * methods. Failing that the kernel simply removes the whole card. | ||
173 | * | ||
174 | * If already not resumed, this function turns on the traffic and | ||
175 | * sends a host sleep cancel request to the firmware. | ||
176 | */ | ||
177 | static int mwifiex_sdio_resume(struct device *dev) | ||
178 | { | ||
179 | struct sdio_func *func = dev_to_sdio_func(dev); | ||
180 | struct sdio_mmc_card *card; | ||
181 | struct mwifiex_adapter *adapter; | ||
182 | mmc_pm_flag_t pm_flag = 0; | ||
183 | int i; | ||
184 | |||
185 | if (func) { | ||
186 | pm_flag = sdio_get_host_pm_caps(func); | ||
187 | card = sdio_get_drvdata(func); | ||
188 | if (!card || !card->adapter) { | ||
189 | pr_err("resume: invalid card or adapter\n"); | ||
190 | return 0; | ||
191 | } | ||
192 | } else { | ||
193 | pr_err("resume: sdio_func is not specified\n"); | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | adapter = card->adapter; | ||
198 | |||
199 | if (!adapter->is_suspended) { | ||
200 | dev_warn(adapter->dev, "device already resumed\n"); | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | adapter->is_suspended = false; | ||
205 | |||
206 | for (i = 0; i < adapter->priv_num; i++) | ||
207 | if (adapter->priv[i]->media_connected) | ||
208 | netif_carrier_on(adapter->priv[i]->netdev); | ||
209 | |||
210 | /* Disable Host Sleep */ | ||
211 | mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), | ||
212 | MWIFIEX_ASYNC_CMD); | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | /* Device ID for SD8787 */ | ||
218 | #define SDIO_DEVICE_ID_MARVELL_8787 (0x9119) | ||
219 | |||
220 | /* WLAN IDs */ | ||
221 | static const struct sdio_device_id mwifiex_ids[] = { | ||
222 | {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787)}, | ||
223 | {}, | ||
224 | }; | ||
225 | |||
226 | MODULE_DEVICE_TABLE(sdio, mwifiex_ids); | ||
227 | |||
228 | static const struct dev_pm_ops mwifiex_sdio_pm_ops = { | ||
229 | .suspend = mwifiex_sdio_suspend, | ||
230 | .resume = mwifiex_sdio_resume, | ||
231 | }; | ||
232 | |||
233 | static struct sdio_driver mwifiex_sdio = { | ||
234 | .name = "mwifiex_sdio", | ||
235 | .id_table = mwifiex_ids, | ||
236 | .probe = mwifiex_sdio_probe, | ||
237 | .remove = mwifiex_sdio_remove, | ||
238 | .drv = { | ||
239 | .owner = THIS_MODULE, | ||
240 | .pm = &mwifiex_sdio_pm_ops, | ||
241 | } | ||
242 | }; | ||
243 | |||
244 | /* | ||
245 | * This function writes data into SDIO card register. | ||
246 | */ | ||
247 | static int | ||
248 | mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u32 data) | ||
249 | { | ||
250 | struct sdio_mmc_card *card = adapter->card; | ||
251 | int ret = -1; | ||
252 | |||
253 | sdio_claim_host(card->func); | ||
254 | sdio_writeb(card->func, (u8) data, reg, &ret); | ||
255 | sdio_release_host(card->func); | ||
256 | |||
257 | return ret; | ||
258 | } | ||
259 | |||
260 | /* | ||
261 | * This function reads data from SDIO card register. | ||
262 | */ | ||
263 | static int | ||
264 | mwifiex_read_reg(struct mwifiex_adapter *adapter, u32 reg, u32 *data) | ||
265 | { | ||
266 | struct sdio_mmc_card *card = adapter->card; | ||
267 | int ret = -1; | ||
268 | u8 val; | ||
269 | |||
270 | sdio_claim_host(card->func); | ||
271 | val = sdio_readb(card->func, reg, &ret); | ||
272 | sdio_release_host(card->func); | ||
273 | |||
274 | *data = val; | ||
275 | |||
276 | return ret; | ||
277 | } | ||
278 | |||
279 | /* | ||
280 | * This function writes multiple data into SDIO card memory. | ||
281 | * | ||
282 | * This does not work in suspended mode. | ||
283 | */ | ||
284 | static int | ||
285 | mwifiex_write_data_sync(struct mwifiex_adapter *adapter, | ||
286 | u8 *buffer, u32 pkt_len, u32 port) | ||
287 | { | ||
288 | struct sdio_mmc_card *card = adapter->card; | ||
289 | int ret = -1; | ||
290 | u8 blk_mode = | ||
291 | (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; | ||
292 | u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; | ||
293 | u32 blk_cnt = | ||
294 | (blk_mode == | ||
295 | BLOCK_MODE) ? (pkt_len / | ||
296 | MWIFIEX_SDIO_BLOCK_SIZE) : pkt_len; | ||
297 | u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK); | ||
298 | |||
299 | if (adapter->is_suspended) { | ||
300 | dev_err(adapter->dev, | ||
301 | "%s: not allowed while suspended\n", __func__); | ||
302 | return -1; | ||
303 | } | ||
304 | |||
305 | sdio_claim_host(card->func); | ||
306 | |||
307 | if (!sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size)) | ||
308 | ret = 0; | ||
309 | |||
310 | sdio_release_host(card->func); | ||
311 | |||
312 | return ret; | ||
313 | } | ||
314 | |||
315 | /* | ||
316 | * This function reads multiple data from SDIO card memory. | ||
317 | */ | ||
318 | static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *buffer, | ||
319 | u32 len, u32 port, u8 claim) | ||
320 | { | ||
321 | struct sdio_mmc_card *card = adapter->card; | ||
322 | int ret = -1; | ||
323 | u8 blk_mode = | ||
324 | (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; | ||
325 | u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; | ||
326 | u32 blk_cnt = | ||
327 | (blk_mode == | ||
328 | BLOCK_MODE) ? (len / MWIFIEX_SDIO_BLOCK_SIZE) : len; | ||
329 | u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK); | ||
330 | |||
331 | if (claim) | ||
332 | sdio_claim_host(card->func); | ||
333 | |||
334 | if (!sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size)) | ||
335 | ret = 0; | ||
336 | |||
337 | if (claim) | ||
338 | sdio_release_host(card->func); | ||
339 | |||
340 | return ret; | ||
341 | } | ||
342 | |||
343 | /* | ||
344 | * This function wakes up the card. | ||
345 | * | ||
346 | * A host power up command is written to the card configuration | ||
347 | * register to wake up the card. | ||
348 | */ | ||
349 | static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) | ||
350 | { | ||
351 | dev_dbg(adapter->dev, "event: wakeup device...\n"); | ||
352 | |||
353 | return mwifiex_write_reg(adapter, CONFIGURATION_REG, HOST_POWER_UP); | ||
354 | } | ||
355 | |||
356 | /* | ||
357 | * This function is called after the card has woken up. | ||
358 | * | ||
359 | * The card configuration register is reset. | ||
360 | */ | ||
361 | static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter) | ||
362 | { | ||
363 | dev_dbg(adapter->dev, "cmd: wakeup device completed\n"); | ||
364 | |||
365 | return mwifiex_write_reg(adapter, CONFIGURATION_REG, 0); | ||
366 | } | ||
367 | |||
368 | /* | ||
369 | * This function initializes the IO ports. | ||
370 | * | ||
371 | * The following operations are performed - | ||
372 | * - Read the IO ports (0, 1 and 2) | ||
373 | * - Set host interrupt Reset-To-Read to clear | ||
374 | * - Set auto re-enable interrupt | ||
375 | */ | ||
376 | static int mwifiex_init_sdio_ioport(struct mwifiex_adapter *adapter) | ||
377 | { | ||
378 | u32 reg; | ||
379 | |||
380 | adapter->ioport = 0; | ||
381 | |||
382 | /* Read the IO port */ | ||
383 | if (!mwifiex_read_reg(adapter, IO_PORT_0_REG, ®)) | ||
384 | adapter->ioport |= (reg & 0xff); | ||
385 | else | ||
386 | return -1; | ||
387 | |||
388 | if (!mwifiex_read_reg(adapter, IO_PORT_1_REG, ®)) | ||
389 | adapter->ioport |= ((reg & 0xff) << 8); | ||
390 | else | ||
391 | return -1; | ||
392 | |||
393 | if (!mwifiex_read_reg(adapter, IO_PORT_2_REG, ®)) | ||
394 | adapter->ioport |= ((reg & 0xff) << 16); | ||
395 | else | ||
396 | return -1; | ||
397 | |||
398 | pr_debug("info: SDIO FUNC1 IO port: %#x\n", adapter->ioport); | ||
399 | |||
400 | /* Set Host interrupt reset to read to clear */ | ||
401 | if (!mwifiex_read_reg(adapter, HOST_INT_RSR_REG, ®)) | ||
402 | mwifiex_write_reg(adapter, HOST_INT_RSR_REG, | ||
403 | reg | SDIO_INT_MASK); | ||
404 | else | ||
405 | return -1; | ||
406 | |||
407 | /* Dnld/Upld ready set to auto reset */ | ||
408 | if (!mwifiex_read_reg(adapter, CARD_MISC_CFG_REG, ®)) | ||
409 | mwifiex_write_reg(adapter, CARD_MISC_CFG_REG, | ||
410 | reg | AUTO_RE_ENABLE_INT); | ||
411 | else | ||
412 | return -1; | ||
413 | |||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | /* | ||
418 | * This function sends data to the card. | ||
419 | */ | ||
420 | static int mwifiex_write_data_to_card(struct mwifiex_adapter *adapter, | ||
421 | u8 *payload, u32 pkt_len, u32 port) | ||
422 | { | ||
423 | u32 i = 0; | ||
424 | int ret; | ||
425 | |||
426 | do { | ||
427 | ret = mwifiex_write_data_sync(adapter, payload, pkt_len, port); | ||
428 | if (ret) { | ||
429 | i++; | ||
430 | dev_err(adapter->dev, "host_to_card, write iomem" | ||
431 | " (%d) failed: %d\n", i, ret); | ||
432 | if (mwifiex_write_reg(adapter, | ||
433 | CONFIGURATION_REG, 0x04)) | ||
434 | dev_err(adapter->dev, "write CFG reg failed\n"); | ||
435 | |||
436 | ret = -1; | ||
437 | if (i > MAX_WRITE_IOMEM_RETRY) | ||
438 | return ret; | ||
439 | } | ||
440 | } while (ret == -1); | ||
441 | |||
442 | return ret; | ||
443 | } | ||
444 | |||
445 | /* | ||
446 | * This function gets the read port. | ||
447 | * | ||
448 | * If control port bit is set in MP read bitmap, the control port | ||
449 | * is returned, otherwise the current read port is returned and | ||
450 | * the value is increased (provided it does not reach the maximum | ||
451 | * limit, in which case it is reset to 1) | ||
452 | */ | ||
453 | static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port) | ||
454 | { | ||
455 | struct sdio_mmc_card *card = adapter->card; | ||
456 | u16 rd_bitmap = card->mp_rd_bitmap; | ||
457 | |||
458 | dev_dbg(adapter->dev, "data: mp_rd_bitmap=0x%04x\n", rd_bitmap); | ||
459 | |||
460 | if (!(rd_bitmap & (CTRL_PORT_MASK | DATA_PORT_MASK))) | ||
461 | return -1; | ||
462 | |||
463 | if (card->mp_rd_bitmap & CTRL_PORT_MASK) { | ||
464 | card->mp_rd_bitmap &= (u16) (~CTRL_PORT_MASK); | ||
465 | *port = CTRL_PORT; | ||
466 | dev_dbg(adapter->dev, "data: port=%d mp_rd_bitmap=0x%04x\n", | ||
467 | *port, card->mp_rd_bitmap); | ||
468 | } else { | ||
469 | if (card->mp_rd_bitmap & (1 << card->curr_rd_port)) { | ||
470 | card->mp_rd_bitmap &= | ||
471 | (u16) (~(1 << card->curr_rd_port)); | ||
472 | *port = card->curr_rd_port; | ||
473 | |||
474 | if (++card->curr_rd_port == MAX_PORT) | ||
475 | card->curr_rd_port = 1; | ||
476 | } else { | ||
477 | return -1; | ||
478 | } | ||
479 | |||
480 | dev_dbg(adapter->dev, | ||
481 | "data: port=%d mp_rd_bitmap=0x%04x -> 0x%04x\n", | ||
482 | *port, rd_bitmap, card->mp_rd_bitmap); | ||
483 | } | ||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | /* | ||
488 | * This function gets the write port for data. | ||
489 | * | ||
490 | * The current write port is returned if available and the value is | ||
491 | * increased (provided it does not reach the maximum limit, in which | ||
492 | * case it is reset to 1) | ||
493 | */ | ||
494 | static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u8 *port) | ||
495 | { | ||
496 | struct sdio_mmc_card *card = adapter->card; | ||
497 | u16 wr_bitmap = card->mp_wr_bitmap; | ||
498 | |||
499 | dev_dbg(adapter->dev, "data: mp_wr_bitmap=0x%04x\n", wr_bitmap); | ||
500 | |||
501 | if (!(wr_bitmap & card->mp_data_port_mask)) | ||
502 | return -1; | ||
503 | |||
504 | if (card->mp_wr_bitmap & (1 << card->curr_wr_port)) { | ||
505 | card->mp_wr_bitmap &= (u16) (~(1 << card->curr_wr_port)); | ||
506 | *port = card->curr_wr_port; | ||
507 | if (++card->curr_wr_port == card->mp_end_port) | ||
508 | card->curr_wr_port = 1; | ||
509 | } else { | ||
510 | adapter->data_sent = true; | ||
511 | return -EBUSY; | ||
512 | } | ||
513 | |||
514 | if (*port == CTRL_PORT) { | ||
515 | dev_err(adapter->dev, "invalid data port=%d cur port=%d" | ||
516 | " mp_wr_bitmap=0x%04x -> 0x%04x\n", | ||
517 | *port, card->curr_wr_port, wr_bitmap, | ||
518 | card->mp_wr_bitmap); | ||
519 | return -1; | ||
520 | } | ||
521 | |||
522 | dev_dbg(adapter->dev, "data: port=%d mp_wr_bitmap=0x%04x -> 0x%04x\n", | ||
523 | *port, wr_bitmap, card->mp_wr_bitmap); | ||
524 | |||
525 | return 0; | ||
526 | } | ||
527 | |||
528 | /* | ||
529 | * This function polls the card status. | ||
530 | */ | ||
531 | static int | ||
532 | mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits) | ||
533 | { | ||
534 | u32 tries; | ||
535 | u32 cs; | ||
536 | |||
537 | for (tries = 0; tries < MAX_POLL_TRIES; tries++) { | ||
538 | if (mwifiex_read_reg(adapter, CARD_STATUS_REG, &cs)) | ||
539 | break; | ||
540 | else if ((cs & bits) == bits) | ||
541 | return 0; | ||
542 | |||
543 | udelay(10); | ||
544 | } | ||
545 | |||
546 | dev_err(adapter->dev, "poll card status failed, tries = %d\n", | ||
547 | tries); | ||
548 | return -1; | ||
549 | } | ||
550 | |||
551 | /* | ||
552 | * This function reads the firmware status. | ||
553 | */ | ||
554 | static int | ||
555 | mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat) | ||
556 | { | ||
557 | u32 fws0, fws1; | ||
558 | |||
559 | if (mwifiex_read_reg(adapter, CARD_FW_STATUS0_REG, &fws0)) | ||
560 | return -1; | ||
561 | |||
562 | if (mwifiex_read_reg(adapter, CARD_FW_STATUS1_REG, &fws1)) | ||
563 | return -1; | ||
564 | |||
565 | *dat = (u16) ((fws1 << 8) | fws0); | ||
566 | |||
567 | return 0; | ||
568 | } | ||
569 | |||
570 | /* | ||
571 | * This function disables the host interrupt. | ||
572 | * | ||
573 | * The host interrupt mask is read, the disable bit is reset and | ||
574 | * written back to the card host interrupt mask register. | ||
575 | */ | ||
576 | static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter) | ||
577 | { | ||
578 | u32 host_int_mask; | ||
579 | |||
580 | /* Read back the host_int_mask register */ | ||
581 | if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask)) | ||
582 | return -1; | ||
583 | |||
584 | /* Update with the mask and write back to the register */ | ||
585 | host_int_mask &= ~HOST_INT_DISABLE; | ||
586 | |||
587 | if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, host_int_mask)) { | ||
588 | dev_err(adapter->dev, "disable host interrupt failed\n"); | ||
589 | return -1; | ||
590 | } | ||
591 | |||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | /* | ||
596 | * This function enables the host interrupt. | ||
597 | * | ||
598 | * The host interrupt enable mask is written to the card | ||
599 | * host interrupt mask register. | ||
600 | */ | ||
601 | static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter) | ||
602 | { | ||
603 | /* Simply write the mask to the register */ | ||
604 | if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, HOST_INT_ENABLE)) { | ||
605 | dev_err(adapter->dev, "enable host interrupt failed\n"); | ||
606 | return -1; | ||
607 | } | ||
608 | return 0; | ||
609 | } | ||
610 | |||
611 | /* | ||
612 | * This function sends a data buffer to the card. | ||
613 | */ | ||
614 | static int mwifiex_sdio_card_to_host(struct mwifiex_adapter *adapter, | ||
615 | u32 *type, u8 *buffer, | ||
616 | u32 npayload, u32 ioport) | ||
617 | { | ||
618 | int ret; | ||
619 | u32 nb; | ||
620 | |||
621 | if (!buffer) { | ||
622 | dev_err(adapter->dev, "%s: buffer is NULL\n", __func__); | ||
623 | return -1; | ||
624 | } | ||
625 | |||
626 | ret = mwifiex_read_data_sync(adapter, buffer, npayload, ioport, 1); | ||
627 | |||
628 | if (ret) { | ||
629 | dev_err(adapter->dev, "%s: read iomem failed: %d\n", __func__, | ||
630 | ret); | ||
631 | return -1; | ||
632 | } | ||
633 | |||
634 | nb = le16_to_cpu(*(__le16 *) (buffer)); | ||
635 | if (nb > npayload) { | ||
636 | dev_err(adapter->dev, "%s: invalid packet, nb=%d, npayload=%d\n", | ||
637 | __func__, nb, npayload); | ||
638 | return -1; | ||
639 | } | ||
640 | |||
641 | *type = le16_to_cpu(*(__le16 *) (buffer + 2)); | ||
642 | |||
643 | return ret; | ||
644 | } | ||
645 | |||
646 | /* | ||
647 | * This function downloads the firmware to the card. | ||
648 | * | ||
649 | * Firmware is downloaded to the card in blocks. Every block download | ||
650 | * is tested for CRC errors, and retried a number of times before | ||
651 | * returning failure. | ||
652 | */ | ||
653 | static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, | ||
654 | struct mwifiex_fw_image *fw) | ||
655 | { | ||
656 | int ret; | ||
657 | u8 *firmware = fw->fw_buf; | ||
658 | u32 firmware_len = fw->fw_len; | ||
659 | u32 offset = 0; | ||
660 | u32 base0, base1; | ||
661 | u8 *fwbuf; | ||
662 | u16 len = 0; | ||
663 | u32 txlen, tx_blocks = 0, tries; | ||
664 | u32 i = 0; | ||
665 | |||
666 | if (!firmware_len) { | ||
667 | dev_err(adapter->dev, "firmware image not found!" | ||
668 | " Terminating download\n"); | ||
669 | return -1; | ||
670 | } | ||
671 | |||
672 | dev_dbg(adapter->dev, "info: downloading FW image (%d bytes)\n", | ||
673 | firmware_len); | ||
674 | |||
675 | /* Assume that the allocated buffer is 8-byte aligned */ | ||
676 | fwbuf = kzalloc(MWIFIEX_UPLD_SIZE, GFP_KERNEL); | ||
677 | if (!fwbuf) { | ||
678 | dev_err(adapter->dev, "unable to alloc buffer for firmware." | ||
679 | " Terminating download\n"); | ||
680 | return -ENOMEM; | ||
681 | } | ||
682 | |||
683 | /* Perform firmware data transfer */ | ||
684 | do { | ||
685 | /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY | ||
686 | bits */ | ||
687 | ret = mwifiex_sdio_poll_card_status(adapter, CARD_IO_READY | | ||
688 | DN_LD_CARD_RDY); | ||
689 | if (ret) { | ||
690 | dev_err(adapter->dev, "FW download with helper:" | ||
691 | " poll status timeout @ %d\n", offset); | ||
692 | goto done; | ||
693 | } | ||
694 | |||
695 | /* More data? */ | ||
696 | if (offset >= firmware_len) | ||
697 | break; | ||
698 | |||
699 | for (tries = 0; tries < MAX_POLL_TRIES; tries++) { | ||
700 | ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_0, | ||
701 | &base0); | ||
702 | if (ret) { | ||
703 | dev_err(adapter->dev, "dev BASE0 register read" | ||
704 | " failed: base0=0x%04X(%d). Terminating " | ||
705 | "download\n", base0, base0); | ||
706 | goto done; | ||
707 | } | ||
708 | ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_1, | ||
709 | &base1); | ||
710 | if (ret) { | ||
711 | dev_err(adapter->dev, "dev BASE1 register read" | ||
712 | " failed: base1=0x%04X(%d). Terminating " | ||
713 | "download\n", base1, base1); | ||
714 | goto done; | ||
715 | } | ||
716 | len = (u16) (((base1 & 0xff) << 8) | (base0 & 0xff)); | ||
717 | |||
718 | if (len) | ||
719 | break; | ||
720 | |||
721 | udelay(10); | ||
722 | } | ||
723 | |||
724 | if (!len) { | ||
725 | break; | ||
726 | } else if (len > MWIFIEX_UPLD_SIZE) { | ||
727 | dev_err(adapter->dev, "FW download failed @ %d," | ||
728 | " invalid length %d\n", offset, len); | ||
729 | ret = -1; | ||
730 | goto done; | ||
731 | } | ||
732 | |||
733 | txlen = len; | ||
734 | |||
735 | if (len & BIT(0)) { | ||
736 | i++; | ||
737 | if (i > MAX_WRITE_IOMEM_RETRY) { | ||
738 | dev_err(adapter->dev, "FW download failed @" | ||
739 | " %d, over max retry count\n", offset); | ||
740 | ret = -1; | ||
741 | goto done; | ||
742 | } | ||
743 | dev_err(adapter->dev, "CRC indicated by the helper:" | ||
744 | " len = 0x%04X, txlen = %d\n", len, txlen); | ||
745 | len &= ~BIT(0); | ||
746 | /* Setting this to 0 to resend from same offset */ | ||
747 | txlen = 0; | ||
748 | } else { | ||
749 | i = 0; | ||
750 | |||
751 | /* Set blocksize to transfer - checking for last | ||
752 | block */ | ||
753 | if (firmware_len - offset < txlen) | ||
754 | txlen = firmware_len - offset; | ||
755 | |||
756 | tx_blocks = (txlen + MWIFIEX_SDIO_BLOCK_SIZE - | ||
757 | 1) / MWIFIEX_SDIO_BLOCK_SIZE; | ||
758 | |||
759 | /* Copy payload to buffer */ | ||
760 | memmove(fwbuf, &firmware[offset], txlen); | ||
761 | } | ||
762 | |||
763 | ret = mwifiex_write_data_sync(adapter, fwbuf, tx_blocks * | ||
764 | MWIFIEX_SDIO_BLOCK_SIZE, | ||
765 | adapter->ioport); | ||
766 | if (ret) { | ||
767 | dev_err(adapter->dev, "FW download, write iomem (%d)" | ||
768 | " failed @ %d\n", i, offset); | ||
769 | if (mwifiex_write_reg(adapter, CONFIGURATION_REG, 0x04)) | ||
770 | dev_err(adapter->dev, "write CFG reg failed\n"); | ||
771 | |||
772 | ret = -1; | ||
773 | goto done; | ||
774 | } | ||
775 | |||
776 | offset += txlen; | ||
777 | } while (true); | ||
778 | |||
779 | dev_dbg(adapter->dev, "info: FW download over, size %d bytes\n", | ||
780 | offset); | ||
781 | |||
782 | ret = 0; | ||
783 | done: | ||
784 | kfree(fwbuf); | ||
785 | return ret; | ||
786 | } | ||
787 | |||
788 | /* | ||
789 | * This function checks the firmware status in card. | ||
790 | * | ||
791 | * The winner interface is also determined by this function. | ||
792 | */ | ||
793 | static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, | ||
794 | u32 poll_num, int *winner) | ||
795 | { | ||
796 | int ret = 0; | ||
797 | u16 firmware_stat; | ||
798 | u32 tries; | ||
799 | u32 winner_status; | ||
800 | |||
801 | /* Wait for firmware initialization event */ | ||
802 | for (tries = 0; tries < poll_num; tries++) { | ||
803 | ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat); | ||
804 | if (ret) | ||
805 | continue; | ||
806 | if (firmware_stat == FIRMWARE_READY) { | ||
807 | ret = 0; | ||
808 | break; | ||
809 | } else { | ||
810 | mdelay(100); | ||
811 | ret = -1; | ||
812 | } | ||
813 | } | ||
814 | |||
815 | if (winner && ret) { | ||
816 | if (mwifiex_read_reg | ||
817 | (adapter, CARD_FW_STATUS0_REG, &winner_status)) | ||
818 | winner_status = 0; | ||
819 | |||
820 | if (winner_status) | ||
821 | *winner = 0; | ||
822 | else | ||
823 | *winner = 1; | ||
824 | } | ||
825 | return ret; | ||
826 | } | ||
827 | |||
828 | /* | ||
829 | * This function reads the interrupt status from card. | ||
830 | */ | ||
831 | static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) | ||
832 | { | ||
833 | struct sdio_mmc_card *card = adapter->card; | ||
834 | u32 sdio_ireg; | ||
835 | unsigned long flags; | ||
836 | |||
837 | if (mwifiex_read_data_sync(adapter, card->mp_regs, MAX_MP_REGS, | ||
838 | REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, | ||
839 | 0)) { | ||
840 | dev_err(adapter->dev, "read mp_regs failed\n"); | ||
841 | return; | ||
842 | } | ||
843 | |||
844 | sdio_ireg = card->mp_regs[HOST_INTSTATUS_REG]; | ||
845 | if (sdio_ireg) { | ||
846 | /* | ||
847 | * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS | ||
848 | * Clear the interrupt status register | ||
849 | */ | ||
850 | dev_dbg(adapter->dev, "int: sdio_ireg = %#x\n", sdio_ireg); | ||
851 | spin_lock_irqsave(&adapter->int_lock, flags); | ||
852 | adapter->int_status |= sdio_ireg; | ||
853 | spin_unlock_irqrestore(&adapter->int_lock, flags); | ||
854 | } | ||
855 | } | ||
856 | |||
857 | /* | ||
858 | * SDIO interrupt handler. | ||
859 | * | ||
860 | * This function reads the interrupt status from firmware and assigns | ||
861 | * the main process in workqueue which will handle the interrupt. | ||
862 | */ | ||
863 | static void | ||
864 | mwifiex_sdio_interrupt(struct sdio_func *func) | ||
865 | { | ||
866 | struct mwifiex_adapter *adapter; | ||
867 | struct sdio_mmc_card *card; | ||
868 | |||
869 | card = sdio_get_drvdata(func); | ||
870 | if (!card || !card->adapter) { | ||
871 | pr_debug("int: func=%p card=%p adapter=%p\n", | ||
872 | func, card, card ? card->adapter : NULL); | ||
873 | return; | ||
874 | } | ||
875 | adapter = card->adapter; | ||
876 | |||
877 | if (adapter->surprise_removed) | ||
878 | return; | ||
879 | |||
880 | if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP) | ||
881 | adapter->ps_state = PS_STATE_AWAKE; | ||
882 | |||
883 | mwifiex_interrupt_status(adapter); | ||
884 | queue_work(adapter->workqueue, &adapter->main_work); | ||
885 | } | ||
886 | |||
887 | /* | ||
888 | * This function decodes a received packet. | ||
889 | * | ||
890 | * Based on the type, the packet is treated as either a data, or | ||
891 | * a command response, or an event, and the correct handler | ||
892 | * function is invoked. | ||
893 | */ | ||
894 | static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, | ||
895 | struct sk_buff *skb, u32 upld_typ) | ||
896 | { | ||
897 | u8 *cmd_buf; | ||
898 | |||
899 | skb_pull(skb, INTF_HEADER_LEN); | ||
900 | |||
901 | switch (upld_typ) { | ||
902 | case MWIFIEX_TYPE_DATA: | ||
903 | dev_dbg(adapter->dev, "info: --- Rx: Data packet ---\n"); | ||
904 | mwifiex_handle_rx_packet(adapter, skb); | ||
905 | break; | ||
906 | |||
907 | case MWIFIEX_TYPE_CMD: | ||
908 | dev_dbg(adapter->dev, "info: --- Rx: Cmd Response ---\n"); | ||
909 | /* take care of curr_cmd = NULL case */ | ||
910 | if (!adapter->curr_cmd) { | ||
911 | cmd_buf = adapter->upld_buf; | ||
912 | |||
913 | if (adapter->ps_state == PS_STATE_SLEEP_CFM) | ||
914 | mwifiex_process_sleep_confirm_resp(adapter, | ||
915 | skb->data, skb->len); | ||
916 | |||
917 | memcpy(cmd_buf, skb->data, min_t(u32, | ||
918 | MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len)); | ||
919 | |||
920 | dev_kfree_skb_any(skb); | ||
921 | } else { | ||
922 | adapter->cmd_resp_received = true; | ||
923 | adapter->curr_cmd->resp_skb = skb; | ||
924 | } | ||
925 | break; | ||
926 | |||
927 | case MWIFIEX_TYPE_EVENT: | ||
928 | dev_dbg(adapter->dev, "info: --- Rx: Event ---\n"); | ||
929 | adapter->event_cause = *(u32 *) skb->data; | ||
930 | |||
931 | skb_pull(skb, MWIFIEX_EVENT_HEADER_LEN); | ||
932 | |||
933 | if ((skb->len > 0) && (skb->len < MAX_EVENT_SIZE)) | ||
934 | memcpy(adapter->event_body, skb->data, skb->len); | ||
935 | |||
936 | /* event cause has been saved to adapter->event_cause */ | ||
937 | adapter->event_received = true; | ||
938 | adapter->event_skb = skb; | ||
939 | |||
940 | break; | ||
941 | |||
942 | default: | ||
943 | dev_err(adapter->dev, "unknown upload type %#x\n", upld_typ); | ||
944 | dev_kfree_skb_any(skb); | ||
945 | break; | ||
946 | } | ||
947 | |||
948 | return 0; | ||
949 | } | ||
950 | |||
951 | /* | ||
952 | * This function transfers received packets from card to driver, performing | ||
953 | * aggregation if required. | ||
954 | * | ||
955 | * For data received on control port, or if aggregation is disabled, the | ||
956 | * received buffers are uploaded as separate packets. However, if aggregation | ||
957 | * is enabled and required, the buffers are copied onto an aggregation buffer, | ||
958 | * provided there is space left, processed and finally uploaded. | ||
959 | */ | ||
960 | static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, | ||
961 | struct sk_buff *skb, u8 port) | ||
962 | { | ||
963 | struct sdio_mmc_card *card = adapter->card; | ||
964 | s32 f_do_rx_aggr = 0; | ||
965 | s32 f_do_rx_cur = 0; | ||
966 | s32 f_aggr_cur = 0; | ||
967 | struct sk_buff *skb_deaggr; | ||
968 | u32 pind; | ||
969 | u32 pkt_len, pkt_type = 0; | ||
970 | u8 *curr_ptr; | ||
971 | u32 rx_len = skb->len; | ||
972 | |||
973 | if (port == CTRL_PORT) { | ||
974 | /* Read the command Resp without aggr */ | ||
975 | dev_dbg(adapter->dev, "info: %s: no aggregation for cmd " | ||
976 | "response\n", __func__); | ||
977 | |||
978 | f_do_rx_cur = 1; | ||
979 | goto rx_curr_single; | ||
980 | } | ||
981 | |||
982 | if (!card->mpa_rx.enabled) { | ||
983 | dev_dbg(adapter->dev, "info: %s: rx aggregation disabled\n", | ||
984 | __func__); | ||
985 | |||
986 | f_do_rx_cur = 1; | ||
987 | goto rx_curr_single; | ||
988 | } | ||
989 | |||
990 | if (card->mp_rd_bitmap & (~((u16) CTRL_PORT_MASK))) { | ||
991 | /* Some more data RX pending */ | ||
992 | dev_dbg(adapter->dev, "info: %s: not last packet\n", __func__); | ||
993 | |||
994 | if (MP_RX_AGGR_IN_PROGRESS(card)) { | ||
995 | if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) { | ||
996 | f_aggr_cur = 1; | ||
997 | } else { | ||
998 | /* No room in Aggr buf, do rx aggr now */ | ||
999 | f_do_rx_aggr = 1; | ||
1000 | f_do_rx_cur = 1; | ||
1001 | } | ||
1002 | } else { | ||
1003 | /* Rx aggr not in progress */ | ||
1004 | f_aggr_cur = 1; | ||
1005 | } | ||
1006 | |||
1007 | } else { | ||
1008 | /* No more data RX pending */ | ||
1009 | dev_dbg(adapter->dev, "info: %s: last packet\n", __func__); | ||
1010 | |||
1011 | if (MP_RX_AGGR_IN_PROGRESS(card)) { | ||
1012 | f_do_rx_aggr = 1; | ||
1013 | if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) | ||
1014 | f_aggr_cur = 1; | ||
1015 | else | ||
1016 | /* No room in Aggr buf, do rx aggr now */ | ||
1017 | f_do_rx_cur = 1; | ||
1018 | } else { | ||
1019 | f_do_rx_cur = 1; | ||
1020 | } | ||
1021 | } | ||
1022 | |||
1023 | if (f_aggr_cur) { | ||
1024 | dev_dbg(adapter->dev, "info: current packet aggregation\n"); | ||
1025 | /* Curr pkt can be aggregated */ | ||
1026 | MP_RX_AGGR_SETUP(card, skb, port); | ||
1027 | |||
1028 | if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) || | ||
1029 | MP_RX_AGGR_PORT_LIMIT_REACHED(card)) { | ||
1030 | dev_dbg(adapter->dev, "info: %s: aggregated packet " | ||
1031 | "limit reached\n", __func__); | ||
1032 | /* No more pkts allowed in Aggr buf, rx it */ | ||
1033 | f_do_rx_aggr = 1; | ||
1034 | } | ||
1035 | } | ||
1036 | |||
1037 | if (f_do_rx_aggr) { | ||
1038 | /* do aggr RX now */ | ||
1039 | dev_dbg(adapter->dev, "info: do_rx_aggr: num of packets: %d\n", | ||
1040 | card->mpa_rx.pkt_cnt); | ||
1041 | |||
1042 | if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf, | ||
1043 | card->mpa_rx.buf_len, | ||
1044 | (adapter->ioport | 0x1000 | | ||
1045 | (card->mpa_rx.ports << 4)) + | ||
1046 | card->mpa_rx.start_port, 1)) | ||
1047 | return -1; | ||
1048 | |||
1049 | curr_ptr = card->mpa_rx.buf; | ||
1050 | |||
1051 | for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) { | ||
1052 | |||
1053 | /* get curr PKT len & type */ | ||
1054 | pkt_len = *(u16 *) &curr_ptr[0]; | ||
1055 | pkt_type = *(u16 *) &curr_ptr[2]; | ||
1056 | |||
1057 | /* copy pkt to deaggr buf */ | ||
1058 | skb_deaggr = card->mpa_rx.skb_arr[pind]; | ||
1059 | |||
1060 | if ((pkt_type == MWIFIEX_TYPE_DATA) && (pkt_len <= | ||
1061 | card->mpa_rx.len_arr[pind])) { | ||
1062 | |||
1063 | memcpy(skb_deaggr->data, curr_ptr, pkt_len); | ||
1064 | |||
1065 | skb_trim(skb_deaggr, pkt_len); | ||
1066 | |||
1067 | /* Process de-aggr packet */ | ||
1068 | mwifiex_decode_rx_packet(adapter, skb_deaggr, | ||
1069 | pkt_type); | ||
1070 | } else { | ||
1071 | dev_err(adapter->dev, "wrong aggr pkt:" | ||
1072 | " type=%d len=%d max_len=%d\n", | ||
1073 | pkt_type, pkt_len, | ||
1074 | card->mpa_rx.len_arr[pind]); | ||
1075 | dev_kfree_skb_any(skb_deaggr); | ||
1076 | } | ||
1077 | curr_ptr += card->mpa_rx.len_arr[pind]; | ||
1078 | } | ||
1079 | MP_RX_AGGR_BUF_RESET(card); | ||
1080 | } | ||
1081 | |||
1082 | rx_curr_single: | ||
1083 | if (f_do_rx_cur) { | ||
1084 | dev_dbg(adapter->dev, "info: RX: port: %d, rx_len: %d\n", | ||
1085 | port, rx_len); | ||
1086 | |||
1087 | if (mwifiex_sdio_card_to_host(adapter, &pkt_type, | ||
1088 | skb->data, skb->len, | ||
1089 | adapter->ioport + port)) | ||
1090 | return -1; | ||
1091 | |||
1092 | mwifiex_decode_rx_packet(adapter, skb, pkt_type); | ||
1093 | } | ||
1094 | |||
1095 | return 0; | ||
1096 | } | ||
1097 | |||
1098 | /* | ||
1099 | * This function checks the current interrupt status. | ||
1100 | * | ||
1101 | * The following interrupts are checked and handled by this function - | ||
1102 | * - Data sent | ||
1103 | * - Command sent | ||
1104 | * - Packets received | ||
1105 | * | ||
1106 | * Since the firmware does not generate download ready interrupt if the | ||
1107 | * port updated is command port only, command sent interrupt checking | ||
1108 | * should be done manually, and for every SDIO interrupt. | ||
1109 | * | ||
1110 | * In case of Rx packets received, the packets are uploaded from card to | ||
1111 | * host and processed accordingly. | ||
1112 | */ | ||
1113 | static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) | ||
1114 | { | ||
1115 | struct sdio_mmc_card *card = adapter->card; | ||
1116 | int ret = 0; | ||
1117 | u8 sdio_ireg; | ||
1118 | struct sk_buff *skb; | ||
1119 | u8 port = CTRL_PORT; | ||
1120 | u32 len_reg_l, len_reg_u; | ||
1121 | u32 rx_blocks; | ||
1122 | u16 rx_len; | ||
1123 | unsigned long flags; | ||
1124 | |||
1125 | spin_lock_irqsave(&adapter->int_lock, flags); | ||
1126 | sdio_ireg = adapter->int_status; | ||
1127 | adapter->int_status = 0; | ||
1128 | spin_unlock_irqrestore(&adapter->int_lock, flags); | ||
1129 | |||
1130 | if (!sdio_ireg) | ||
1131 | return ret; | ||
1132 | |||
1133 | if (sdio_ireg & DN_LD_HOST_INT_STATUS) { | ||
1134 | card->mp_wr_bitmap = ((u16) card->mp_regs[WR_BITMAP_U]) << 8; | ||
1135 | card->mp_wr_bitmap |= (u16) card->mp_regs[WR_BITMAP_L]; | ||
1136 | dev_dbg(adapter->dev, "int: DNLD: wr_bitmap=0x%04x\n", | ||
1137 | card->mp_wr_bitmap); | ||
1138 | if (adapter->data_sent && | ||
1139 | (card->mp_wr_bitmap & card->mp_data_port_mask)) { | ||
1140 | dev_dbg(adapter->dev, | ||
1141 | "info: <--- Tx DONE Interrupt --->\n"); | ||
1142 | adapter->data_sent = false; | ||
1143 | } | ||
1144 | } | ||
1145 | |||
1146 | /* As firmware will not generate download ready interrupt if the port | ||
1147 | updated is command port only, cmd_sent should be done for any SDIO | ||
1148 | interrupt. */ | ||
1149 | if (adapter->cmd_sent) { | ||
1150 | /* Check if firmware has attach buffer at command port and | ||
1151 | update just that in wr_bit_map. */ | ||
1152 | card->mp_wr_bitmap |= | ||
1153 | (u16) card->mp_regs[WR_BITMAP_L] & CTRL_PORT_MASK; | ||
1154 | if (card->mp_wr_bitmap & CTRL_PORT_MASK) | ||
1155 | adapter->cmd_sent = false; | ||
1156 | } | ||
1157 | |||
1158 | dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n", | ||
1159 | adapter->cmd_sent, adapter->data_sent); | ||
1160 | if (sdio_ireg & UP_LD_HOST_INT_STATUS) { | ||
1161 | card->mp_rd_bitmap = ((u16) card->mp_regs[RD_BITMAP_U]) << 8; | ||
1162 | card->mp_rd_bitmap |= (u16) card->mp_regs[RD_BITMAP_L]; | ||
1163 | dev_dbg(adapter->dev, "int: UPLD: rd_bitmap=0x%04x\n", | ||
1164 | card->mp_rd_bitmap); | ||
1165 | |||
1166 | while (true) { | ||
1167 | ret = mwifiex_get_rd_port(adapter, &port); | ||
1168 | if (ret) { | ||
1169 | dev_dbg(adapter->dev, | ||
1170 | "info: no more rd_port available\n"); | ||
1171 | break; | ||
1172 | } | ||
1173 | len_reg_l = RD_LEN_P0_L + (port << 1); | ||
1174 | len_reg_u = RD_LEN_P0_U + (port << 1); | ||
1175 | rx_len = ((u16) card->mp_regs[len_reg_u]) << 8; | ||
1176 | rx_len |= (u16) card->mp_regs[len_reg_l]; | ||
1177 | dev_dbg(adapter->dev, "info: RX: port=%d rx_len=%u\n", | ||
1178 | port, rx_len); | ||
1179 | rx_blocks = | ||
1180 | (rx_len + MWIFIEX_SDIO_BLOCK_SIZE - | ||
1181 | 1) / MWIFIEX_SDIO_BLOCK_SIZE; | ||
1182 | if (rx_len <= INTF_HEADER_LEN | ||
1183 | || (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) > | ||
1184 | MWIFIEX_RX_DATA_BUF_SIZE) { | ||
1185 | dev_err(adapter->dev, "invalid rx_len=%d\n", | ||
1186 | rx_len); | ||
1187 | return -1; | ||
1188 | } | ||
1189 | rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE); | ||
1190 | |||
1191 | skb = dev_alloc_skb(rx_len); | ||
1192 | |||
1193 | if (!skb) { | ||
1194 | dev_err(adapter->dev, "%s: failed to alloc skb", | ||
1195 | __func__); | ||
1196 | return -1; | ||
1197 | } | ||
1198 | |||
1199 | skb_put(skb, rx_len); | ||
1200 | |||
1201 | dev_dbg(adapter->dev, "info: rx_len = %d skb->len = %d\n", | ||
1202 | rx_len, skb->len); | ||
1203 | |||
1204 | if (mwifiex_sdio_card_to_host_mp_aggr(adapter, skb, | ||
1205 | port)) { | ||
1206 | u32 cr = 0; | ||
1207 | |||
1208 | dev_err(adapter->dev, "card_to_host_mpa failed:" | ||
1209 | " int status=%#x\n", sdio_ireg); | ||
1210 | if (mwifiex_read_reg(adapter, | ||
1211 | CONFIGURATION_REG, &cr)) | ||
1212 | dev_err(adapter->dev, | ||
1213 | "read CFG reg failed\n"); | ||
1214 | |||
1215 | dev_dbg(adapter->dev, | ||
1216 | "info: CFG reg val = %d\n", cr); | ||
1217 | if (mwifiex_write_reg(adapter, | ||
1218 | CONFIGURATION_REG, | ||
1219 | (cr | 0x04))) | ||
1220 | dev_err(adapter->dev, | ||
1221 | "write CFG reg failed\n"); | ||
1222 | |||
1223 | dev_dbg(adapter->dev, "info: write success\n"); | ||
1224 | if (mwifiex_read_reg(adapter, | ||
1225 | CONFIGURATION_REG, &cr)) | ||
1226 | dev_err(adapter->dev, | ||
1227 | "read CFG reg failed\n"); | ||
1228 | |||
1229 | dev_dbg(adapter->dev, | ||
1230 | "info: CFG reg val =%x\n", cr); | ||
1231 | dev_kfree_skb_any(skb); | ||
1232 | return -1; | ||
1233 | } | ||
1234 | } | ||
1235 | } | ||
1236 | |||
1237 | return 0; | ||
1238 | } | ||
1239 | |||
1240 | /* | ||
1241 | * This function aggregates transmission buffers in driver and downloads | ||
1242 | * the aggregated packet to card. | ||
1243 | * | ||
1244 | * The individual packets are aggregated by copying into an aggregation | ||
1245 | * buffer and then downloaded to the card. Previous unsent packets in the | ||
1246 | * aggregation buffer are pre-copied first before new packets are added. | ||
1247 | * Aggregation is done till there is space left in the aggregation buffer, | ||
1248 | * or till new packets are available. | ||
1249 | * | ||
1250 | * The function will only download the packet to the card when aggregation | ||
1251 | * stops, otherwise it will just aggregate the packet in aggregation buffer | ||
1252 | * and return. | ||
1253 | */ | ||
1254 | static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, | ||
1255 | u8 *payload, u32 pkt_len, u8 port, | ||
1256 | u32 next_pkt_len) | ||
1257 | { | ||
1258 | struct sdio_mmc_card *card = adapter->card; | ||
1259 | int ret = 0; | ||
1260 | s32 f_send_aggr_buf = 0; | ||
1261 | s32 f_send_cur_buf = 0; | ||
1262 | s32 f_precopy_cur_buf = 0; | ||
1263 | s32 f_postcopy_cur_buf = 0; | ||
1264 | |||
1265 | if ((!card->mpa_tx.enabled) || (port == CTRL_PORT)) { | ||
1266 | dev_dbg(adapter->dev, "info: %s: tx aggregation disabled\n", | ||
1267 | __func__); | ||
1268 | |||
1269 | f_send_cur_buf = 1; | ||
1270 | goto tx_curr_single; | ||
1271 | } | ||
1272 | |||
1273 | if (next_pkt_len) { | ||
1274 | /* More pkt in TX queue */ | ||
1275 | dev_dbg(adapter->dev, "info: %s: more packets in queue.\n", | ||
1276 | __func__); | ||
1277 | |||
1278 | if (MP_TX_AGGR_IN_PROGRESS(card)) { | ||
1279 | if (!MP_TX_AGGR_PORT_LIMIT_REACHED(card) && | ||
1280 | MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) { | ||
1281 | f_precopy_cur_buf = 1; | ||
1282 | |||
1283 | if (!(card->mp_wr_bitmap & | ||
1284 | (1 << card->curr_wr_port)) | ||
1285 | || !MP_TX_AGGR_BUF_HAS_ROOM( | ||
1286 | card, next_pkt_len)) | ||
1287 | f_send_aggr_buf = 1; | ||
1288 | } else { | ||
1289 | /* No room in Aggr buf, send it */ | ||
1290 | f_send_aggr_buf = 1; | ||
1291 | |||
1292 | if (MP_TX_AGGR_PORT_LIMIT_REACHED(card) || | ||
1293 | !(card->mp_wr_bitmap & | ||
1294 | (1 << card->curr_wr_port))) | ||
1295 | f_send_cur_buf = 1; | ||
1296 | else | ||
1297 | f_postcopy_cur_buf = 1; | ||
1298 | } | ||
1299 | } else { | ||
1300 | if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len) | ||
1301 | && (card->mp_wr_bitmap & (1 << card->curr_wr_port))) | ||
1302 | f_precopy_cur_buf = 1; | ||
1303 | else | ||
1304 | f_send_cur_buf = 1; | ||
1305 | } | ||
1306 | } else { | ||
1307 | /* Last pkt in TX queue */ | ||
1308 | dev_dbg(adapter->dev, "info: %s: Last packet in Tx Queue.\n", | ||
1309 | __func__); | ||
1310 | |||
1311 | if (MP_TX_AGGR_IN_PROGRESS(card)) { | ||
1312 | /* some packs in Aggr buf already */ | ||
1313 | f_send_aggr_buf = 1; | ||
1314 | |||
1315 | if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) | ||
1316 | f_precopy_cur_buf = 1; | ||
1317 | else | ||
1318 | /* No room in Aggr buf, send it */ | ||
1319 | f_send_cur_buf = 1; | ||
1320 | } else { | ||
1321 | f_send_cur_buf = 1; | ||
1322 | } | ||
1323 | } | ||
1324 | |||
1325 | if (f_precopy_cur_buf) { | ||
1326 | dev_dbg(adapter->dev, "data: %s: precopy current buffer\n", | ||
1327 | __func__); | ||
1328 | MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port); | ||
1329 | |||
1330 | if (MP_TX_AGGR_PKT_LIMIT_REACHED(card) || | ||
1331 | MP_TX_AGGR_PORT_LIMIT_REACHED(card)) | ||
1332 | /* No more pkts allowed in Aggr buf, send it */ | ||
1333 | f_send_aggr_buf = 1; | ||
1334 | } | ||
1335 | |||
1336 | if (f_send_aggr_buf) { | ||
1337 | dev_dbg(adapter->dev, "data: %s: send aggr buffer: %d %d\n", | ||
1338 | __func__, | ||
1339 | card->mpa_tx.start_port, card->mpa_tx.ports); | ||
1340 | ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf, | ||
1341 | card->mpa_tx.buf_len, | ||
1342 | (adapter->ioport | 0x1000 | | ||
1343 | (card->mpa_tx.ports << 4)) + | ||
1344 | card->mpa_tx.start_port); | ||
1345 | |||
1346 | MP_TX_AGGR_BUF_RESET(card); | ||
1347 | } | ||
1348 | |||
1349 | tx_curr_single: | ||
1350 | if (f_send_cur_buf) { | ||
1351 | dev_dbg(adapter->dev, "data: %s: send current buffer %d\n", | ||
1352 | __func__, port); | ||
1353 | ret = mwifiex_write_data_to_card(adapter, payload, pkt_len, | ||
1354 | adapter->ioport + port); | ||
1355 | } | ||
1356 | |||
1357 | if (f_postcopy_cur_buf) { | ||
1358 | dev_dbg(adapter->dev, "data: %s: postcopy current buffer\n", | ||
1359 | __func__); | ||
1360 | MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port); | ||
1361 | } | ||
1362 | |||
1363 | return ret; | ||
1364 | } | ||
1365 | |||
1366 | /* | ||
1367 | * This function downloads data from driver to card. | ||
1368 | * | ||
1369 | * Both commands and data packets are transferred to the card by this | ||
1370 | * function. | ||
1371 | * | ||
1372 | * This function adds the SDIO specific header to the front of the buffer | ||
1373 | * before transferring. The header contains the length of the packet and | ||
1374 | * the type. The firmware handles the packets based upon this set type. | ||
1375 | */ | ||
1376 | static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter, | ||
1377 | u8 type, u8 *payload, u32 pkt_len, | ||
1378 | struct mwifiex_tx_param *tx_param) | ||
1379 | { | ||
1380 | struct sdio_mmc_card *card = adapter->card; | ||
1381 | int ret; | ||
1382 | u32 buf_block_len; | ||
1383 | u32 blk_size; | ||
1384 | u8 port = CTRL_PORT; | ||
1385 | |||
1386 | /* Allocate buffer and copy payload */ | ||
1387 | blk_size = MWIFIEX_SDIO_BLOCK_SIZE; | ||
1388 | buf_block_len = (pkt_len + blk_size - 1) / blk_size; | ||
1389 | *(u16 *) &payload[0] = (u16) pkt_len; | ||
1390 | *(u16 *) &payload[2] = type; | ||
1391 | |||
1392 | /* | ||
1393 | * This is SDIO specific header | ||
1394 | * u16 length, | ||
1395 | * u16 type (MWIFIEX_TYPE_DATA = 0, MWIFIEX_TYPE_CMD = 1, | ||
1396 | * MWIFIEX_TYPE_EVENT = 3) | ||
1397 | */ | ||
1398 | if (type == MWIFIEX_TYPE_DATA) { | ||
1399 | ret = mwifiex_get_wr_port_data(adapter, &port); | ||
1400 | if (ret) { | ||
1401 | dev_err(adapter->dev, "%s: no wr_port available\n", | ||
1402 | __func__); | ||
1403 | return ret; | ||
1404 | } | ||
1405 | } else { | ||
1406 | adapter->cmd_sent = true; | ||
1407 | /* Type must be MWIFIEX_TYPE_CMD */ | ||
1408 | |||
1409 | if (pkt_len <= INTF_HEADER_LEN || | ||
1410 | pkt_len > MWIFIEX_UPLD_SIZE) | ||
1411 | dev_err(adapter->dev, "%s: payload=%p, nb=%d\n", | ||
1412 | __func__, payload, pkt_len); | ||
1413 | } | ||
1414 | |||
1415 | /* Transfer data to card */ | ||
1416 | pkt_len = buf_block_len * blk_size; | ||
1417 | |||
1418 | if (tx_param) | ||
1419 | ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len, | ||
1420 | port, tx_param->next_pkt_len); | ||
1421 | else | ||
1422 | ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len, | ||
1423 | port, 0); | ||
1424 | |||
1425 | if (ret) { | ||
1426 | if (type == MWIFIEX_TYPE_CMD) | ||
1427 | adapter->cmd_sent = false; | ||
1428 | if (type == MWIFIEX_TYPE_DATA) | ||
1429 | adapter->data_sent = false; | ||
1430 | } else { | ||
1431 | if (type == MWIFIEX_TYPE_DATA) { | ||
1432 | if (!(card->mp_wr_bitmap & (1 << card->curr_wr_port))) | ||
1433 | adapter->data_sent = true; | ||
1434 | else | ||
1435 | adapter->data_sent = false; | ||
1436 | } | ||
1437 | } | ||
1438 | |||
1439 | return ret; | ||
1440 | } | ||
1441 | |||
1442 | /* | ||
1443 | * This function allocates the MPA Tx and Rx buffers. | ||
1444 | */ | ||
1445 | static int mwifiex_alloc_sdio_mpa_buffers(struct mwifiex_adapter *adapter, | ||
1446 | u32 mpa_tx_buf_size, u32 mpa_rx_buf_size) | ||
1447 | { | ||
1448 | struct sdio_mmc_card *card = adapter->card; | ||
1449 | int ret = 0; | ||
1450 | |||
1451 | card->mpa_tx.buf = kzalloc(mpa_tx_buf_size, GFP_KERNEL); | ||
1452 | if (!card->mpa_tx.buf) { | ||
1453 | dev_err(adapter->dev, "could not alloc buffer for MP-A TX\n"); | ||
1454 | ret = -1; | ||
1455 | goto error; | ||
1456 | } | ||
1457 | |||
1458 | card->mpa_tx.buf_size = mpa_tx_buf_size; | ||
1459 | |||
1460 | card->mpa_rx.buf = kzalloc(mpa_rx_buf_size, GFP_KERNEL); | ||
1461 | if (!card->mpa_rx.buf) { | ||
1462 | dev_err(adapter->dev, "could not alloc buffer for MP-A RX\n"); | ||
1463 | ret = -1; | ||
1464 | goto error; | ||
1465 | } | ||
1466 | |||
1467 | card->mpa_rx.buf_size = mpa_rx_buf_size; | ||
1468 | |||
1469 | error: | ||
1470 | if (ret) { | ||
1471 | kfree(card->mpa_tx.buf); | ||
1472 | kfree(card->mpa_rx.buf); | ||
1473 | } | ||
1474 | |||
1475 | return ret; | ||
1476 | } | ||
1477 | |||
1478 | /* | ||
1479 | * This function unregisters the SDIO device. | ||
1480 | * | ||
1481 | * The SDIO IRQ is released, the function is disabled and driver | ||
1482 | * data is set to null. | ||
1483 | */ | ||
1484 | static void | ||
1485 | mwifiex_unregister_dev(struct mwifiex_adapter *adapter) | ||
1486 | { | ||
1487 | struct sdio_mmc_card *card = adapter->card; | ||
1488 | |||
1489 | if (adapter->card) { | ||
1490 | /* Release the SDIO IRQ */ | ||
1491 | sdio_claim_host(card->func); | ||
1492 | sdio_release_irq(card->func); | ||
1493 | sdio_disable_func(card->func); | ||
1494 | sdio_release_host(card->func); | ||
1495 | sdio_set_drvdata(card->func, NULL); | ||
1496 | } | ||
1497 | } | ||
1498 | |||
1499 | /* | ||
1500 | * This function registers the SDIO device. | ||
1501 | * | ||
1502 | * SDIO IRQ is claimed, block size is set and driver data is initialized. | ||
1503 | */ | ||
1504 | static int mwifiex_register_dev(struct mwifiex_adapter *adapter) | ||
1505 | { | ||
1506 | int ret = 0; | ||
1507 | struct sdio_mmc_card *card = adapter->card; | ||
1508 | struct sdio_func *func = card->func; | ||
1509 | |||
1510 | /* save adapter pointer in card */ | ||
1511 | card->adapter = adapter; | ||
1512 | |||
1513 | sdio_claim_host(func); | ||
1514 | |||
1515 | /* Request the SDIO IRQ */ | ||
1516 | ret = sdio_claim_irq(func, mwifiex_sdio_interrupt); | ||
1517 | if (ret) { | ||
1518 | pr_err("claim irq failed: ret=%d\n", ret); | ||
1519 | goto disable_func; | ||
1520 | } | ||
1521 | |||
1522 | /* Set block size */ | ||
1523 | ret = sdio_set_block_size(card->func, MWIFIEX_SDIO_BLOCK_SIZE); | ||
1524 | if (ret) { | ||
1525 | pr_err("cannot set SDIO block size\n"); | ||
1526 | ret = -1; | ||
1527 | goto release_irq; | ||
1528 | } | ||
1529 | |||
1530 | sdio_release_host(func); | ||
1531 | sdio_set_drvdata(func, card); | ||
1532 | |||
1533 | adapter->dev = &func->dev; | ||
1534 | |||
1535 | return 0; | ||
1536 | |||
1537 | release_irq: | ||
1538 | sdio_release_irq(func); | ||
1539 | disable_func: | ||
1540 | sdio_disable_func(func); | ||
1541 | sdio_release_host(func); | ||
1542 | adapter->card = NULL; | ||
1543 | |||
1544 | return -1; | ||
1545 | } | ||
1546 | |||
1547 | /* | ||
1548 | * This function initializes the SDIO driver. | ||
1549 | * | ||
1550 | * The following initializations steps are followed - | ||
1551 | * - Read the Host interrupt status register to acknowledge | ||
1552 | * the first interrupt got from bootloader | ||
1553 | * - Disable host interrupt mask register | ||
1554 | * - Get SDIO port | ||
1555 | * - Get revision ID | ||
1556 | * - Initialize SDIO variables in card | ||
1557 | * - Allocate MP registers | ||
1558 | * - Allocate MPA Tx and Rx buffers | ||
1559 | */ | ||
1560 | static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) | ||
1561 | { | ||
1562 | struct sdio_mmc_card *card = adapter->card; | ||
1563 | int ret; | ||
1564 | u32 sdio_ireg; | ||
1565 | |||
1566 | /* | ||
1567 | * Read the HOST_INT_STATUS_REG for ACK the first interrupt got | ||
1568 | * from the bootloader. If we don't do this we get a interrupt | ||
1569 | * as soon as we register the irq. | ||
1570 | */ | ||
1571 | mwifiex_read_reg(adapter, HOST_INTSTATUS_REG, &sdio_ireg); | ||
1572 | |||
1573 | /* Disable host interrupt mask register for SDIO */ | ||
1574 | mwifiex_sdio_disable_host_int(adapter); | ||
1575 | |||
1576 | /* Get SDIO ioport */ | ||
1577 | mwifiex_init_sdio_ioport(adapter); | ||
1578 | |||
1579 | /* Get revision ID */ | ||
1580 | #define REV_ID_REG 0x5c | ||
1581 | mwifiex_read_reg(adapter, REV_ID_REG, &adapter->revision_id); | ||
1582 | |||
1583 | /* Initialize SDIO variables in card */ | ||
1584 | card->mp_rd_bitmap = 0; | ||
1585 | card->mp_wr_bitmap = 0; | ||
1586 | card->curr_rd_port = 1; | ||
1587 | card->curr_wr_port = 1; | ||
1588 | |||
1589 | card->mp_data_port_mask = DATA_PORT_MASK; | ||
1590 | |||
1591 | card->mpa_tx.buf_len = 0; | ||
1592 | card->mpa_tx.pkt_cnt = 0; | ||
1593 | card->mpa_tx.start_port = 0; | ||
1594 | |||
1595 | card->mpa_tx.enabled = 0; | ||
1596 | card->mpa_tx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT; | ||
1597 | |||
1598 | card->mpa_rx.buf_len = 0; | ||
1599 | card->mpa_rx.pkt_cnt = 0; | ||
1600 | card->mpa_rx.start_port = 0; | ||
1601 | |||
1602 | card->mpa_rx.enabled = 0; | ||
1603 | card->mpa_rx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT; | ||
1604 | |||
1605 | /* Allocate buffers for SDIO MP-A */ | ||
1606 | card->mp_regs = kzalloc(MAX_MP_REGS, GFP_KERNEL); | ||
1607 | if (!card->mp_regs) { | ||
1608 | dev_err(adapter->dev, "failed to alloc mp_regs\n"); | ||
1609 | return -ENOMEM; | ||
1610 | } | ||
1611 | |||
1612 | ret = mwifiex_alloc_sdio_mpa_buffers(adapter, | ||
1613 | SDIO_MP_TX_AGGR_DEF_BUF_SIZE, | ||
1614 | SDIO_MP_RX_AGGR_DEF_BUF_SIZE); | ||
1615 | if (ret) { | ||
1616 | dev_err(adapter->dev, "failed to alloc sdio mp-a buffers\n"); | ||
1617 | kfree(card->mp_regs); | ||
1618 | return -1; | ||
1619 | } | ||
1620 | |||
1621 | return ret; | ||
1622 | } | ||
1623 | |||
1624 | /* | ||
1625 | * This function resets the MPA Tx and Rx buffers. | ||
1626 | */ | ||
1627 | static void mwifiex_cleanup_mpa_buf(struct mwifiex_adapter *adapter) | ||
1628 | { | ||
1629 | struct sdio_mmc_card *card = adapter->card; | ||
1630 | |||
1631 | MP_TX_AGGR_BUF_RESET(card); | ||
1632 | MP_RX_AGGR_BUF_RESET(card); | ||
1633 | } | ||
1634 | |||
1635 | /* | ||
1636 | * This function cleans up the allocated card buffers. | ||
1637 | * | ||
1638 | * The following are freed by this function - | ||
1639 | * - MP registers | ||
1640 | * - MPA Tx buffer | ||
1641 | * - MPA Rx buffer | ||
1642 | */ | ||
1643 | static void mwifiex_cleanup_sdio(struct mwifiex_adapter *adapter) | ||
1644 | { | ||
1645 | struct sdio_mmc_card *card = adapter->card; | ||
1646 | |||
1647 | kfree(card->mp_regs); | ||
1648 | kfree(card->mpa_tx.buf); | ||
1649 | kfree(card->mpa_rx.buf); | ||
1650 | } | ||
1651 | |||
1652 | /* | ||
1653 | * This function updates the MP end port in card. | ||
1654 | */ | ||
1655 | static void | ||
1656 | mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port) | ||
1657 | { | ||
1658 | struct sdio_mmc_card *card = adapter->card; | ||
1659 | int i; | ||
1660 | |||
1661 | card->mp_end_port = port; | ||
1662 | |||
1663 | card->mp_data_port_mask = DATA_PORT_MASK; | ||
1664 | |||
1665 | for (i = 1; i <= MAX_PORT - card->mp_end_port; i++) | ||
1666 | card->mp_data_port_mask &= ~(1 << (MAX_PORT - i)); | ||
1667 | |||
1668 | card->curr_wr_port = 1; | ||
1669 | |||
1670 | dev_dbg(adapter->dev, "cmd: mp_end_port %d, data port mask 0x%x\n", | ||
1671 | port, card->mp_data_port_mask); | ||
1672 | } | ||
1673 | |||
1674 | static struct mwifiex_if_ops sdio_ops = { | ||
1675 | .init_if = mwifiex_init_sdio, | ||
1676 | .cleanup_if = mwifiex_cleanup_sdio, | ||
1677 | .check_fw_status = mwifiex_check_fw_status, | ||
1678 | .prog_fw = mwifiex_prog_fw_w_helper, | ||
1679 | .register_dev = mwifiex_register_dev, | ||
1680 | .unregister_dev = mwifiex_unregister_dev, | ||
1681 | .enable_int = mwifiex_sdio_enable_host_int, | ||
1682 | .process_int_status = mwifiex_process_int_status, | ||
1683 | .host_to_card = mwifiex_sdio_host_to_card, | ||
1684 | .wakeup = mwifiex_pm_wakeup_card, | ||
1685 | .wakeup_complete = mwifiex_pm_wakeup_card_complete, | ||
1686 | |||
1687 | /* SDIO specific */ | ||
1688 | .update_mp_end_port = mwifiex_update_mp_end_port, | ||
1689 | .cleanup_mpa_buf = mwifiex_cleanup_mpa_buf, | ||
1690 | }; | ||
1691 | |||
1692 | /* | ||
1693 | * This function initializes the SDIO driver. | ||
1694 | * | ||
1695 | * This initiates the semaphore and registers the device with | ||
1696 | * SDIO bus. | ||
1697 | */ | ||
1698 | static int | ||
1699 | mwifiex_sdio_init_module(void) | ||
1700 | { | ||
1701 | sema_init(&add_remove_card_sem, 1); | ||
1702 | |||
1703 | return sdio_register_driver(&mwifiex_sdio); | ||
1704 | } | ||
1705 | |||
1706 | /* | ||
1707 | * This function cleans up the SDIO driver. | ||
1708 | * | ||
1709 | * The following major steps are followed for cleanup - | ||
1710 | * - Resume the device if its suspended | ||
1711 | * - Disconnect the device if connected | ||
1712 | * - Shutdown the firmware | ||
1713 | * - Unregister the device from SDIO bus. | ||
1714 | */ | ||
1715 | static void | ||
1716 | mwifiex_sdio_cleanup_module(void) | ||
1717 | { | ||
1718 | struct mwifiex_adapter *adapter = g_adapter; | ||
1719 | int i; | ||
1720 | |||
1721 | if (down_interruptible(&add_remove_card_sem)) | ||
1722 | goto exit_sem_err; | ||
1723 | |||
1724 | if (!adapter || !adapter->priv_num) | ||
1725 | goto exit; | ||
1726 | |||
1727 | if (adapter->is_suspended) | ||
1728 | mwifiex_sdio_resume(adapter->dev); | ||
1729 | |||
1730 | for (i = 0; i < adapter->priv_num; i++) | ||
1731 | if ((GET_BSS_ROLE(adapter->priv[i]) == MWIFIEX_BSS_ROLE_STA) && | ||
1732 | adapter->priv[i]->media_connected) | ||
1733 | mwifiex_deauthenticate(adapter->priv[i], NULL); | ||
1734 | |||
1735 | if (!adapter->surprise_removed) | ||
1736 | mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter, | ||
1737 | MWIFIEX_BSS_ROLE_ANY), | ||
1738 | MWIFIEX_FUNC_SHUTDOWN); | ||
1739 | |||
1740 | exit: | ||
1741 | up(&add_remove_card_sem); | ||
1742 | |||
1743 | exit_sem_err: | ||
1744 | sdio_unregister_driver(&mwifiex_sdio); | ||
1745 | } | ||
1746 | |||
1747 | module_init(mwifiex_sdio_init_module); | ||
1748 | module_exit(mwifiex_sdio_cleanup_module); | ||
1749 | |||
1750 | MODULE_AUTHOR("Marvell International Ltd."); | ||
1751 | MODULE_DESCRIPTION("Marvell WiFi-Ex SDIO Driver version " SDIO_VERSION); | ||
1752 | MODULE_VERSION(SDIO_VERSION); | ||
1753 | MODULE_LICENSE("GPL v2"); | ||
1754 | MODULE_FIRMWARE("sd8787.bin"); | ||