Linux Audio

Check our new training course

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