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