aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mwifiex/init.c
diff options
context:
space:
mode:
authorBing Zhao <bzhao@marvell.com>2011-03-21 21:00:50 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-03-30 14:15:17 -0400
commit5e6e3a92b9a4c9416b17f468fa5c7fa2233b8b4e (patch)
treede22c4c414412501e62894de65040bf30db28c64 /drivers/net/wireless/mwifiex/init.c
parent903946e6e21ef4dd678acafb8881cabde9182caf (diff)
wireless: mwifiex: initial commit for Marvell mwifiex driver
This driver adds WiFi support for Marvell 802.11n based chipsets with SDIO interface. Currently only SD8787 is supported. More chipsets will be supported later. drivers/net/wireless/mwifiex/ Signed-off-by: Nishant Sarmukadam <nishants@marvell.com> Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: Kiran Divekar <dkiran@marvell.com> Signed-off-by: Bing Zhao <bzhao@marvell.com> Signed-off-by: Yogesh Ashok Powar <yogeshp@marvell.com> Signed-off-by: Marc Yang <yangyang@marvell.com> Signed-off-by: Ramesh Radhakrishnan <rramesh@marvell.com> Signed-off-by: Frank Huang <frankh@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/mwifiex/init.c')
-rw-r--r--drivers/net/wireless/mwifiex/init.c665
1 files changed, 665 insertions, 0 deletions
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
new file mode 100644
index 000000000000..07ebc97e19c0
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -0,0 +1,665 @@
1/*
2 * Marvell Wireless LAN device driver: HW/FW Initialization
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 "decl.h"
21#include "ioctl.h"
22#include "util.h"
23#include "fw.h"
24#include "main.h"
25#include "wmm.h"
26#include "11n.h"
27
28/*
29 * This function adds a BSS priority table to the table list.
30 *
31 * The function allocates a new BSS priority table node and adds it to
32 * the end of BSS priority table list, kept in driver memory.
33 */
34static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv)
35{
36 struct mwifiex_adapter *adapter = priv->adapter;
37 struct mwifiex_bss_prio_node *bss_prio;
38 int status = 0;
39 unsigned long flags;
40
41 bss_prio = kzalloc(sizeof(struct mwifiex_bss_prio_node), GFP_KERNEL);
42 if (!bss_prio) {
43 dev_err(adapter->dev, "%s: failed to alloc bss_prio\n",
44 __func__);
45 return -1;
46 }
47
48 bss_prio->priv = priv;
49 INIT_LIST_HEAD(&bss_prio->list);
50 if (!adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur)
51 adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur =
52 bss_prio;
53
54 spin_lock_irqsave(&adapter->bss_prio_tbl[priv->bss_priority]
55 .bss_prio_lock, flags);
56 list_add_tail(&bss_prio->list,
57 &adapter->bss_prio_tbl[priv->bss_priority]
58 .bss_prio_head);
59 spin_unlock_irqrestore(&adapter->bss_prio_tbl[priv->bss_priority]
60 .bss_prio_lock, flags);
61
62 return status;
63}
64
65/*
66 * This function initializes the private structure and sets default
67 * values to the members.
68 *
69 * Additionally, it also initializes all the locks and sets up all the
70 * lists.
71 */
72static int mwifiex_init_priv(struct mwifiex_private *priv)
73{
74 u32 i;
75 int ret = 0;
76
77 priv->media_connected = false;
78 memset(priv->curr_addr, 0xff, ETH_ALEN);
79
80 priv->pkt_tx_ctrl = 0;
81 priv->bss_mode = MWIFIEX_BSS_MODE_INFRA;
82 priv->data_rate = 0; /* Initially indicate the rate as auto */
83 priv->is_data_rate_auto = true;
84 priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
85 priv->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
86
87 priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED;
88 priv->sec_info.authentication_mode = MWIFIEX_AUTH_MODE_OPEN;
89 priv->sec_info.encryption_mode = MWIFIEX_ENCRYPTION_MODE_NONE;
90 for (i = 0; i < ARRAY_SIZE(priv->wep_key); i++)
91 memset(&priv->wep_key[i], 0, sizeof(struct mwifiex_wep_key));
92 priv->wep_key_curr_index = 0;
93 priv->curr_pkt_filter = HostCmd_ACT_MAC_RX_ON | HostCmd_ACT_MAC_TX_ON |
94 HostCmd_ACT_MAC_ETHERNETII_ENABLE;
95
96 priv->beacon_period = 100; /* beacon interval */ ;
97 priv->attempted_bss_desc = NULL;
98 memset(&priv->curr_bss_params, 0, sizeof(priv->curr_bss_params));
99 priv->listen_interval = MWIFIEX_DEFAULT_LISTEN_INTERVAL;
100
101 memset(&priv->prev_ssid, 0, sizeof(priv->prev_ssid));
102 memset(&priv->prev_bssid, 0, sizeof(priv->prev_bssid));
103 memset(&priv->assoc_rsp_buf, 0, sizeof(priv->assoc_rsp_buf));
104 priv->assoc_rsp_size = 0;
105 priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
106 priv->atim_window = 0;
107 priv->adhoc_state = ADHOC_IDLE;
108 priv->tx_power_level = 0;
109 priv->max_tx_power_level = 0;
110 priv->min_tx_power_level = 0;
111 priv->tx_rate = 0;
112 priv->rxpd_htinfo = 0;
113 priv->rxpd_rate = 0;
114 priv->rate_bitmap = 0;
115 priv->data_rssi_last = 0;
116 priv->data_rssi_avg = 0;
117 priv->data_nf_avg = 0;
118 priv->data_nf_last = 0;
119 priv->bcn_rssi_last = 0;
120 priv->bcn_rssi_avg = 0;
121 priv->bcn_nf_avg = 0;
122 priv->bcn_nf_last = 0;
123 memset(&priv->wpa_ie, 0, sizeof(priv->wpa_ie));
124 memset(&priv->aes_key, 0, sizeof(priv->aes_key));
125 priv->wpa_ie_len = 0;
126 priv->wpa_is_gtk_set = false;
127
128 memset(&priv->assoc_tlv_buf, 0, sizeof(priv->assoc_tlv_buf));
129 priv->assoc_tlv_buf_len = 0;
130 memset(&priv->wps, 0, sizeof(priv->wps));
131 memset(&priv->gen_ie_buf, 0, sizeof(priv->gen_ie_buf));
132 priv->gen_ie_buf_len = 0;
133 memset(priv->vs_ie, 0, sizeof(priv->vs_ie));
134
135 priv->wmm_required = true;
136 priv->wmm_enabled = false;
137 priv->wmm_qosinfo = 0;
138 priv->curr_bcn_buf = NULL;
139 priv->curr_bcn_size = 0;
140
141 priv->scan_block = false;
142
143 ret = mwifiex_add_bss_prio_tbl(priv);
144
145 return ret;
146}
147
148/*
149 * This function allocates buffers for members of the adapter
150 * structure.
151 *
152 * The memory allocated includes scan table, command buffers, and
153 * sleep confirm command buffer. In addition, the queues are
154 * also initialized.
155 */
156static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter)
157{
158 int ret = 0;
159 u32 buf_size;
160 struct mwifiex_bssdescriptor *temp_scan_table;
161
162 /* Allocate buffer to store the BSSID list */
163 buf_size = sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP;
164 temp_scan_table = kzalloc(buf_size, GFP_KERNEL);
165 if (!temp_scan_table) {
166 dev_err(adapter->dev, "%s: failed to alloc temp_scan_table\n",
167 __func__);
168 return -1;
169 }
170
171 adapter->scan_table = temp_scan_table;
172
173 /* Allocate command buffer */
174 ret = mwifiex_alloc_cmd_buffer(adapter);
175 if (ret) {
176 dev_err(adapter->dev, "%s: failed to alloc cmd buffer\n",
177 __func__);
178 return -1;
179 }
180
181 adapter->sleep_cfm =
182 dev_alloc_skb(sizeof(struct mwifiex_opt_sleep_confirm_buffer)
183 + INTF_HEADER_LEN);
184
185 if (!adapter->sleep_cfm) {
186 dev_err(adapter->dev, "%s: failed to alloc sleep cfm"
187 " cmd buffer\n", __func__);
188 return -1;
189 }
190 skb_reserve(adapter->sleep_cfm, INTF_HEADER_LEN);
191
192 return 0;
193}
194
195/*
196 * This function initializes the adapter structure and sets default
197 * values to the members of adapter.
198 *
199 * This also initializes the WMM related parameters in the driver private
200 * structures.
201 */
202static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
203{
204 struct mwifiex_opt_sleep_confirm_buffer *sleep_cfm_buf = NULL;
205
206 skb_put(adapter->sleep_cfm, sizeof(sleep_cfm_buf->ps_cfm_sleep));
207 sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm_buffer *)
208 (adapter->sleep_cfm->data);
209
210 adapter->cmd_sent = false;
211 adapter->data_sent = true;
212 adapter->cmd_resp_received = false;
213 adapter->event_received = false;
214 adapter->data_received = false;
215
216 adapter->surprise_removed = false;
217
218 adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
219
220 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
221 adapter->ps_state = PS_STATE_AWAKE;
222 adapter->need_to_wakeup = false;
223
224 adapter->scan_mode = HostCmd_BSS_MODE_ANY;
225 adapter->specific_scan_time = MWIFIEX_SPECIFIC_SCAN_CHAN_TIME;
226 adapter->active_scan_time = MWIFIEX_ACTIVE_SCAN_CHAN_TIME;
227 adapter->passive_scan_time = MWIFIEX_PASSIVE_SCAN_CHAN_TIME;
228
229 adapter->num_in_scan_table = 0;
230 memset(adapter->scan_table, 0,
231 (sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP));
232 adapter->scan_probes = 1;
233
234 memset(adapter->bcn_buf, 0, sizeof(adapter->bcn_buf));
235 adapter->bcn_buf_end = adapter->bcn_buf;
236
237 adapter->radio_on = RADIO_ON;
238 adapter->multiple_dtim = 1;
239
240 adapter->local_listen_interval = 0; /* default value in firmware
241 will be used */
242
243 adapter->is_deep_sleep = false;
244
245 adapter->delay_null_pkt = false;
246 adapter->delay_to_ps = 1000;
247 adapter->enhanced_ps_mode = PS_MODE_AUTO;
248
249 adapter->gen_null_pkt = false; /* Disable NULL Pkg generation by
250 default */
251 adapter->pps_uapsd_mode = false; /* Disable pps/uapsd mode by
252 default */
253 adapter->pm_wakeup_card_req = false;
254
255 adapter->pm_wakeup_fw_try = false;
256
257 adapter->max_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
258 adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
259 adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
260
261 adapter->is_hs_configured = false;
262 adapter->hs_cfg.conditions = cpu_to_le32(HOST_SLEEP_CFG_COND_DEF);
263 adapter->hs_cfg.gpio = HOST_SLEEP_CFG_GPIO_DEF;
264 adapter->hs_cfg.gap = HOST_SLEEP_CFG_GAP_DEF;
265 adapter->hs_activated = false;
266
267 memset(adapter->event_body, 0, sizeof(adapter->event_body));
268 adapter->hw_dot_11n_dev_cap = 0;
269 adapter->hw_dev_mcs_support = 0;
270 adapter->usr_dot_11n_dev_cap = 0;
271 adapter->usr_dev_mcs_support = 0;
272 adapter->chan_offset = 0;
273 adapter->adhoc_11n_enabled = false;
274
275 mwifiex_wmm_init(adapter);
276
277 if (adapter->sleep_cfm) {
278 memset(&sleep_cfm_buf->ps_cfm_sleep, 0,
279 adapter->sleep_cfm->len);
280 sleep_cfm_buf->ps_cfm_sleep.command =
281 cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
282 sleep_cfm_buf->ps_cfm_sleep.size =
283 cpu_to_le16(adapter->sleep_cfm->len);
284 sleep_cfm_buf->ps_cfm_sleep.result = 0;
285 sleep_cfm_buf->ps_cfm_sleep.action = cpu_to_le16(SLEEP_CONFIRM);
286 sleep_cfm_buf->ps_cfm_sleep.sleep_cfm.resp_ctrl =
287 cpu_to_le16(RESP_NEEDED);
288 }
289 memset(&adapter->sleep_params, 0, sizeof(adapter->sleep_params));
290 memset(&adapter->sleep_period, 0, sizeof(adapter->sleep_period));
291 adapter->tx_lock_flag = false;
292 adapter->null_pkt_interval = 0;
293 adapter->fw_bands = 0;
294 adapter->config_bands = 0;
295 adapter->adhoc_start_band = 0;
296 adapter->scan_channels = NULL;
297 adapter->fw_release_number = 0;
298 adapter->fw_cap_info = 0;
299 memset(&adapter->upld_buf, 0, sizeof(adapter->upld_buf));
300 adapter->event_cause = 0;
301 adapter->region_code = 0;
302 adapter->bcn_miss_time_out = DEFAULT_BCN_MISS_TIMEOUT;
303 adapter->adhoc_awake_period = 0;
304 memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter));
305 adapter->arp_filter_size = 0;
306
307 return;
308}
309
310/*
311 * This function frees the adapter structure.
312 *
313 * The freeing operation is done recursively, by canceling all
314 * pending commands, freeing the member buffers previously
315 * allocated (command buffers, scan table buffer, sleep confirm
316 * command buffer), stopping the timers and calling the cleanup
317 * routines for every interface, before the actual adapter
318 * structure is freed.
319 */
320static void
321mwifiex_free_adapter(struct mwifiex_adapter *adapter)
322{
323 if (!adapter) {
324 pr_err("%s: adapter is NULL\n", __func__);
325 return;
326 }
327
328 mwifiex_cancel_all_pending_cmd(adapter);
329
330 /* Free lock variables */
331 mwifiex_free_lock_list(adapter);
332
333 /* Free command buffer */
334 dev_dbg(adapter->dev, "info: free cmd buffer\n");
335 mwifiex_free_cmd_buffer(adapter);
336
337 del_timer(&adapter->cmd_timer);
338
339 dev_dbg(adapter->dev, "info: free scan table\n");
340 kfree(adapter->scan_table);
341 adapter->scan_table = NULL;
342
343 adapter->if_ops.cleanup_if(adapter);
344
345 dev_kfree_skb_any(adapter->sleep_cfm);
346
347 return;
348}
349
350/*
351 * This function intializes the lock variables and
352 * the list heads.
353 */
354int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
355{
356 struct mwifiex_private *priv = NULL;
357 s32 i = 0;
358 u32 j = 0;
359
360 spin_lock_init(&adapter->mwifiex_lock);
361 spin_lock_init(&adapter->int_lock);
362 spin_lock_init(&adapter->main_proc_lock);
363 spin_lock_init(&adapter->mwifiex_cmd_lock);
364 for (i = 0; i < adapter->priv_num; i++) {
365 if (adapter->priv[i]) {
366 priv = adapter->priv[i];
367 spin_lock_init(&priv->rx_pkt_lock);
368 spin_lock_init(&priv->wmm.ra_list_spinlock);
369 spin_lock_init(&priv->curr_bcn_buf_lock);
370 }
371 }
372
373 /* Initialize cmd_free_q */
374 INIT_LIST_HEAD(&adapter->cmd_free_q);
375 /* Initialize cmd_pending_q */
376 INIT_LIST_HEAD(&adapter->cmd_pending_q);
377 /* Initialize scan_pending_q */
378 INIT_LIST_HEAD(&adapter->scan_pending_q);
379
380 spin_lock_init(&adapter->cmd_free_q_lock);
381 spin_lock_init(&adapter->cmd_pending_q_lock);
382 spin_lock_init(&adapter->scan_pending_q_lock);
383
384 for (i = 0; i < adapter->priv_num; ++i) {
385 INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head);
386 adapter->bss_prio_tbl[i].bss_prio_cur = NULL;
387 spin_lock_init(&adapter->bss_prio_tbl[i].bss_prio_lock);
388 }
389
390 for (i = 0; i < adapter->priv_num; i++) {
391 if (!adapter->priv[i])
392 continue;
393 priv = adapter->priv[i];
394 for (j = 0; j < MAX_NUM_TID; ++j) {
395 INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[j].ra_list);
396 spin_lock_init(&priv->wmm.tid_tbl_ptr[j].tid_tbl_lock);
397 }
398 INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr);
399 INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
400
401 spin_lock_init(&priv->tx_ba_stream_tbl_lock);
402 spin_lock_init(&priv->rx_reorder_tbl_lock);
403 }
404
405 return 0;
406}
407
408/*
409 * This function releases the lock variables and frees the locks and
410 * associated locks.
411 */
412void mwifiex_free_lock_list(struct mwifiex_adapter *adapter)
413{
414 struct mwifiex_private *priv = NULL;
415 s32 i = 0;
416 s32 j = 0;
417
418 /* Free lists */
419 list_del(&adapter->cmd_free_q);
420 list_del(&adapter->cmd_pending_q);
421 list_del(&adapter->scan_pending_q);
422
423 for (i = 0; i < adapter->priv_num; i++)
424 list_del(&adapter->bss_prio_tbl[i].bss_prio_head);
425
426 for (i = 0; i < adapter->priv_num; i++) {
427 if (adapter->priv[i]) {
428 priv = adapter->priv[i];
429 for (j = 0; j < MAX_NUM_TID; ++j)
430 list_del(&priv->wmm.tid_tbl_ptr[j].ra_list);
431 list_del(&priv->tx_ba_stream_tbl_ptr);
432 list_del(&priv->rx_reorder_tbl_ptr);
433 }
434 }
435
436 return;
437}
438
439/*
440 * This function initializes the firmware.
441 *
442 * The following operations are performed sequentially -
443 * - Allocate adapter structure
444 * - Initialize the adapter structure
445 * - Initialize the private structure
446 * - Add BSS priority tables to the adapter structure
447 * - For each interface, send the init commands to firmware
448 * - Send the first command in command pending queue, if available
449 */
450int mwifiex_init_fw(struct mwifiex_adapter *adapter)
451{
452 int ret = 0;
453 struct mwifiex_private *priv = NULL;
454 u8 i = 0;
455 u8 first_sta = true;
456 int is_cmd_pend_q_empty;
457 unsigned long flags;
458
459 adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
460
461 /* Allocate memory for member of adapter structure */
462 ret = mwifiex_allocate_adapter(adapter);
463 if (ret)
464 return -1;
465
466 /* Initialize adapter structure */
467 mwifiex_init_adapter(adapter);
468
469 for (i = 0; i < adapter->priv_num; i++) {
470 if (adapter->priv[i]) {
471 priv = adapter->priv[i];
472
473 /* Initialize private structure */
474 ret = mwifiex_init_priv(priv);
475 if (ret)
476 return -1;
477 }
478 }
479 for (i = 0; i < adapter->priv_num; i++) {
480 if (adapter->priv[i]) {
481 ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta);
482 if (ret == -1)
483 return -1;
484
485 first_sta = false;
486 }
487 }
488
489 spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
490 is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q);
491 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
492 if (!is_cmd_pend_q_empty) {
493 /* Send the first command in queue and return */
494 if (mwifiex_main_process(adapter) != -1)
495 ret = -EINPROGRESS;
496 } else {
497 adapter->hw_status = MWIFIEX_HW_STATUS_READY;
498 }
499
500 return ret;
501}
502
503/*
504 * This function deletes the BSS priority tables.
505 *
506 * The function traverses through all the allocated BSS priority nodes
507 * in every BSS priority table and frees them.
508 */
509static void mwifiex_delete_bss_prio_tbl(struct mwifiex_private *priv)
510{
511 int i;
512 struct mwifiex_adapter *adapter = priv->adapter;
513 struct mwifiex_bss_prio_node *bssprio_node = NULL, *tmp_node = NULL,
514 **cur = NULL;
515 struct list_head *head;
516 spinlock_t *lock;
517 unsigned long flags;
518
519 for (i = 0; i < adapter->priv_num; ++i) {
520 head = &adapter->bss_prio_tbl[i].bss_prio_head;
521 cur = &adapter->bss_prio_tbl[i].bss_prio_cur;
522 lock = &adapter->bss_prio_tbl[i].bss_prio_lock;
523 dev_dbg(adapter->dev, "info: delete BSS priority table,"
524 " index = %d, i = %d, head = %p, cur = %p\n",
525 priv->bss_index, i, head, *cur);
526 if (*cur) {
527 spin_lock_irqsave(lock, flags);
528 if (list_empty(head)) {
529 spin_unlock_irqrestore(lock, flags);
530 continue;
531 }
532 bssprio_node = list_first_entry(head,
533 struct mwifiex_bss_prio_node, list);
534 spin_unlock_irqrestore(lock, flags);
535
536 list_for_each_entry_safe(bssprio_node, tmp_node, head,
537 list) {
538 if (bssprio_node->priv == priv) {
539 dev_dbg(adapter->dev, "info: Delete "
540 "node %p, next = %p\n",
541 bssprio_node, tmp_node);
542 spin_lock_irqsave(lock, flags);
543 list_del(&bssprio_node->list);
544 spin_unlock_irqrestore(lock, flags);
545 kfree(bssprio_node);
546 }
547 }
548 *cur = (struct mwifiex_bss_prio_node *)head;
549 }
550 }
551}
552
553/*
554 * This function is used to shutdown the driver.
555 *
556 * The following operations are performed sequentially -
557 * - Check if already shut down
558 * - Make sure the main process has stopped
559 * - Clean up the Tx and Rx queues
560 * - Delete BSS priority tables
561 * - Free the adapter
562 * - Notify completion
563 */
564int
565mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
566{
567 int ret = -EINPROGRESS;
568 struct mwifiex_private *priv = NULL;
569 s32 i = 0;
570 unsigned long flags;
571
572 /* mwifiex already shutdown */
573 if (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY)
574 return 0;
575
576 adapter->hw_status = MWIFIEX_HW_STATUS_CLOSING;
577 /* wait for mwifiex_process to complete */
578 if (adapter->mwifiex_processing) {
579 dev_warn(adapter->dev, "main process is still running\n");
580 return ret;
581 }
582
583 /* shut down mwifiex */
584 dev_dbg(adapter->dev, "info: shutdown mwifiex...\n");
585
586 /* Clean up Tx/Rx queues and delete BSS priority table */
587 for (i = 0; i < adapter->priv_num; i++) {
588 if (adapter->priv[i]) {
589 priv = adapter->priv[i];
590
591 mwifiex_clean_txrx(priv);
592 mwifiex_delete_bss_prio_tbl(priv);
593 }
594 }
595
596 spin_lock_irqsave(&adapter->mwifiex_lock, flags);
597
598 /* Free adapter structure */
599 mwifiex_free_adapter(adapter);
600
601 spin_unlock_irqrestore(&adapter->mwifiex_lock, flags);
602
603 /* Notify completion */
604 ret = mwifiex_shutdown_fw_complete(adapter);
605
606 return ret;
607}
608
609/*
610 * This function downloads the firmware to the card.
611 *
612 * The actual download is preceded by two sanity checks -
613 * - Check if firmware is already running
614 * - Check if the interface is the winner to download the firmware
615 *
616 * ...and followed by another -
617 * - Check if the firmware is downloaded successfully
618 *
619 * After download is successfully completed, the host interrupts are enabled.
620 */
621int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
622 struct mwifiex_fw_image *pmfw)
623{
624 int ret = 0;
625 u32 poll_num = 1;
626 int winner;
627
628 /* Check if firmware is already running */
629 ret = adapter->if_ops.check_fw_status(adapter, poll_num, &winner);
630 if (!ret) {
631 dev_notice(adapter->dev,
632 "WLAN FW already running! Skip FW download\n");
633 goto done;
634 }
635 poll_num = MAX_FIRMWARE_POLL_TRIES;
636
637 /* Check if we are the winner for downloading FW */
638 if (!winner) {
639 dev_notice(adapter->dev,
640 "Other interface already running!"
641 " Skip FW download\n");
642 poll_num = MAX_MULTI_INTERFACE_POLL_TRIES;
643 goto poll_fw;
644 }
645 if (pmfw) {
646 /* Download firmware with helper */
647 ret = adapter->if_ops.prog_fw(adapter, pmfw);
648 if (ret) {
649 dev_err(adapter->dev, "prog_fw failed ret=%#x\n", ret);
650 return ret;
651 }
652 }
653
654poll_fw:
655 /* Check if the firmware is downloaded successfully or not */
656 ret = adapter->if_ops.check_fw_status(adapter, poll_num, NULL);
657 if (ret) {
658 dev_err(adapter->dev, "FW failed to be active in time\n");
659 return -1;
660 }
661done:
662 /* re-enable host interrupt for mwifiex after fw dnld is successful */
663 adapter->if_ops.enable_int(adapter);
664 return ret;
665}