162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * NXP Wireless LAN device driver: major functions 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2011-2020 NXP 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/suspend.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "main.h" 1162306a36Sopenharmony_ci#include "wmm.h" 1262306a36Sopenharmony_ci#include "cfg80211.h" 1362306a36Sopenharmony_ci#include "11n.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define VERSION "1.0" 1662306a36Sopenharmony_ci#define MFG_FIRMWARE "mwifiex_mfg.bin" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic unsigned int debug_mask = MWIFIEX_DEFAULT_DEBUG_MASK; 1962306a36Sopenharmony_cimodule_param(debug_mask, uint, 0); 2062306a36Sopenharmony_ciMODULE_PARM_DESC(debug_mask, "bitmap for debug flags"); 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ciconst char driver_version[] = "mwifiex " VERSION " (%s) "; 2362306a36Sopenharmony_cistatic char *cal_data_cfg; 2462306a36Sopenharmony_cimodule_param(cal_data_cfg, charp, 0); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic unsigned short driver_mode; 2762306a36Sopenharmony_cimodule_param(driver_mode, ushort, 0); 2862306a36Sopenharmony_ciMODULE_PARM_DESC(driver_mode, 2962306a36Sopenharmony_ci "station=0x1(default), ap-sta=0x3, station-p2p=0x5, ap-sta-p2p=0x7"); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cibool mfg_mode; 3262306a36Sopenharmony_cimodule_param(mfg_mode, bool, 0); 3362306a36Sopenharmony_ciMODULE_PARM_DESC(mfg_mode, "manufacturing mode enable:1, disable:0"); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cibool aggr_ctrl; 3662306a36Sopenharmony_cimodule_param(aggr_ctrl, bool, 0000); 3762306a36Sopenharmony_ciMODULE_PARM_DESC(aggr_ctrl, "usb tx aggregation enable:1, disable:0"); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ciconst u16 mwifiex_1d_to_wmm_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* 4262306a36Sopenharmony_ci * This function registers the device and performs all the necessary 4362306a36Sopenharmony_ci * initializations. 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * The following initialization operations are performed - 4662306a36Sopenharmony_ci * - Allocate adapter structure 4762306a36Sopenharmony_ci * - Save interface specific operations table in adapter 4862306a36Sopenharmony_ci * - Call interface specific initialization routine 4962306a36Sopenharmony_ci * - Allocate private structures 5062306a36Sopenharmony_ci * - Set default adapter structure parameters 5162306a36Sopenharmony_ci * - Initialize locks 5262306a36Sopenharmony_ci * 5362306a36Sopenharmony_ci * In case of any errors during inittialization, this function also ensures 5462306a36Sopenharmony_ci * proper cleanup before exiting. 5562306a36Sopenharmony_ci */ 5662306a36Sopenharmony_cistatic int mwifiex_register(void *card, struct device *dev, 5762306a36Sopenharmony_ci struct mwifiex_if_ops *if_ops, void **padapter) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci struct mwifiex_adapter *adapter; 6062306a36Sopenharmony_ci int i; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci adapter = kzalloc(sizeof(struct mwifiex_adapter), GFP_KERNEL); 6362306a36Sopenharmony_ci if (!adapter) 6462306a36Sopenharmony_ci return -ENOMEM; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci *padapter = adapter; 6762306a36Sopenharmony_ci adapter->dev = dev; 6862306a36Sopenharmony_ci adapter->card = card; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* Save interface specific operations in adapter */ 7162306a36Sopenharmony_ci memmove(&adapter->if_ops, if_ops, sizeof(struct mwifiex_if_ops)); 7262306a36Sopenharmony_ci adapter->debug_mask = debug_mask; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* card specific initialization has been deferred until now .. */ 7562306a36Sopenharmony_ci if (adapter->if_ops.init_if) 7662306a36Sopenharmony_ci if (adapter->if_ops.init_if(adapter)) 7762306a36Sopenharmony_ci goto error; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci adapter->priv_num = 0; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) { 8262306a36Sopenharmony_ci /* Allocate memory for private structure */ 8362306a36Sopenharmony_ci adapter->priv[i] = 8462306a36Sopenharmony_ci kzalloc(sizeof(struct mwifiex_private), GFP_KERNEL); 8562306a36Sopenharmony_ci if (!adapter->priv[i]) 8662306a36Sopenharmony_ci goto error; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci adapter->priv[i]->adapter = adapter; 8962306a36Sopenharmony_ci adapter->priv_num++; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci mwifiex_init_lock_list(adapter); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci timer_setup(&adapter->cmd_timer, mwifiex_cmd_timeout_func, 0); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci return 0; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cierror: 9862306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 9962306a36Sopenharmony_ci "info: leave mwifiex_register with error\n"); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci for (i = 0; i < adapter->priv_num; i++) 10262306a36Sopenharmony_ci kfree(adapter->priv[i]); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci kfree(adapter); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return -1; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/* 11062306a36Sopenharmony_ci * This function unregisters the device and performs all the necessary 11162306a36Sopenharmony_ci * cleanups. 11262306a36Sopenharmony_ci * 11362306a36Sopenharmony_ci * The following cleanup operations are performed - 11462306a36Sopenharmony_ci * - Free the timers 11562306a36Sopenharmony_ci * - Free beacon buffers 11662306a36Sopenharmony_ci * - Free private structures 11762306a36Sopenharmony_ci * - Free adapter structure 11862306a36Sopenharmony_ci */ 11962306a36Sopenharmony_cistatic int mwifiex_unregister(struct mwifiex_adapter *adapter) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci s32 i; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (adapter->if_ops.cleanup_if) 12462306a36Sopenharmony_ci adapter->if_ops.cleanup_if(adapter); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci timer_shutdown_sync(&adapter->cmd_timer); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /* Free private structures */ 12962306a36Sopenharmony_ci for (i = 0; i < adapter->priv_num; i++) { 13062306a36Sopenharmony_ci if (adapter->priv[i]) { 13162306a36Sopenharmony_ci mwifiex_free_curr_bcn(adapter->priv[i]); 13262306a36Sopenharmony_ci kfree(adapter->priv[i]); 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (adapter->nd_info) { 13762306a36Sopenharmony_ci for (i = 0 ; i < adapter->nd_info->n_matches ; i++) 13862306a36Sopenharmony_ci kfree(adapter->nd_info->matches[i]); 13962306a36Sopenharmony_ci kfree(adapter->nd_info); 14062306a36Sopenharmony_ci adapter->nd_info = NULL; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci kfree(adapter->regd); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci kfree(adapter); 14662306a36Sopenharmony_ci return 0; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_civoid mwifiex_queue_main_work(struct mwifiex_adapter *adapter) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci unsigned long flags; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci spin_lock_irqsave(&adapter->main_proc_lock, flags); 15462306a36Sopenharmony_ci if (adapter->mwifiex_processing) { 15562306a36Sopenharmony_ci adapter->more_task_flag = true; 15662306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->main_proc_lock, flags); 15762306a36Sopenharmony_ci } else { 15862306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->main_proc_lock, flags); 15962306a36Sopenharmony_ci queue_work(adapter->workqueue, &adapter->main_work); 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_queue_main_work); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic void mwifiex_queue_rx_work(struct mwifiex_adapter *adapter) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci spin_lock_bh(&adapter->rx_proc_lock); 16762306a36Sopenharmony_ci if (adapter->rx_processing) { 16862306a36Sopenharmony_ci spin_unlock_bh(&adapter->rx_proc_lock); 16962306a36Sopenharmony_ci } else { 17062306a36Sopenharmony_ci spin_unlock_bh(&adapter->rx_proc_lock); 17162306a36Sopenharmony_ci queue_work(adapter->rx_workqueue, &adapter->rx_work); 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic int mwifiex_process_rx(struct mwifiex_adapter *adapter) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci struct sk_buff *skb; 17862306a36Sopenharmony_ci struct mwifiex_rxinfo *rx_info; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci spin_lock_bh(&adapter->rx_proc_lock); 18162306a36Sopenharmony_ci if (adapter->rx_processing || adapter->rx_locked) { 18262306a36Sopenharmony_ci spin_unlock_bh(&adapter->rx_proc_lock); 18362306a36Sopenharmony_ci goto exit_rx_proc; 18462306a36Sopenharmony_ci } else { 18562306a36Sopenharmony_ci adapter->rx_processing = true; 18662306a36Sopenharmony_ci spin_unlock_bh(&adapter->rx_proc_lock); 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* Check for Rx data */ 19062306a36Sopenharmony_ci while ((skb = skb_dequeue(&adapter->rx_data_q))) { 19162306a36Sopenharmony_ci atomic_dec(&adapter->rx_pending); 19262306a36Sopenharmony_ci if ((adapter->delay_main_work || 19362306a36Sopenharmony_ci adapter->iface_type == MWIFIEX_USB) && 19462306a36Sopenharmony_ci (atomic_read(&adapter->rx_pending) < LOW_RX_PENDING)) { 19562306a36Sopenharmony_ci if (adapter->if_ops.submit_rem_rx_urbs) 19662306a36Sopenharmony_ci adapter->if_ops.submit_rem_rx_urbs(adapter); 19762306a36Sopenharmony_ci adapter->delay_main_work = false; 19862306a36Sopenharmony_ci mwifiex_queue_main_work(adapter); 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci rx_info = MWIFIEX_SKB_RXCB(skb); 20162306a36Sopenharmony_ci if (rx_info->buf_type == MWIFIEX_TYPE_AGGR_DATA) { 20262306a36Sopenharmony_ci if (adapter->if_ops.deaggr_pkt) 20362306a36Sopenharmony_ci adapter->if_ops.deaggr_pkt(adapter, skb); 20462306a36Sopenharmony_ci dev_kfree_skb_any(skb); 20562306a36Sopenharmony_ci } else { 20662306a36Sopenharmony_ci mwifiex_handle_rx_packet(adapter, skb); 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci spin_lock_bh(&adapter->rx_proc_lock); 21062306a36Sopenharmony_ci adapter->rx_processing = false; 21162306a36Sopenharmony_ci spin_unlock_bh(&adapter->rx_proc_lock); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ciexit_rx_proc: 21462306a36Sopenharmony_ci return 0; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic void maybe_quirk_fw_disable_ds(struct mwifiex_adapter *adapter) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); 22062306a36Sopenharmony_ci struct mwifiex_ver_ext ver_ext; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (test_and_set_bit(MWIFIEX_IS_REQUESTING_FW_VEREXT, &adapter->work_flags)) 22362306a36Sopenharmony_ci return; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci memset(&ver_ext, 0, sizeof(ver_ext)); 22662306a36Sopenharmony_ci ver_ext.version_str_sel = 1; 22762306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_VERSION_EXT, 22862306a36Sopenharmony_ci HostCmd_ACT_GEN_GET, 0, &ver_ext, false)) { 22962306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, 23062306a36Sopenharmony_ci "Checking hardware revision failed.\n"); 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci/* 23562306a36Sopenharmony_ci * The main process. 23662306a36Sopenharmony_ci * 23762306a36Sopenharmony_ci * This function is the main procedure of the driver and handles various driver 23862306a36Sopenharmony_ci * operations. It runs in a loop and provides the core functionalities. 23962306a36Sopenharmony_ci * 24062306a36Sopenharmony_ci * The main responsibilities of this function are - 24162306a36Sopenharmony_ci * - Ensure concurrency control 24262306a36Sopenharmony_ci * - Handle pending interrupts and call interrupt handlers 24362306a36Sopenharmony_ci * - Wake up the card if required 24462306a36Sopenharmony_ci * - Handle command responses and call response handlers 24562306a36Sopenharmony_ci * - Handle events and call event handlers 24662306a36Sopenharmony_ci * - Execute pending commands 24762306a36Sopenharmony_ci * - Transmit pending data packets 24862306a36Sopenharmony_ci */ 24962306a36Sopenharmony_ciint mwifiex_main_process(struct mwifiex_adapter *adapter) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci int ret = 0; 25262306a36Sopenharmony_ci unsigned long flags; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci spin_lock_irqsave(&adapter->main_proc_lock, flags); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci /* Check if already processing */ 25762306a36Sopenharmony_ci if (adapter->mwifiex_processing || adapter->main_locked) { 25862306a36Sopenharmony_ci adapter->more_task_flag = true; 25962306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->main_proc_lock, flags); 26062306a36Sopenharmony_ci return 0; 26162306a36Sopenharmony_ci } else { 26262306a36Sopenharmony_ci adapter->mwifiex_processing = true; 26362306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->main_proc_lock, flags); 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ciprocess_start: 26662306a36Sopenharmony_ci do { 26762306a36Sopenharmony_ci if (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY) 26862306a36Sopenharmony_ci break; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* For non-USB interfaces, If we process interrupts first, it 27162306a36Sopenharmony_ci * would increase RX pending even further. Avoid this by 27262306a36Sopenharmony_ci * checking if rx_pending has crossed high threshold and 27362306a36Sopenharmony_ci * schedule rx work queue and then process interrupts. 27462306a36Sopenharmony_ci * For USB interface, there are no interrupts. We already have 27562306a36Sopenharmony_ci * HIGH_RX_PENDING check in usb.c 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_ci if (atomic_read(&adapter->rx_pending) >= HIGH_RX_PENDING && 27862306a36Sopenharmony_ci adapter->iface_type != MWIFIEX_USB) { 27962306a36Sopenharmony_ci adapter->delay_main_work = true; 28062306a36Sopenharmony_ci mwifiex_queue_rx_work(adapter); 28162306a36Sopenharmony_ci break; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* Handle pending interrupt if any */ 28562306a36Sopenharmony_ci if (adapter->int_status) { 28662306a36Sopenharmony_ci if (adapter->hs_activated) 28762306a36Sopenharmony_ci mwifiex_process_hs_config(adapter); 28862306a36Sopenharmony_ci if (adapter->if_ops.process_int_status) 28962306a36Sopenharmony_ci adapter->if_ops.process_int_status(adapter); 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (adapter->rx_work_enabled && adapter->data_received) 29362306a36Sopenharmony_ci mwifiex_queue_rx_work(adapter); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* Need to wake up the card ? */ 29662306a36Sopenharmony_ci if ((adapter->ps_state == PS_STATE_SLEEP) && 29762306a36Sopenharmony_ci (adapter->pm_wakeup_card_req && 29862306a36Sopenharmony_ci !adapter->pm_wakeup_fw_try) && 29962306a36Sopenharmony_ci (is_command_pending(adapter) || 30062306a36Sopenharmony_ci !skb_queue_empty(&adapter->tx_data_q) || 30162306a36Sopenharmony_ci !mwifiex_bypass_txlist_empty(adapter) || 30262306a36Sopenharmony_ci !mwifiex_wmm_lists_empty(adapter))) { 30362306a36Sopenharmony_ci adapter->pm_wakeup_fw_try = true; 30462306a36Sopenharmony_ci mod_timer(&adapter->wakeup_timer, jiffies + (HZ*3)); 30562306a36Sopenharmony_ci adapter->if_ops.wakeup(adapter); 30662306a36Sopenharmony_ci continue; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (IS_CARD_RX_RCVD(adapter)) { 31062306a36Sopenharmony_ci adapter->data_received = false; 31162306a36Sopenharmony_ci adapter->pm_wakeup_fw_try = false; 31262306a36Sopenharmony_ci del_timer(&adapter->wakeup_timer); 31362306a36Sopenharmony_ci if (adapter->ps_state == PS_STATE_SLEEP) 31462306a36Sopenharmony_ci adapter->ps_state = PS_STATE_AWAKE; 31562306a36Sopenharmony_ci } else { 31662306a36Sopenharmony_ci /* We have tried to wakeup the card already */ 31762306a36Sopenharmony_ci if (adapter->pm_wakeup_fw_try) 31862306a36Sopenharmony_ci break; 31962306a36Sopenharmony_ci if (adapter->ps_state == PS_STATE_PRE_SLEEP) 32062306a36Sopenharmony_ci mwifiex_check_ps_cond(adapter); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci if (adapter->ps_state != PS_STATE_AWAKE) 32362306a36Sopenharmony_ci break; 32462306a36Sopenharmony_ci if (adapter->tx_lock_flag) { 32562306a36Sopenharmony_ci if (adapter->iface_type == MWIFIEX_USB) { 32662306a36Sopenharmony_ci if (!adapter->usb_mc_setup) 32762306a36Sopenharmony_ci break; 32862306a36Sopenharmony_ci } else 32962306a36Sopenharmony_ci break; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci if ((!adapter->scan_chan_gap_enabled && 33362306a36Sopenharmony_ci adapter->scan_processing) || adapter->data_sent || 33462306a36Sopenharmony_ci mwifiex_is_tdls_chan_switching 33562306a36Sopenharmony_ci (mwifiex_get_priv(adapter, 33662306a36Sopenharmony_ci MWIFIEX_BSS_ROLE_STA)) || 33762306a36Sopenharmony_ci (mwifiex_wmm_lists_empty(adapter) && 33862306a36Sopenharmony_ci mwifiex_bypass_txlist_empty(adapter) && 33962306a36Sopenharmony_ci skb_queue_empty(&adapter->tx_data_q))) { 34062306a36Sopenharmony_ci if (adapter->cmd_sent || adapter->curr_cmd || 34162306a36Sopenharmony_ci !mwifiex_is_send_cmd_allowed 34262306a36Sopenharmony_ci (mwifiex_get_priv(adapter, 34362306a36Sopenharmony_ci MWIFIEX_BSS_ROLE_STA)) || 34462306a36Sopenharmony_ci (!is_command_pending(adapter))) 34562306a36Sopenharmony_ci break; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* Check for event */ 35062306a36Sopenharmony_ci if (adapter->event_received) { 35162306a36Sopenharmony_ci adapter->event_received = false; 35262306a36Sopenharmony_ci mwifiex_process_event(adapter); 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* Check for Cmd Resp */ 35662306a36Sopenharmony_ci if (adapter->cmd_resp_received) { 35762306a36Sopenharmony_ci adapter->cmd_resp_received = false; 35862306a36Sopenharmony_ci mwifiex_process_cmdresp(adapter); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* call mwifiex back when init_fw is done */ 36162306a36Sopenharmony_ci if (adapter->hw_status == MWIFIEX_HW_STATUS_INIT_DONE) { 36262306a36Sopenharmony_ci adapter->hw_status = MWIFIEX_HW_STATUS_READY; 36362306a36Sopenharmony_ci mwifiex_init_fw_complete(adapter); 36462306a36Sopenharmony_ci maybe_quirk_fw_disable_ds(adapter); 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* Check if we need to confirm Sleep Request 36962306a36Sopenharmony_ci received previously */ 37062306a36Sopenharmony_ci if (adapter->ps_state == PS_STATE_PRE_SLEEP) 37162306a36Sopenharmony_ci mwifiex_check_ps_cond(adapter); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci /* * The ps_state may have been changed during processing of 37462306a36Sopenharmony_ci * Sleep Request event. 37562306a36Sopenharmony_ci */ 37662306a36Sopenharmony_ci if ((adapter->ps_state == PS_STATE_SLEEP) || 37762306a36Sopenharmony_ci (adapter->ps_state == PS_STATE_PRE_SLEEP) || 37862306a36Sopenharmony_ci (adapter->ps_state == PS_STATE_SLEEP_CFM)) { 37962306a36Sopenharmony_ci continue; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci if (adapter->tx_lock_flag) { 38362306a36Sopenharmony_ci if (adapter->iface_type == MWIFIEX_USB) { 38462306a36Sopenharmony_ci if (!adapter->usb_mc_setup) 38562306a36Sopenharmony_ci continue; 38662306a36Sopenharmony_ci } else 38762306a36Sopenharmony_ci continue; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (!adapter->cmd_sent && !adapter->curr_cmd && 39162306a36Sopenharmony_ci mwifiex_is_send_cmd_allowed 39262306a36Sopenharmony_ci (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA))) { 39362306a36Sopenharmony_ci if (mwifiex_exec_next_cmd(adapter) == -1) { 39462306a36Sopenharmony_ci ret = -1; 39562306a36Sopenharmony_ci break; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /** If USB Multi channel setup ongoing, 40062306a36Sopenharmony_ci * wait for ready to tx data. 40162306a36Sopenharmony_ci */ 40262306a36Sopenharmony_ci if (adapter->iface_type == MWIFIEX_USB && 40362306a36Sopenharmony_ci adapter->usb_mc_setup) 40462306a36Sopenharmony_ci continue; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci if ((adapter->scan_chan_gap_enabled || 40762306a36Sopenharmony_ci !adapter->scan_processing) && 40862306a36Sopenharmony_ci !adapter->data_sent && 40962306a36Sopenharmony_ci !skb_queue_empty(&adapter->tx_data_q)) { 41062306a36Sopenharmony_ci if (adapter->hs_activated_manually) { 41162306a36Sopenharmony_ci mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY), 41262306a36Sopenharmony_ci MWIFIEX_ASYNC_CMD); 41362306a36Sopenharmony_ci adapter->hs_activated_manually = false; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci mwifiex_process_tx_queue(adapter); 41762306a36Sopenharmony_ci if (adapter->hs_activated) { 41862306a36Sopenharmony_ci clear_bit(MWIFIEX_IS_HS_CONFIGURED, 41962306a36Sopenharmony_ci &adapter->work_flags); 42062306a36Sopenharmony_ci mwifiex_hs_activated_event 42162306a36Sopenharmony_ci (mwifiex_get_priv 42262306a36Sopenharmony_ci (adapter, MWIFIEX_BSS_ROLE_ANY), 42362306a36Sopenharmony_ci false); 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci if ((adapter->scan_chan_gap_enabled || 42862306a36Sopenharmony_ci !adapter->scan_processing) && 42962306a36Sopenharmony_ci !adapter->data_sent && 43062306a36Sopenharmony_ci !mwifiex_bypass_txlist_empty(adapter) && 43162306a36Sopenharmony_ci !mwifiex_is_tdls_chan_switching 43262306a36Sopenharmony_ci (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA))) { 43362306a36Sopenharmony_ci if (adapter->hs_activated_manually) { 43462306a36Sopenharmony_ci mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY), 43562306a36Sopenharmony_ci MWIFIEX_ASYNC_CMD); 43662306a36Sopenharmony_ci adapter->hs_activated_manually = false; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci mwifiex_process_bypass_tx(adapter); 44062306a36Sopenharmony_ci if (adapter->hs_activated) { 44162306a36Sopenharmony_ci clear_bit(MWIFIEX_IS_HS_CONFIGURED, 44262306a36Sopenharmony_ci &adapter->work_flags); 44362306a36Sopenharmony_ci mwifiex_hs_activated_event 44462306a36Sopenharmony_ci (mwifiex_get_priv 44562306a36Sopenharmony_ci (adapter, MWIFIEX_BSS_ROLE_ANY), 44662306a36Sopenharmony_ci false); 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci if ((adapter->scan_chan_gap_enabled || 45162306a36Sopenharmony_ci !adapter->scan_processing) && 45262306a36Sopenharmony_ci !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter) && 45362306a36Sopenharmony_ci !mwifiex_is_tdls_chan_switching 45462306a36Sopenharmony_ci (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA))) { 45562306a36Sopenharmony_ci if (adapter->hs_activated_manually) { 45662306a36Sopenharmony_ci mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY), 45762306a36Sopenharmony_ci MWIFIEX_ASYNC_CMD); 45862306a36Sopenharmony_ci adapter->hs_activated_manually = false; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci mwifiex_wmm_process_tx(adapter); 46262306a36Sopenharmony_ci if (adapter->hs_activated) { 46362306a36Sopenharmony_ci clear_bit(MWIFIEX_IS_HS_CONFIGURED, 46462306a36Sopenharmony_ci &adapter->work_flags); 46562306a36Sopenharmony_ci mwifiex_hs_activated_event 46662306a36Sopenharmony_ci (mwifiex_get_priv 46762306a36Sopenharmony_ci (adapter, MWIFIEX_BSS_ROLE_ANY), 46862306a36Sopenharmony_ci false); 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci if (adapter->delay_null_pkt && !adapter->cmd_sent && 47362306a36Sopenharmony_ci !adapter->curr_cmd && !is_command_pending(adapter) && 47462306a36Sopenharmony_ci (mwifiex_wmm_lists_empty(adapter) && 47562306a36Sopenharmony_ci mwifiex_bypass_txlist_empty(adapter) && 47662306a36Sopenharmony_ci skb_queue_empty(&adapter->tx_data_q))) { 47762306a36Sopenharmony_ci if (!mwifiex_send_null_packet 47862306a36Sopenharmony_ci (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), 47962306a36Sopenharmony_ci MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET | 48062306a36Sopenharmony_ci MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET)) { 48162306a36Sopenharmony_ci adapter->delay_null_pkt = false; 48262306a36Sopenharmony_ci adapter->ps_state = PS_STATE_SLEEP; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci break; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci } while (true); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci spin_lock_irqsave(&adapter->main_proc_lock, flags); 48962306a36Sopenharmony_ci if (adapter->more_task_flag) { 49062306a36Sopenharmony_ci adapter->more_task_flag = false; 49162306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->main_proc_lock, flags); 49262306a36Sopenharmony_ci goto process_start; 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci adapter->mwifiex_processing = false; 49562306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->main_proc_lock, flags); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci return ret; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_main_process); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci/* 50262306a36Sopenharmony_ci * This function frees the adapter structure. 50362306a36Sopenharmony_ci * 50462306a36Sopenharmony_ci * Additionally, this closes the netlink socket, frees the timers 50562306a36Sopenharmony_ci * and private structures. 50662306a36Sopenharmony_ci */ 50762306a36Sopenharmony_cistatic void mwifiex_free_adapter(struct mwifiex_adapter *adapter) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci if (!adapter) { 51062306a36Sopenharmony_ci pr_err("%s: adapter is NULL\n", __func__); 51162306a36Sopenharmony_ci return; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci mwifiex_unregister(adapter); 51562306a36Sopenharmony_ci pr_debug("info: %s: free adapter\n", __func__); 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci/* 51962306a36Sopenharmony_ci * This function cancels all works in the queue and destroys 52062306a36Sopenharmony_ci * the main workqueue. 52162306a36Sopenharmony_ci */ 52262306a36Sopenharmony_cistatic void mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci if (adapter->workqueue) { 52562306a36Sopenharmony_ci destroy_workqueue(adapter->workqueue); 52662306a36Sopenharmony_ci adapter->workqueue = NULL; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (adapter->rx_workqueue) { 53062306a36Sopenharmony_ci destroy_workqueue(adapter->rx_workqueue); 53162306a36Sopenharmony_ci adapter->rx_workqueue = NULL; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci/* 53662306a36Sopenharmony_ci * This function gets firmware and initializes it. 53762306a36Sopenharmony_ci * 53862306a36Sopenharmony_ci * The main initialization steps followed are - 53962306a36Sopenharmony_ci * - Download the correct firmware to card 54062306a36Sopenharmony_ci * - Issue the init commands to firmware 54162306a36Sopenharmony_ci */ 54262306a36Sopenharmony_cistatic int _mwifiex_fw_dpc(const struct firmware *firmware, void *context) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci int ret; 54562306a36Sopenharmony_ci char fmt[64]; 54662306a36Sopenharmony_ci struct mwifiex_adapter *adapter = context; 54762306a36Sopenharmony_ci struct mwifiex_fw_image fw; 54862306a36Sopenharmony_ci bool init_failed = false; 54962306a36Sopenharmony_ci struct wireless_dev *wdev; 55062306a36Sopenharmony_ci struct completion *fw_done = adapter->fw_done; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci if (!firmware) { 55362306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 55462306a36Sopenharmony_ci "Failed to get firmware %s\n", adapter->fw_name); 55562306a36Sopenharmony_ci goto err_dnld_fw; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci memset(&fw, 0, sizeof(struct mwifiex_fw_image)); 55962306a36Sopenharmony_ci adapter->firmware = firmware; 56062306a36Sopenharmony_ci fw.fw_buf = (u8 *) adapter->firmware->data; 56162306a36Sopenharmony_ci fw.fw_len = adapter->firmware->size; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (adapter->if_ops.dnld_fw) { 56462306a36Sopenharmony_ci ret = adapter->if_ops.dnld_fw(adapter, &fw); 56562306a36Sopenharmony_ci } else { 56662306a36Sopenharmony_ci ret = mwifiex_dnld_fw(adapter, &fw); 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (ret == -1) 57062306a36Sopenharmony_ci goto err_dnld_fw; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci mwifiex_dbg(adapter, MSG, "WLAN FW is active\n"); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci if (cal_data_cfg) { 57562306a36Sopenharmony_ci if ((request_firmware(&adapter->cal_data, cal_data_cfg, 57662306a36Sopenharmony_ci adapter->dev)) < 0) 57762306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 57862306a36Sopenharmony_ci "Cal data request_firmware() failed\n"); 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci /* enable host interrupt after fw dnld is successful */ 58262306a36Sopenharmony_ci if (adapter->if_ops.enable_int) { 58362306a36Sopenharmony_ci if (adapter->if_ops.enable_int(adapter)) 58462306a36Sopenharmony_ci goto err_dnld_fw; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci adapter->init_wait_q_woken = false; 58862306a36Sopenharmony_ci ret = mwifiex_init_fw(adapter); 58962306a36Sopenharmony_ci if (ret == -1) { 59062306a36Sopenharmony_ci goto err_init_fw; 59162306a36Sopenharmony_ci } else if (!ret) { 59262306a36Sopenharmony_ci adapter->hw_status = MWIFIEX_HW_STATUS_READY; 59362306a36Sopenharmony_ci goto done; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci /* Wait for mwifiex_init to complete */ 59662306a36Sopenharmony_ci if (!adapter->mfg_mode) { 59762306a36Sopenharmony_ci wait_event_interruptible(adapter->init_wait_q, 59862306a36Sopenharmony_ci adapter->init_wait_q_woken); 59962306a36Sopenharmony_ci if (adapter->hw_status != MWIFIEX_HW_STATUS_READY) 60062306a36Sopenharmony_ci goto err_init_fw; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci if (!adapter->wiphy) { 60462306a36Sopenharmony_ci if (mwifiex_register_cfg80211(adapter)) { 60562306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 60662306a36Sopenharmony_ci "cannot register with cfg80211\n"); 60762306a36Sopenharmony_ci goto err_init_fw; 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci if (mwifiex_init_channel_scan_gap(adapter)) { 61262306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 61362306a36Sopenharmony_ci "could not init channel stats table\n"); 61462306a36Sopenharmony_ci goto err_init_chan_scan; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci if (driver_mode) { 61862306a36Sopenharmony_ci driver_mode &= MWIFIEX_DRIVER_MODE_BITMASK; 61962306a36Sopenharmony_ci driver_mode |= MWIFIEX_DRIVER_MODE_STA; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci rtnl_lock(); 62362306a36Sopenharmony_ci wiphy_lock(adapter->wiphy); 62462306a36Sopenharmony_ci /* Create station interface by default */ 62562306a36Sopenharmony_ci wdev = mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d", NET_NAME_ENUM, 62662306a36Sopenharmony_ci NL80211_IFTYPE_STATION, NULL); 62762306a36Sopenharmony_ci if (IS_ERR(wdev)) { 62862306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 62962306a36Sopenharmony_ci "cannot create default STA interface\n"); 63062306a36Sopenharmony_ci wiphy_unlock(adapter->wiphy); 63162306a36Sopenharmony_ci rtnl_unlock(); 63262306a36Sopenharmony_ci goto err_add_intf; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci if (driver_mode & MWIFIEX_DRIVER_MODE_UAP) { 63662306a36Sopenharmony_ci wdev = mwifiex_add_virtual_intf(adapter->wiphy, "uap%d", NET_NAME_ENUM, 63762306a36Sopenharmony_ci NL80211_IFTYPE_AP, NULL); 63862306a36Sopenharmony_ci if (IS_ERR(wdev)) { 63962306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 64062306a36Sopenharmony_ci "cannot create AP interface\n"); 64162306a36Sopenharmony_ci wiphy_unlock(adapter->wiphy); 64262306a36Sopenharmony_ci rtnl_unlock(); 64362306a36Sopenharmony_ci goto err_add_intf; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci if (driver_mode & MWIFIEX_DRIVER_MODE_P2P) { 64862306a36Sopenharmony_ci wdev = mwifiex_add_virtual_intf(adapter->wiphy, "p2p%d", NET_NAME_ENUM, 64962306a36Sopenharmony_ci NL80211_IFTYPE_P2P_CLIENT, NULL); 65062306a36Sopenharmony_ci if (IS_ERR(wdev)) { 65162306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 65262306a36Sopenharmony_ci "cannot create p2p client interface\n"); 65362306a36Sopenharmony_ci wiphy_unlock(adapter->wiphy); 65462306a36Sopenharmony_ci rtnl_unlock(); 65562306a36Sopenharmony_ci goto err_add_intf; 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci wiphy_unlock(adapter->wiphy); 65962306a36Sopenharmony_ci rtnl_unlock(); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1); 66262306a36Sopenharmony_ci mwifiex_dbg(adapter, MSG, "driver_version = %s\n", fmt); 66362306a36Sopenharmony_ci adapter->is_up = true; 66462306a36Sopenharmony_ci goto done; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_cierr_add_intf: 66762306a36Sopenharmony_ci vfree(adapter->chan_stats); 66862306a36Sopenharmony_cierr_init_chan_scan: 66962306a36Sopenharmony_ci wiphy_unregister(adapter->wiphy); 67062306a36Sopenharmony_ci wiphy_free(adapter->wiphy); 67162306a36Sopenharmony_cierr_init_fw: 67262306a36Sopenharmony_ci if (adapter->if_ops.disable_int) 67362306a36Sopenharmony_ci adapter->if_ops.disable_int(adapter); 67462306a36Sopenharmony_cierr_dnld_fw: 67562306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 67662306a36Sopenharmony_ci "info: %s: unregister device\n", __func__); 67762306a36Sopenharmony_ci if (adapter->if_ops.unregister_dev) 67862306a36Sopenharmony_ci adapter->if_ops.unregister_dev(adapter); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci set_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags); 68162306a36Sopenharmony_ci mwifiex_terminate_workqueue(adapter); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci if (adapter->hw_status == MWIFIEX_HW_STATUS_READY) { 68462306a36Sopenharmony_ci pr_debug("info: %s: shutdown mwifiex\n", __func__); 68562306a36Sopenharmony_ci mwifiex_shutdown_drv(adapter); 68662306a36Sopenharmony_ci mwifiex_free_cmd_buffers(adapter); 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci init_failed = true; 69062306a36Sopenharmony_cidone: 69162306a36Sopenharmony_ci if (adapter->cal_data) { 69262306a36Sopenharmony_ci release_firmware(adapter->cal_data); 69362306a36Sopenharmony_ci adapter->cal_data = NULL; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci if (adapter->firmware) { 69662306a36Sopenharmony_ci release_firmware(adapter->firmware); 69762306a36Sopenharmony_ci adapter->firmware = NULL; 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci if (init_failed) { 70062306a36Sopenharmony_ci if (adapter->irq_wakeup >= 0) 70162306a36Sopenharmony_ci device_init_wakeup(adapter->dev, false); 70262306a36Sopenharmony_ci mwifiex_free_adapter(adapter); 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci /* Tell all current and future waiters we're finished */ 70562306a36Sopenharmony_ci complete_all(fw_done); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci return init_failed ? -EIO : 0; 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cistatic void mwifiex_fw_dpc(const struct firmware *firmware, void *context) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci _mwifiex_fw_dpc(firmware, context); 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci/* 71662306a36Sopenharmony_ci * This function gets the firmware and (if called asynchronously) kicks off the 71762306a36Sopenharmony_ci * HW init when done. 71862306a36Sopenharmony_ci */ 71962306a36Sopenharmony_cistatic int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter, 72062306a36Sopenharmony_ci bool req_fw_nowait) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci int ret; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci /* Override default firmware with manufacturing one if 72562306a36Sopenharmony_ci * manufacturing mode is enabled 72662306a36Sopenharmony_ci */ 72762306a36Sopenharmony_ci if (mfg_mode) 72862306a36Sopenharmony_ci strscpy(adapter->fw_name, MFG_FIRMWARE, 72962306a36Sopenharmony_ci sizeof(adapter->fw_name)); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci if (req_fw_nowait) { 73262306a36Sopenharmony_ci ret = request_firmware_nowait(THIS_MODULE, 1, adapter->fw_name, 73362306a36Sopenharmony_ci adapter->dev, GFP_KERNEL, adapter, 73462306a36Sopenharmony_ci mwifiex_fw_dpc); 73562306a36Sopenharmony_ci } else { 73662306a36Sopenharmony_ci ret = request_firmware(&adapter->firmware, 73762306a36Sopenharmony_ci adapter->fw_name, 73862306a36Sopenharmony_ci adapter->dev); 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci if (ret < 0) 74262306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, "request_firmware%s error %d\n", 74362306a36Sopenharmony_ci req_fw_nowait ? "_nowait" : "", ret); 74462306a36Sopenharmony_ci return ret; 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci/* 74862306a36Sopenharmony_ci * CFG802.11 network device handler for open. 74962306a36Sopenharmony_ci * 75062306a36Sopenharmony_ci * Starts the data queue. 75162306a36Sopenharmony_ci */ 75262306a36Sopenharmony_cistatic int 75362306a36Sopenharmony_cimwifiex_open(struct net_device *dev) 75462306a36Sopenharmony_ci{ 75562306a36Sopenharmony_ci netif_carrier_off(dev); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci return 0; 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci/* 76162306a36Sopenharmony_ci * CFG802.11 network device handler for close. 76262306a36Sopenharmony_ci */ 76362306a36Sopenharmony_cistatic int 76462306a36Sopenharmony_cimwifiex_close(struct net_device *dev) 76562306a36Sopenharmony_ci{ 76662306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci if (priv->scan_request) { 76962306a36Sopenharmony_ci struct cfg80211_scan_info info = { 77062306a36Sopenharmony_ci .aborted = true, 77162306a36Sopenharmony_ci }; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 77462306a36Sopenharmony_ci "aborting scan on ndo_stop\n"); 77562306a36Sopenharmony_ci cfg80211_scan_done(priv->scan_request, &info); 77662306a36Sopenharmony_ci priv->scan_request = NULL; 77762306a36Sopenharmony_ci priv->scan_aborting = true; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci if (priv->sched_scanning) { 78162306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 78262306a36Sopenharmony_ci "aborting bgscan on ndo_stop\n"); 78362306a36Sopenharmony_ci mwifiex_stop_bg_scan(priv); 78462306a36Sopenharmony_ci cfg80211_sched_scan_stopped(priv->wdev.wiphy, 0); 78562306a36Sopenharmony_ci } 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci return 0; 78862306a36Sopenharmony_ci} 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_cistatic bool 79162306a36Sopenharmony_cimwifiex_bypass_tx_queue(struct mwifiex_private *priv, 79262306a36Sopenharmony_ci struct sk_buff *skb) 79362306a36Sopenharmony_ci{ 79462306a36Sopenharmony_ci struct ethhdr *eth_hdr = (struct ethhdr *)skb->data; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (ntohs(eth_hdr->h_proto) == ETH_P_PAE || 79762306a36Sopenharmony_ci mwifiex_is_skb_mgmt_frame(skb) || 79862306a36Sopenharmony_ci (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA && 79962306a36Sopenharmony_ci ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && 80062306a36Sopenharmony_ci (ntohs(eth_hdr->h_proto) == ETH_P_TDLS))) { 80162306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, DATA, 80262306a36Sopenharmony_ci "bypass txqueue; eth type %#x, mgmt %d\n", 80362306a36Sopenharmony_ci ntohs(eth_hdr->h_proto), 80462306a36Sopenharmony_ci mwifiex_is_skb_mgmt_frame(skb)); 80562306a36Sopenharmony_ci return true; 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci return false; 80962306a36Sopenharmony_ci} 81062306a36Sopenharmony_ci/* 81162306a36Sopenharmony_ci * Add buffer into wmm tx queue and queue work to transmit it. 81262306a36Sopenharmony_ci */ 81362306a36Sopenharmony_ciint mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb) 81462306a36Sopenharmony_ci{ 81562306a36Sopenharmony_ci struct netdev_queue *txq; 81662306a36Sopenharmony_ci int index = mwifiex_1d_to_wmm_queue[skb->priority]; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci if (atomic_inc_return(&priv->wmm_tx_pending[index]) >= MAX_TX_PENDING) { 81962306a36Sopenharmony_ci txq = netdev_get_tx_queue(priv->netdev, index); 82062306a36Sopenharmony_ci if (!netif_tx_queue_stopped(txq)) { 82162306a36Sopenharmony_ci netif_tx_stop_queue(txq); 82262306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, DATA, 82362306a36Sopenharmony_ci "stop queue: %d\n", index); 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci if (mwifiex_bypass_tx_queue(priv, skb)) { 82862306a36Sopenharmony_ci atomic_inc(&priv->adapter->tx_pending); 82962306a36Sopenharmony_ci atomic_inc(&priv->adapter->bypass_tx_pending); 83062306a36Sopenharmony_ci mwifiex_wmm_add_buf_bypass_txqueue(priv, skb); 83162306a36Sopenharmony_ci } else { 83262306a36Sopenharmony_ci atomic_inc(&priv->adapter->tx_pending); 83362306a36Sopenharmony_ci mwifiex_wmm_add_buf_txqueue(priv, skb); 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci mwifiex_queue_main_work(priv->adapter); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci return 0; 83962306a36Sopenharmony_ci} 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_cistruct sk_buff * 84262306a36Sopenharmony_cimwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv, 84362306a36Sopenharmony_ci struct sk_buff *skb, u8 flag, u64 *cookie) 84462306a36Sopenharmony_ci{ 84562306a36Sopenharmony_ci struct sk_buff *orig_skb = skb; 84662306a36Sopenharmony_ci struct mwifiex_txinfo *tx_info, *orig_tx_info; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci skb = skb_clone(skb, GFP_ATOMIC); 84962306a36Sopenharmony_ci if (skb) { 85062306a36Sopenharmony_ci int id; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci spin_lock_bh(&priv->ack_status_lock); 85362306a36Sopenharmony_ci id = idr_alloc(&priv->ack_status_frames, orig_skb, 85462306a36Sopenharmony_ci 1, 0x10, GFP_ATOMIC); 85562306a36Sopenharmony_ci spin_unlock_bh(&priv->ack_status_lock); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci if (id >= 0) { 85862306a36Sopenharmony_ci tx_info = MWIFIEX_SKB_TXCB(skb); 85962306a36Sopenharmony_ci tx_info->ack_frame_id = id; 86062306a36Sopenharmony_ci tx_info->flags |= flag; 86162306a36Sopenharmony_ci orig_tx_info = MWIFIEX_SKB_TXCB(orig_skb); 86262306a36Sopenharmony_ci orig_tx_info->ack_frame_id = id; 86362306a36Sopenharmony_ci orig_tx_info->flags |= flag; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci if (flag == MWIFIEX_BUF_FLAG_ACTION_TX_STATUS && cookie) 86662306a36Sopenharmony_ci orig_tx_info->cookie = *cookie; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci } else if (skb_shared(skb)) { 86962306a36Sopenharmony_ci kfree_skb(orig_skb); 87062306a36Sopenharmony_ci } else { 87162306a36Sopenharmony_ci kfree_skb(skb); 87262306a36Sopenharmony_ci skb = orig_skb; 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci } else { 87562306a36Sopenharmony_ci /* couldn't clone -- lose tx status ... */ 87662306a36Sopenharmony_ci skb = orig_skb; 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci return skb; 88062306a36Sopenharmony_ci} 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci/* 88362306a36Sopenharmony_ci * CFG802.11 network device handler for data transmission. 88462306a36Sopenharmony_ci */ 88562306a36Sopenharmony_cistatic netdev_tx_t 88662306a36Sopenharmony_cimwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) 88762306a36Sopenharmony_ci{ 88862306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 88962306a36Sopenharmony_ci struct sk_buff *new_skb; 89062306a36Sopenharmony_ci struct mwifiex_txinfo *tx_info; 89162306a36Sopenharmony_ci bool multicast; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, DATA, 89462306a36Sopenharmony_ci "data: %lu BSS(%d-%d): Data <= kernel\n", 89562306a36Sopenharmony_ci jiffies, priv->bss_type, priv->bss_num); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci if (test_bit(MWIFIEX_SURPRISE_REMOVED, &priv->adapter->work_flags)) { 89862306a36Sopenharmony_ci kfree_skb(skb); 89962306a36Sopenharmony_ci priv->stats.tx_dropped++; 90062306a36Sopenharmony_ci return 0; 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci if (!skb->len || (skb->len > ETH_FRAME_LEN)) { 90362306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 90462306a36Sopenharmony_ci "Tx: bad skb len %d\n", skb->len); 90562306a36Sopenharmony_ci kfree_skb(skb); 90662306a36Sopenharmony_ci priv->stats.tx_dropped++; 90762306a36Sopenharmony_ci return 0; 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) { 91062306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, DATA, 91162306a36Sopenharmony_ci "data: Tx: insufficient skb headroom %d\n", 91262306a36Sopenharmony_ci skb_headroom(skb)); 91362306a36Sopenharmony_ci /* Insufficient skb headroom - allocate a new skb */ 91462306a36Sopenharmony_ci new_skb = 91562306a36Sopenharmony_ci skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN); 91662306a36Sopenharmony_ci if (unlikely(!new_skb)) { 91762306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 91862306a36Sopenharmony_ci "Tx: cannot alloca new_skb\n"); 91962306a36Sopenharmony_ci kfree_skb(skb); 92062306a36Sopenharmony_ci priv->stats.tx_dropped++; 92162306a36Sopenharmony_ci return 0; 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci kfree_skb(skb); 92462306a36Sopenharmony_ci skb = new_skb; 92562306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 92662306a36Sopenharmony_ci "info: new skb headroomd %d\n", 92762306a36Sopenharmony_ci skb_headroom(skb)); 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci tx_info = MWIFIEX_SKB_TXCB(skb); 93162306a36Sopenharmony_ci memset(tx_info, 0, sizeof(*tx_info)); 93262306a36Sopenharmony_ci tx_info->bss_num = priv->bss_num; 93362306a36Sopenharmony_ci tx_info->bss_type = priv->bss_type; 93462306a36Sopenharmony_ci tx_info->pkt_len = skb->len; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci multicast = is_multicast_ether_addr(skb->data); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci if (unlikely(!multicast && skb->sk && 93962306a36Sopenharmony_ci skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS && 94062306a36Sopenharmony_ci priv->adapter->fw_api_ver == MWIFIEX_FW_V15)) 94162306a36Sopenharmony_ci skb = mwifiex_clone_skb_for_tx_status(priv, 94262306a36Sopenharmony_ci skb, 94362306a36Sopenharmony_ci MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS, NULL); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci /* Record the current time the packet was queued; used to 94662306a36Sopenharmony_ci * determine the amount of time the packet was queued in 94762306a36Sopenharmony_ci * the driver before it was sent to the firmware. 94862306a36Sopenharmony_ci * The delay is then sent along with the packet to the 94962306a36Sopenharmony_ci * firmware for aggregate delay calculation for stats and 95062306a36Sopenharmony_ci * MSDU lifetime expiry. 95162306a36Sopenharmony_ci */ 95262306a36Sopenharmony_ci __net_timestamp(skb); 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && 95562306a36Sopenharmony_ci priv->bss_type == MWIFIEX_BSS_TYPE_STA && 95662306a36Sopenharmony_ci !ether_addr_equal_unaligned(priv->cfg_bssid, skb->data)) { 95762306a36Sopenharmony_ci if (priv->adapter->auto_tdls && priv->check_tdls_tx) 95862306a36Sopenharmony_ci mwifiex_tdls_check_tx(priv, skb); 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci mwifiex_queue_tx_pkt(priv, skb); 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci return 0; 96462306a36Sopenharmony_ci} 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ciint mwifiex_set_mac_address(struct mwifiex_private *priv, 96762306a36Sopenharmony_ci struct net_device *dev, bool external, 96862306a36Sopenharmony_ci u8 *new_mac) 96962306a36Sopenharmony_ci{ 97062306a36Sopenharmony_ci int ret; 97162306a36Sopenharmony_ci u64 mac_addr, old_mac_addr; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci old_mac_addr = ether_addr_to_u64(priv->curr_addr); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci if (external) { 97662306a36Sopenharmony_ci mac_addr = ether_addr_to_u64(new_mac); 97762306a36Sopenharmony_ci } else { 97862306a36Sopenharmony_ci /* Internal mac address change */ 97962306a36Sopenharmony_ci if (priv->bss_type == MWIFIEX_BSS_TYPE_ANY) 98062306a36Sopenharmony_ci return -EOPNOTSUPP; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci mac_addr = old_mac_addr; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P) { 98562306a36Sopenharmony_ci mac_addr |= BIT_ULL(MWIFIEX_MAC_LOCAL_ADMIN_BIT); 98662306a36Sopenharmony_ci mac_addr += priv->bss_num; 98762306a36Sopenharmony_ci } else if (priv->adapter->priv[0] != priv) { 98862306a36Sopenharmony_ci /* Set mac address based on bss_type/bss_num */ 98962306a36Sopenharmony_ci mac_addr ^= BIT_ULL(priv->bss_type + 8); 99062306a36Sopenharmony_ci mac_addr += priv->bss_num; 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci } 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci u64_to_ether_addr(mac_addr, priv->curr_addr); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci /* Send request to firmware */ 99762306a36Sopenharmony_ci ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_MAC_ADDRESS, 99862306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, NULL, true); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci if (ret) { 100162306a36Sopenharmony_ci u64_to_ether_addr(old_mac_addr, priv->curr_addr); 100262306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 100362306a36Sopenharmony_ci "set mac address failed: ret=%d\n", ret); 100462306a36Sopenharmony_ci return ret; 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci eth_hw_addr_set(dev, priv->curr_addr); 100862306a36Sopenharmony_ci return 0; 100962306a36Sopenharmony_ci} 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci/* CFG802.11 network device handler for setting MAC address. 101262306a36Sopenharmony_ci */ 101362306a36Sopenharmony_cistatic int 101462306a36Sopenharmony_cimwifiex_ndo_set_mac_address(struct net_device *dev, void *addr) 101562306a36Sopenharmony_ci{ 101662306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 101762306a36Sopenharmony_ci struct sockaddr *hw_addr = addr; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci return mwifiex_set_mac_address(priv, dev, true, hw_addr->sa_data); 102062306a36Sopenharmony_ci} 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci/* 102362306a36Sopenharmony_ci * CFG802.11 network device handler for setting multicast list. 102462306a36Sopenharmony_ci */ 102562306a36Sopenharmony_cistatic void mwifiex_set_multicast_list(struct net_device *dev) 102662306a36Sopenharmony_ci{ 102762306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 102862306a36Sopenharmony_ci struct mwifiex_multicast_list mcast_list; 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci if (dev->flags & IFF_PROMISC) { 103162306a36Sopenharmony_ci mcast_list.mode = MWIFIEX_PROMISC_MODE; 103262306a36Sopenharmony_ci } else if (dev->flags & IFF_ALLMULTI || 103362306a36Sopenharmony_ci netdev_mc_count(dev) > MWIFIEX_MAX_MULTICAST_LIST_SIZE) { 103462306a36Sopenharmony_ci mcast_list.mode = MWIFIEX_ALL_MULTI_MODE; 103562306a36Sopenharmony_ci } else { 103662306a36Sopenharmony_ci mcast_list.mode = MWIFIEX_MULTICAST_MODE; 103762306a36Sopenharmony_ci mcast_list.num_multicast_addr = 103862306a36Sopenharmony_ci mwifiex_copy_mcast_addr(&mcast_list, dev); 103962306a36Sopenharmony_ci } 104062306a36Sopenharmony_ci mwifiex_request_set_multicast_list(priv, &mcast_list); 104162306a36Sopenharmony_ci} 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci/* 104462306a36Sopenharmony_ci * CFG802.11 network device handler for transmission timeout. 104562306a36Sopenharmony_ci */ 104662306a36Sopenharmony_cistatic void 104762306a36Sopenharmony_cimwifiex_tx_timeout(struct net_device *dev, unsigned int txqueue) 104862306a36Sopenharmony_ci{ 104962306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci priv->num_tx_timeout++; 105262306a36Sopenharmony_ci priv->tx_timeout_cnt++; 105362306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 105462306a36Sopenharmony_ci "%lu : Tx timeout(#%d), bss_type-num = %d-%d\n", 105562306a36Sopenharmony_ci jiffies, priv->tx_timeout_cnt, priv->bss_type, 105662306a36Sopenharmony_ci priv->bss_num); 105762306a36Sopenharmony_ci mwifiex_set_trans_start(dev); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci if (priv->tx_timeout_cnt > TX_TIMEOUT_THRESHOLD && 106062306a36Sopenharmony_ci priv->adapter->if_ops.card_reset) { 106162306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 106262306a36Sopenharmony_ci "tx_timeout_cnt exceeds threshold.\t" 106362306a36Sopenharmony_ci "Triggering card reset!\n"); 106462306a36Sopenharmony_ci priv->adapter->if_ops.card_reset(priv->adapter); 106562306a36Sopenharmony_ci } 106662306a36Sopenharmony_ci} 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_civoid mwifiex_multi_chan_resync(struct mwifiex_adapter *adapter) 106962306a36Sopenharmony_ci{ 107062306a36Sopenharmony_ci struct usb_card_rec *card = adapter->card; 107162306a36Sopenharmony_ci struct mwifiex_private *priv; 107262306a36Sopenharmony_ci u16 tx_buf_size; 107362306a36Sopenharmony_ci int i, ret; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci card->mc_resync_flag = true; 107662306a36Sopenharmony_ci for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) { 107762306a36Sopenharmony_ci if (atomic_read(&card->port[i].tx_data_urb_pending)) { 107862306a36Sopenharmony_ci mwifiex_dbg(adapter, WARN, "pending data urb in sys\n"); 107962306a36Sopenharmony_ci return; 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci } 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci card->mc_resync_flag = false; 108462306a36Sopenharmony_ci tx_buf_size = 0xffff; 108562306a36Sopenharmony_ci priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); 108662306a36Sopenharmony_ci ret = mwifiex_send_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, 108762306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, &tx_buf_size, false); 108862306a36Sopenharmony_ci if (ret) 108962306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 109062306a36Sopenharmony_ci "send reconfig tx buf size cmd err\n"); 109162306a36Sopenharmony_ci} 109262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_multi_chan_resync); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_civoid mwifiex_upload_device_dump(struct mwifiex_adapter *adapter) 109562306a36Sopenharmony_ci{ 109662306a36Sopenharmony_ci /* Dump all the memory data into single file, a userspace script will 109762306a36Sopenharmony_ci * be used to split all the memory data to multiple files 109862306a36Sopenharmony_ci */ 109962306a36Sopenharmony_ci mwifiex_dbg(adapter, MSG, 110062306a36Sopenharmony_ci "== mwifiex dump information to /sys/class/devcoredump start\n"); 110162306a36Sopenharmony_ci dev_coredumpv(adapter->dev, adapter->devdump_data, adapter->devdump_len, 110262306a36Sopenharmony_ci GFP_KERNEL); 110362306a36Sopenharmony_ci mwifiex_dbg(adapter, MSG, 110462306a36Sopenharmony_ci "== mwifiex dump information to /sys/class/devcoredump end\n"); 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci /* Device dump data will be freed in device coredump release function 110762306a36Sopenharmony_ci * after 5 min. Here reset adapter->devdump_data and ->devdump_len 110862306a36Sopenharmony_ci * to avoid it been accidentally reused. 110962306a36Sopenharmony_ci */ 111062306a36Sopenharmony_ci adapter->devdump_data = NULL; 111162306a36Sopenharmony_ci adapter->devdump_len = 0; 111262306a36Sopenharmony_ci} 111362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_upload_device_dump); 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_civoid mwifiex_drv_info_dump(struct mwifiex_adapter *adapter) 111662306a36Sopenharmony_ci{ 111762306a36Sopenharmony_ci char *p; 111862306a36Sopenharmony_ci char drv_version[64]; 111962306a36Sopenharmony_ci struct usb_card_rec *cardp; 112062306a36Sopenharmony_ci struct sdio_mmc_card *sdio_card; 112162306a36Sopenharmony_ci struct mwifiex_private *priv; 112262306a36Sopenharmony_ci int i, idx; 112362306a36Sopenharmony_ci struct netdev_queue *txq; 112462306a36Sopenharmony_ci struct mwifiex_debug_info *debug_info; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci mwifiex_dbg(adapter, MSG, "===mwifiex driverinfo dump start===\n"); 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci p = adapter->devdump_data; 112962306a36Sopenharmony_ci strcpy(p, "========Start dump driverinfo========\n"); 113062306a36Sopenharmony_ci p += strlen("========Start dump driverinfo========\n"); 113162306a36Sopenharmony_ci p += sprintf(p, "driver_name = " "\"mwifiex\"\n"); 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci mwifiex_drv_get_driver_version(adapter, drv_version, 113462306a36Sopenharmony_ci sizeof(drv_version) - 1); 113562306a36Sopenharmony_ci p += sprintf(p, "driver_version = %s\n", drv_version); 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci if (adapter->iface_type == MWIFIEX_USB) { 113862306a36Sopenharmony_ci cardp = (struct usb_card_rec *)adapter->card; 113962306a36Sopenharmony_ci p += sprintf(p, "tx_cmd_urb_pending = %d\n", 114062306a36Sopenharmony_ci atomic_read(&cardp->tx_cmd_urb_pending)); 114162306a36Sopenharmony_ci p += sprintf(p, "tx_data_urb_pending_port_0 = %d\n", 114262306a36Sopenharmony_ci atomic_read(&cardp->port[0].tx_data_urb_pending)); 114362306a36Sopenharmony_ci p += sprintf(p, "tx_data_urb_pending_port_1 = %d\n", 114462306a36Sopenharmony_ci atomic_read(&cardp->port[1].tx_data_urb_pending)); 114562306a36Sopenharmony_ci p += sprintf(p, "rx_cmd_urb_pending = %d\n", 114662306a36Sopenharmony_ci atomic_read(&cardp->rx_cmd_urb_pending)); 114762306a36Sopenharmony_ci p += sprintf(p, "rx_data_urb_pending = %d\n", 114862306a36Sopenharmony_ci atomic_read(&cardp->rx_data_urb_pending)); 114962306a36Sopenharmony_ci } 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci p += sprintf(p, "tx_pending = %d\n", 115262306a36Sopenharmony_ci atomic_read(&adapter->tx_pending)); 115362306a36Sopenharmony_ci p += sprintf(p, "rx_pending = %d\n", 115462306a36Sopenharmony_ci atomic_read(&adapter->rx_pending)); 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci if (adapter->iface_type == MWIFIEX_SDIO) { 115762306a36Sopenharmony_ci sdio_card = (struct sdio_mmc_card *)adapter->card; 115862306a36Sopenharmony_ci p += sprintf(p, "\nmp_rd_bitmap=0x%x curr_rd_port=0x%x\n", 115962306a36Sopenharmony_ci sdio_card->mp_rd_bitmap, sdio_card->curr_rd_port); 116062306a36Sopenharmony_ci p += sprintf(p, "mp_wr_bitmap=0x%x curr_wr_port=0x%x\n", 116162306a36Sopenharmony_ci sdio_card->mp_wr_bitmap, sdio_card->curr_wr_port); 116262306a36Sopenharmony_ci } 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci for (i = 0; i < adapter->priv_num; i++) { 116562306a36Sopenharmony_ci if (!adapter->priv[i] || !adapter->priv[i]->netdev) 116662306a36Sopenharmony_ci continue; 116762306a36Sopenharmony_ci priv = adapter->priv[i]; 116862306a36Sopenharmony_ci p += sprintf(p, "\n[interface : \"%s\"]\n", 116962306a36Sopenharmony_ci priv->netdev->name); 117062306a36Sopenharmony_ci p += sprintf(p, "wmm_tx_pending[0] = %d\n", 117162306a36Sopenharmony_ci atomic_read(&priv->wmm_tx_pending[0])); 117262306a36Sopenharmony_ci p += sprintf(p, "wmm_tx_pending[1] = %d\n", 117362306a36Sopenharmony_ci atomic_read(&priv->wmm_tx_pending[1])); 117462306a36Sopenharmony_ci p += sprintf(p, "wmm_tx_pending[2] = %d\n", 117562306a36Sopenharmony_ci atomic_read(&priv->wmm_tx_pending[2])); 117662306a36Sopenharmony_ci p += sprintf(p, "wmm_tx_pending[3] = %d\n", 117762306a36Sopenharmony_ci atomic_read(&priv->wmm_tx_pending[3])); 117862306a36Sopenharmony_ci p += sprintf(p, "media_state=\"%s\"\n", !priv->media_connected ? 117962306a36Sopenharmony_ci "Disconnected" : "Connected"); 118062306a36Sopenharmony_ci p += sprintf(p, "carrier %s\n", (netif_carrier_ok(priv->netdev) 118162306a36Sopenharmony_ci ? "on" : "off")); 118262306a36Sopenharmony_ci for (idx = 0; idx < priv->netdev->num_tx_queues; idx++) { 118362306a36Sopenharmony_ci txq = netdev_get_tx_queue(priv->netdev, idx); 118462306a36Sopenharmony_ci p += sprintf(p, "tx queue %d:%s ", idx, 118562306a36Sopenharmony_ci netif_tx_queue_stopped(txq) ? 118662306a36Sopenharmony_ci "stopped" : "started"); 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci p += sprintf(p, "\n%s: num_tx_timeout = %d\n", 118962306a36Sopenharmony_ci priv->netdev->name, priv->num_tx_timeout); 119062306a36Sopenharmony_ci } 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci if (adapter->iface_type == MWIFIEX_SDIO || 119362306a36Sopenharmony_ci adapter->iface_type == MWIFIEX_PCIE) { 119462306a36Sopenharmony_ci p += sprintf(p, "\n=== %s register dump===\n", 119562306a36Sopenharmony_ci adapter->iface_type == MWIFIEX_SDIO ? 119662306a36Sopenharmony_ci "SDIO" : "PCIE"); 119762306a36Sopenharmony_ci if (adapter->if_ops.reg_dump) 119862306a36Sopenharmony_ci p += adapter->if_ops.reg_dump(adapter, p); 119962306a36Sopenharmony_ci } 120062306a36Sopenharmony_ci p += sprintf(p, "\n=== more debug information\n"); 120162306a36Sopenharmony_ci debug_info = kzalloc(sizeof(*debug_info), GFP_KERNEL); 120262306a36Sopenharmony_ci if (debug_info) { 120362306a36Sopenharmony_ci for (i = 0; i < adapter->priv_num; i++) { 120462306a36Sopenharmony_ci if (!adapter->priv[i] || !adapter->priv[i]->netdev) 120562306a36Sopenharmony_ci continue; 120662306a36Sopenharmony_ci priv = adapter->priv[i]; 120762306a36Sopenharmony_ci mwifiex_get_debug_info(priv, debug_info); 120862306a36Sopenharmony_ci p += mwifiex_debug_info_to_buffer(priv, p, debug_info); 120962306a36Sopenharmony_ci break; 121062306a36Sopenharmony_ci } 121162306a36Sopenharmony_ci kfree(debug_info); 121262306a36Sopenharmony_ci } 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci strcpy(p, "\n========End dump========\n"); 121562306a36Sopenharmony_ci p += strlen("\n========End dump========\n"); 121662306a36Sopenharmony_ci mwifiex_dbg(adapter, MSG, "===mwifiex driverinfo dump end===\n"); 121762306a36Sopenharmony_ci adapter->devdump_len = p - (char *)adapter->devdump_data; 121862306a36Sopenharmony_ci} 121962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_drv_info_dump); 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_civoid mwifiex_prepare_fw_dump_info(struct mwifiex_adapter *adapter) 122262306a36Sopenharmony_ci{ 122362306a36Sopenharmony_ci u8 idx; 122462306a36Sopenharmony_ci char *fw_dump_ptr; 122562306a36Sopenharmony_ci u32 dump_len = 0; 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci for (idx = 0; idx < adapter->num_mem_types; idx++) { 122862306a36Sopenharmony_ci struct memory_type_mapping *entry = 122962306a36Sopenharmony_ci &adapter->mem_type_mapping_tbl[idx]; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci if (entry->mem_ptr) { 123262306a36Sopenharmony_ci dump_len += (strlen("========Start dump ") + 123362306a36Sopenharmony_ci strlen(entry->mem_name) + 123462306a36Sopenharmony_ci strlen("========\n") + 123562306a36Sopenharmony_ci (entry->mem_size + 1) + 123662306a36Sopenharmony_ci strlen("\n========End dump========\n")); 123762306a36Sopenharmony_ci } 123862306a36Sopenharmony_ci } 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci if (dump_len + 1 + adapter->devdump_len > MWIFIEX_FW_DUMP_SIZE) { 124162306a36Sopenharmony_ci /* Realloc in case buffer overflow */ 124262306a36Sopenharmony_ci fw_dump_ptr = vzalloc(dump_len + 1 + adapter->devdump_len); 124362306a36Sopenharmony_ci mwifiex_dbg(adapter, MSG, "Realloc device dump data.\n"); 124462306a36Sopenharmony_ci if (!fw_dump_ptr) { 124562306a36Sopenharmony_ci vfree(adapter->devdump_data); 124662306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 124762306a36Sopenharmony_ci "vzalloc devdump data failure!\n"); 124862306a36Sopenharmony_ci return; 124962306a36Sopenharmony_ci } 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci memmove(fw_dump_ptr, adapter->devdump_data, 125262306a36Sopenharmony_ci adapter->devdump_len); 125362306a36Sopenharmony_ci vfree(adapter->devdump_data); 125462306a36Sopenharmony_ci adapter->devdump_data = fw_dump_ptr; 125562306a36Sopenharmony_ci } 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci fw_dump_ptr = (char *)adapter->devdump_data + adapter->devdump_len; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci for (idx = 0; idx < adapter->num_mem_types; idx++) { 126062306a36Sopenharmony_ci struct memory_type_mapping *entry = 126162306a36Sopenharmony_ci &adapter->mem_type_mapping_tbl[idx]; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci if (entry->mem_ptr) { 126462306a36Sopenharmony_ci strcpy(fw_dump_ptr, "========Start dump "); 126562306a36Sopenharmony_ci fw_dump_ptr += strlen("========Start dump "); 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci strcpy(fw_dump_ptr, entry->mem_name); 126862306a36Sopenharmony_ci fw_dump_ptr += strlen(entry->mem_name); 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci strcpy(fw_dump_ptr, "========\n"); 127162306a36Sopenharmony_ci fw_dump_ptr += strlen("========\n"); 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci memcpy(fw_dump_ptr, entry->mem_ptr, entry->mem_size); 127462306a36Sopenharmony_ci fw_dump_ptr += entry->mem_size; 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci strcpy(fw_dump_ptr, "\n========End dump========\n"); 127762306a36Sopenharmony_ci fw_dump_ptr += strlen("\n========End dump========\n"); 127862306a36Sopenharmony_ci } 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci adapter->devdump_len = fw_dump_ptr - (char *)adapter->devdump_data; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci for (idx = 0; idx < adapter->num_mem_types; idx++) { 128462306a36Sopenharmony_ci struct memory_type_mapping *entry = 128562306a36Sopenharmony_ci &adapter->mem_type_mapping_tbl[idx]; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci vfree(entry->mem_ptr); 128862306a36Sopenharmony_ci entry->mem_ptr = NULL; 128962306a36Sopenharmony_ci entry->mem_size = 0; 129062306a36Sopenharmony_ci } 129162306a36Sopenharmony_ci} 129262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_prepare_fw_dump_info); 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci/* 129562306a36Sopenharmony_ci * CFG802.11 network device handler for statistics retrieval. 129662306a36Sopenharmony_ci */ 129762306a36Sopenharmony_cistatic struct net_device_stats *mwifiex_get_stats(struct net_device *dev) 129862306a36Sopenharmony_ci{ 129962306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci return &priv->stats; 130262306a36Sopenharmony_ci} 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_cistatic u16 130562306a36Sopenharmony_cimwifiex_netdev_select_wmm_queue(struct net_device *dev, struct sk_buff *skb, 130662306a36Sopenharmony_ci struct net_device *sb_dev) 130762306a36Sopenharmony_ci{ 130862306a36Sopenharmony_ci skb->priority = cfg80211_classify8021d(skb, NULL); 130962306a36Sopenharmony_ci return mwifiex_1d_to_wmm_queue[skb->priority]; 131062306a36Sopenharmony_ci} 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci/* Network device handlers */ 131362306a36Sopenharmony_cistatic const struct net_device_ops mwifiex_netdev_ops = { 131462306a36Sopenharmony_ci .ndo_open = mwifiex_open, 131562306a36Sopenharmony_ci .ndo_stop = mwifiex_close, 131662306a36Sopenharmony_ci .ndo_start_xmit = mwifiex_hard_start_xmit, 131762306a36Sopenharmony_ci .ndo_set_mac_address = mwifiex_ndo_set_mac_address, 131862306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 131962306a36Sopenharmony_ci .ndo_tx_timeout = mwifiex_tx_timeout, 132062306a36Sopenharmony_ci .ndo_get_stats = mwifiex_get_stats, 132162306a36Sopenharmony_ci .ndo_set_rx_mode = mwifiex_set_multicast_list, 132262306a36Sopenharmony_ci .ndo_select_queue = mwifiex_netdev_select_wmm_queue, 132362306a36Sopenharmony_ci}; 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci/* 132662306a36Sopenharmony_ci * This function initializes the private structure parameters. 132762306a36Sopenharmony_ci * 132862306a36Sopenharmony_ci * The following wait queues are initialized - 132962306a36Sopenharmony_ci * - IOCTL wait queue 133062306a36Sopenharmony_ci * - Command wait queue 133162306a36Sopenharmony_ci * - Statistics wait queue 133262306a36Sopenharmony_ci * 133362306a36Sopenharmony_ci * ...and the following default parameters are set - 133462306a36Sopenharmony_ci * - Current key index : Set to 0 133562306a36Sopenharmony_ci * - Rate index : Set to auto 133662306a36Sopenharmony_ci * - Media connected : Set to disconnected 133762306a36Sopenharmony_ci * - Adhoc link sensed : Set to false 133862306a36Sopenharmony_ci * - Nick name : Set to null 133962306a36Sopenharmony_ci * - Number of Tx timeout : Set to 0 134062306a36Sopenharmony_ci * - Device address : Set to current address 134162306a36Sopenharmony_ci * - Rx histogram statistc : Set to 0 134262306a36Sopenharmony_ci * 134362306a36Sopenharmony_ci * In addition, the CFG80211 work queue is also created. 134462306a36Sopenharmony_ci */ 134562306a36Sopenharmony_civoid mwifiex_init_priv_params(struct mwifiex_private *priv, 134662306a36Sopenharmony_ci struct net_device *dev) 134762306a36Sopenharmony_ci{ 134862306a36Sopenharmony_ci dev->netdev_ops = &mwifiex_netdev_ops; 134962306a36Sopenharmony_ci dev->needs_free_netdev = true; 135062306a36Sopenharmony_ci /* Initialize private structure */ 135162306a36Sopenharmony_ci priv->current_key_index = 0; 135262306a36Sopenharmony_ci priv->media_connected = false; 135362306a36Sopenharmony_ci memset(priv->mgmt_ie, 0, 135462306a36Sopenharmony_ci sizeof(struct mwifiex_ie) * MAX_MGMT_IE_INDEX); 135562306a36Sopenharmony_ci priv->beacon_idx = MWIFIEX_AUTO_IDX_MASK; 135662306a36Sopenharmony_ci priv->proberesp_idx = MWIFIEX_AUTO_IDX_MASK; 135762306a36Sopenharmony_ci priv->assocresp_idx = MWIFIEX_AUTO_IDX_MASK; 135862306a36Sopenharmony_ci priv->gen_idx = MWIFIEX_AUTO_IDX_MASK; 135962306a36Sopenharmony_ci priv->num_tx_timeout = 0; 136062306a36Sopenharmony_ci if (is_valid_ether_addr(dev->dev_addr)) 136162306a36Sopenharmony_ci ether_addr_copy(priv->curr_addr, dev->dev_addr); 136262306a36Sopenharmony_ci else 136362306a36Sopenharmony_ci ether_addr_copy(priv->curr_addr, priv->adapter->perm_addr); 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || 136662306a36Sopenharmony_ci GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { 136762306a36Sopenharmony_ci priv->hist_data = kmalloc(sizeof(*priv->hist_data), GFP_KERNEL); 136862306a36Sopenharmony_ci if (priv->hist_data) 136962306a36Sopenharmony_ci mwifiex_hist_data_reset(priv); 137062306a36Sopenharmony_ci } 137162306a36Sopenharmony_ci} 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci/* 137462306a36Sopenharmony_ci * This function check if command is pending. 137562306a36Sopenharmony_ci */ 137662306a36Sopenharmony_ciint is_command_pending(struct mwifiex_adapter *adapter) 137762306a36Sopenharmony_ci{ 137862306a36Sopenharmony_ci int is_cmd_pend_q_empty; 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci spin_lock_bh(&adapter->cmd_pending_q_lock); 138162306a36Sopenharmony_ci is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q); 138262306a36Sopenharmony_ci spin_unlock_bh(&adapter->cmd_pending_q_lock); 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci return !is_cmd_pend_q_empty; 138562306a36Sopenharmony_ci} 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci/* 138862306a36Sopenharmony_ci * This is the RX work queue function. 138962306a36Sopenharmony_ci * 139062306a36Sopenharmony_ci * It handles the RX operations. 139162306a36Sopenharmony_ci */ 139262306a36Sopenharmony_cistatic void mwifiex_rx_work_queue(struct work_struct *work) 139362306a36Sopenharmony_ci{ 139462306a36Sopenharmony_ci struct mwifiex_adapter *adapter = 139562306a36Sopenharmony_ci container_of(work, struct mwifiex_adapter, rx_work); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci if (test_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags)) 139862306a36Sopenharmony_ci return; 139962306a36Sopenharmony_ci mwifiex_process_rx(adapter); 140062306a36Sopenharmony_ci} 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci/* 140362306a36Sopenharmony_ci * This is the main work queue function. 140462306a36Sopenharmony_ci * 140562306a36Sopenharmony_ci * It handles the main process, which in turn handles the complete 140662306a36Sopenharmony_ci * driver operations. 140762306a36Sopenharmony_ci */ 140862306a36Sopenharmony_cistatic void mwifiex_main_work_queue(struct work_struct *work) 140962306a36Sopenharmony_ci{ 141062306a36Sopenharmony_ci struct mwifiex_adapter *adapter = 141162306a36Sopenharmony_ci container_of(work, struct mwifiex_adapter, main_work); 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci if (test_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags)) 141462306a36Sopenharmony_ci return; 141562306a36Sopenharmony_ci mwifiex_main_process(adapter); 141662306a36Sopenharmony_ci} 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci/* Common teardown code used for both device removal and reset */ 141962306a36Sopenharmony_cistatic void mwifiex_uninit_sw(struct mwifiex_adapter *adapter) 142062306a36Sopenharmony_ci{ 142162306a36Sopenharmony_ci struct mwifiex_private *priv; 142262306a36Sopenharmony_ci int i; 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci /* We can no longer handle interrupts once we start doing the teardown 142562306a36Sopenharmony_ci * below. 142662306a36Sopenharmony_ci */ 142762306a36Sopenharmony_ci if (adapter->if_ops.disable_int) 142862306a36Sopenharmony_ci adapter->if_ops.disable_int(adapter); 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci set_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags); 143162306a36Sopenharmony_ci mwifiex_terminate_workqueue(adapter); 143262306a36Sopenharmony_ci adapter->int_status = 0; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci /* Stop data */ 143562306a36Sopenharmony_ci for (i = 0; i < adapter->priv_num; i++) { 143662306a36Sopenharmony_ci priv = adapter->priv[i]; 143762306a36Sopenharmony_ci if (priv && priv->netdev) { 143862306a36Sopenharmony_ci mwifiex_stop_net_dev_queue(priv->netdev, adapter); 143962306a36Sopenharmony_ci if (netif_carrier_ok(priv->netdev)) 144062306a36Sopenharmony_ci netif_carrier_off(priv->netdev); 144162306a36Sopenharmony_ci netif_device_detach(priv->netdev); 144262306a36Sopenharmony_ci } 144362306a36Sopenharmony_ci } 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci mwifiex_dbg(adapter, CMD, "cmd: calling mwifiex_shutdown_drv...\n"); 144662306a36Sopenharmony_ci mwifiex_shutdown_drv(adapter); 144762306a36Sopenharmony_ci mwifiex_dbg(adapter, CMD, "cmd: mwifiex_shutdown_drv done\n"); 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci if (atomic_read(&adapter->rx_pending) || 145062306a36Sopenharmony_ci atomic_read(&adapter->tx_pending) || 145162306a36Sopenharmony_ci atomic_read(&adapter->cmd_pending)) { 145262306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 145362306a36Sopenharmony_ci "rx_pending=%d, tx_pending=%d,\t" 145462306a36Sopenharmony_ci "cmd_pending=%d\n", 145562306a36Sopenharmony_ci atomic_read(&adapter->rx_pending), 145662306a36Sopenharmony_ci atomic_read(&adapter->tx_pending), 145762306a36Sopenharmony_ci atomic_read(&adapter->cmd_pending)); 145862306a36Sopenharmony_ci } 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci for (i = 0; i < adapter->priv_num; i++) { 146162306a36Sopenharmony_ci priv = adapter->priv[i]; 146262306a36Sopenharmony_ci if (!priv) 146362306a36Sopenharmony_ci continue; 146462306a36Sopenharmony_ci rtnl_lock(); 146562306a36Sopenharmony_ci if (priv->netdev && 146662306a36Sopenharmony_ci priv->wdev.iftype != NL80211_IFTYPE_UNSPECIFIED) { 146762306a36Sopenharmony_ci /* 146862306a36Sopenharmony_ci * Close the netdev now, because if we do it later, the 146962306a36Sopenharmony_ci * netdev notifiers will need to acquire the wiphy lock 147062306a36Sopenharmony_ci * again --> deadlock. 147162306a36Sopenharmony_ci */ 147262306a36Sopenharmony_ci dev_close(priv->wdev.netdev); 147362306a36Sopenharmony_ci wiphy_lock(adapter->wiphy); 147462306a36Sopenharmony_ci mwifiex_del_virtual_intf(adapter->wiphy, &priv->wdev); 147562306a36Sopenharmony_ci wiphy_unlock(adapter->wiphy); 147662306a36Sopenharmony_ci } 147762306a36Sopenharmony_ci rtnl_unlock(); 147862306a36Sopenharmony_ci } 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci wiphy_unregister(adapter->wiphy); 148162306a36Sopenharmony_ci wiphy_free(adapter->wiphy); 148262306a36Sopenharmony_ci adapter->wiphy = NULL; 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci vfree(adapter->chan_stats); 148562306a36Sopenharmony_ci mwifiex_free_cmd_buffers(adapter); 148662306a36Sopenharmony_ci} 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci/* 148962306a36Sopenharmony_ci * This function can be used for shutting down the adapter SW. 149062306a36Sopenharmony_ci */ 149162306a36Sopenharmony_ciint mwifiex_shutdown_sw(struct mwifiex_adapter *adapter) 149262306a36Sopenharmony_ci{ 149362306a36Sopenharmony_ci struct mwifiex_private *priv; 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci if (!adapter) 149662306a36Sopenharmony_ci return 0; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci wait_for_completion(adapter->fw_done); 149962306a36Sopenharmony_ci /* Caller should ensure we aren't suspending while this happens */ 150062306a36Sopenharmony_ci reinit_completion(adapter->fw_done); 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); 150362306a36Sopenharmony_ci mwifiex_deauthenticate(priv, NULL); 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci mwifiex_init_shutdown_fw(priv, MWIFIEX_FUNC_SHUTDOWN); 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci mwifiex_uninit_sw(adapter); 150862306a36Sopenharmony_ci adapter->is_up = false; 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci if (adapter->if_ops.down_dev) 151162306a36Sopenharmony_ci adapter->if_ops.down_dev(adapter); 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci return 0; 151462306a36Sopenharmony_ci} 151562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_shutdown_sw); 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci/* This function can be used for reinitting the adapter SW. Required 151862306a36Sopenharmony_ci * code is extracted from mwifiex_add_card() 151962306a36Sopenharmony_ci */ 152062306a36Sopenharmony_ciint 152162306a36Sopenharmony_cimwifiex_reinit_sw(struct mwifiex_adapter *adapter) 152262306a36Sopenharmony_ci{ 152362306a36Sopenharmony_ci int ret; 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci mwifiex_init_lock_list(adapter); 152662306a36Sopenharmony_ci if (adapter->if_ops.up_dev) 152762306a36Sopenharmony_ci adapter->if_ops.up_dev(adapter); 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; 153062306a36Sopenharmony_ci clear_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags); 153162306a36Sopenharmony_ci init_waitqueue_head(&adapter->init_wait_q); 153262306a36Sopenharmony_ci clear_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags); 153362306a36Sopenharmony_ci adapter->hs_activated = false; 153462306a36Sopenharmony_ci clear_bit(MWIFIEX_IS_CMD_TIMEDOUT, &adapter->work_flags); 153562306a36Sopenharmony_ci init_waitqueue_head(&adapter->hs_activate_wait_q); 153662306a36Sopenharmony_ci init_waitqueue_head(&adapter->cmd_wait_q.wait); 153762306a36Sopenharmony_ci adapter->cmd_wait_q.status = 0; 153862306a36Sopenharmony_ci adapter->scan_wait_q_woken = false; 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci if ((num_possible_cpus() > 1) || adapter->iface_type == MWIFIEX_USB) 154162306a36Sopenharmony_ci adapter->rx_work_enabled = true; 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci adapter->workqueue = 154462306a36Sopenharmony_ci alloc_workqueue("MWIFIEX_WORK_QUEUE", 154562306a36Sopenharmony_ci WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 0); 154662306a36Sopenharmony_ci if (!adapter->workqueue) 154762306a36Sopenharmony_ci goto err_kmalloc; 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci INIT_WORK(&adapter->main_work, mwifiex_main_work_queue); 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci if (adapter->rx_work_enabled) { 155262306a36Sopenharmony_ci adapter->rx_workqueue = alloc_workqueue("MWIFIEX_RX_WORK_QUEUE", 155362306a36Sopenharmony_ci WQ_HIGHPRI | 155462306a36Sopenharmony_ci WQ_MEM_RECLAIM | 155562306a36Sopenharmony_ci WQ_UNBOUND, 0); 155662306a36Sopenharmony_ci if (!adapter->rx_workqueue) 155762306a36Sopenharmony_ci goto err_kmalloc; 155862306a36Sopenharmony_ci INIT_WORK(&adapter->rx_work, mwifiex_rx_work_queue); 155962306a36Sopenharmony_ci } 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci /* Register the device. Fill up the private data structure with 156262306a36Sopenharmony_ci * relevant information from the card. Some code extracted from 156362306a36Sopenharmony_ci * mwifiex_register_dev() 156462306a36Sopenharmony_ci */ 156562306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, "%s, mwifiex_init_hw_fw()...\n", __func__); 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci if (mwifiex_init_hw_fw(adapter, false)) { 156862306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 156962306a36Sopenharmony_ci "%s: firmware init failed\n", __func__); 157062306a36Sopenharmony_ci goto err_init_fw; 157162306a36Sopenharmony_ci } 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci /* _mwifiex_fw_dpc() does its own cleanup */ 157462306a36Sopenharmony_ci ret = _mwifiex_fw_dpc(adapter->firmware, adapter); 157562306a36Sopenharmony_ci if (ret) { 157662306a36Sopenharmony_ci pr_err("Failed to bring up adapter: %d\n", ret); 157762306a36Sopenharmony_ci return ret; 157862306a36Sopenharmony_ci } 157962306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__); 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci return 0; 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_cierr_init_fw: 158462306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, "info: %s: unregister device\n", __func__); 158562306a36Sopenharmony_ci if (adapter->if_ops.unregister_dev) 158662306a36Sopenharmony_ci adapter->if_ops.unregister_dev(adapter); 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_cierr_kmalloc: 158962306a36Sopenharmony_ci set_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags); 159062306a36Sopenharmony_ci mwifiex_terminate_workqueue(adapter); 159162306a36Sopenharmony_ci if (adapter->hw_status == MWIFIEX_HW_STATUS_READY) { 159262306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 159362306a36Sopenharmony_ci "info: %s: shutdown mwifiex\n", __func__); 159462306a36Sopenharmony_ci mwifiex_shutdown_drv(adapter); 159562306a36Sopenharmony_ci mwifiex_free_cmd_buffers(adapter); 159662306a36Sopenharmony_ci } 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci complete_all(adapter->fw_done); 159962306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, "%s, error\n", __func__); 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci return -1; 160262306a36Sopenharmony_ci} 160362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_reinit_sw); 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_cistatic irqreturn_t mwifiex_irq_wakeup_handler(int irq, void *priv) 160662306a36Sopenharmony_ci{ 160762306a36Sopenharmony_ci struct mwifiex_adapter *adapter = priv; 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci dev_dbg(adapter->dev, "%s: wake by wifi", __func__); 161062306a36Sopenharmony_ci adapter->wake_by_wifi = true; 161162306a36Sopenharmony_ci disable_irq_nosync(irq); 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci /* Notify PM core we are wakeup source */ 161462306a36Sopenharmony_ci pm_wakeup_event(adapter->dev, 0); 161562306a36Sopenharmony_ci pm_system_wakeup(); 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci return IRQ_HANDLED; 161862306a36Sopenharmony_ci} 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_cistatic void mwifiex_probe_of(struct mwifiex_adapter *adapter) 162162306a36Sopenharmony_ci{ 162262306a36Sopenharmony_ci int ret; 162362306a36Sopenharmony_ci struct device *dev = adapter->dev; 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci if (!dev->of_node) 162662306a36Sopenharmony_ci goto err_exit; 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci adapter->dt_node = dev->of_node; 162962306a36Sopenharmony_ci adapter->irq_wakeup = irq_of_parse_and_map(adapter->dt_node, 0); 163062306a36Sopenharmony_ci if (!adapter->irq_wakeup) { 163162306a36Sopenharmony_ci dev_dbg(dev, "fail to parse irq_wakeup from device tree\n"); 163262306a36Sopenharmony_ci goto err_exit; 163362306a36Sopenharmony_ci } 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci ret = devm_request_irq(dev, adapter->irq_wakeup, 163662306a36Sopenharmony_ci mwifiex_irq_wakeup_handler, IRQF_TRIGGER_LOW, 163762306a36Sopenharmony_ci "wifi_wake", adapter); 163862306a36Sopenharmony_ci if (ret) { 163962306a36Sopenharmony_ci dev_err(dev, "Failed to request irq_wakeup %d (%d)\n", 164062306a36Sopenharmony_ci adapter->irq_wakeup, ret); 164162306a36Sopenharmony_ci goto err_exit; 164262306a36Sopenharmony_ci } 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci disable_irq(adapter->irq_wakeup); 164562306a36Sopenharmony_ci if (device_init_wakeup(dev, true)) { 164662306a36Sopenharmony_ci dev_err(dev, "fail to init wakeup for mwifiex\n"); 164762306a36Sopenharmony_ci goto err_exit; 164862306a36Sopenharmony_ci } 164962306a36Sopenharmony_ci return; 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_cierr_exit: 165262306a36Sopenharmony_ci adapter->irq_wakeup = -1; 165362306a36Sopenharmony_ci} 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci/* 165662306a36Sopenharmony_ci * This function adds the card. 165762306a36Sopenharmony_ci * 165862306a36Sopenharmony_ci * This function follows the following major steps to set up the device - 165962306a36Sopenharmony_ci * - Initialize software. This includes probing the card, registering 166062306a36Sopenharmony_ci * the interface operations table, and allocating/initializing the 166162306a36Sopenharmony_ci * adapter structure 166262306a36Sopenharmony_ci * - Set up the netlink socket 166362306a36Sopenharmony_ci * - Create and start the main work queue 166462306a36Sopenharmony_ci * - Register the device 166562306a36Sopenharmony_ci * - Initialize firmware and hardware 166662306a36Sopenharmony_ci * - Add logical interfaces 166762306a36Sopenharmony_ci */ 166862306a36Sopenharmony_ciint 166962306a36Sopenharmony_cimwifiex_add_card(void *card, struct completion *fw_done, 167062306a36Sopenharmony_ci struct mwifiex_if_ops *if_ops, u8 iface_type, 167162306a36Sopenharmony_ci struct device *dev) 167262306a36Sopenharmony_ci{ 167362306a36Sopenharmony_ci struct mwifiex_adapter *adapter; 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci if (mwifiex_register(card, dev, if_ops, (void **)&adapter)) { 167662306a36Sopenharmony_ci pr_err("%s: software init failed\n", __func__); 167762306a36Sopenharmony_ci goto err_init_sw; 167862306a36Sopenharmony_ci } 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci mwifiex_probe_of(adapter); 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci adapter->iface_type = iface_type; 168362306a36Sopenharmony_ci adapter->fw_done = fw_done; 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; 168662306a36Sopenharmony_ci clear_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags); 168762306a36Sopenharmony_ci init_waitqueue_head(&adapter->init_wait_q); 168862306a36Sopenharmony_ci clear_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags); 168962306a36Sopenharmony_ci adapter->hs_activated = false; 169062306a36Sopenharmony_ci init_waitqueue_head(&adapter->hs_activate_wait_q); 169162306a36Sopenharmony_ci init_waitqueue_head(&adapter->cmd_wait_q.wait); 169262306a36Sopenharmony_ci adapter->cmd_wait_q.status = 0; 169362306a36Sopenharmony_ci adapter->scan_wait_q_woken = false; 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci if ((num_possible_cpus() > 1) || adapter->iface_type == MWIFIEX_USB) 169662306a36Sopenharmony_ci adapter->rx_work_enabled = true; 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci adapter->workqueue = 169962306a36Sopenharmony_ci alloc_workqueue("MWIFIEX_WORK_QUEUE", 170062306a36Sopenharmony_ci WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 0); 170162306a36Sopenharmony_ci if (!adapter->workqueue) 170262306a36Sopenharmony_ci goto err_kmalloc; 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci INIT_WORK(&adapter->main_work, mwifiex_main_work_queue); 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci if (adapter->rx_work_enabled) { 170762306a36Sopenharmony_ci adapter->rx_workqueue = alloc_workqueue("MWIFIEX_RX_WORK_QUEUE", 170862306a36Sopenharmony_ci WQ_HIGHPRI | 170962306a36Sopenharmony_ci WQ_MEM_RECLAIM | 171062306a36Sopenharmony_ci WQ_UNBOUND, 0); 171162306a36Sopenharmony_ci if (!adapter->rx_workqueue) 171262306a36Sopenharmony_ci goto err_kmalloc; 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci INIT_WORK(&adapter->rx_work, mwifiex_rx_work_queue); 171562306a36Sopenharmony_ci } 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci /* Register the device. Fill up the private data structure with relevant 171862306a36Sopenharmony_ci information from the card. */ 171962306a36Sopenharmony_ci if (adapter->if_ops.register_dev(adapter)) { 172062306a36Sopenharmony_ci pr_err("%s: failed to register mwifiex device\n", __func__); 172162306a36Sopenharmony_ci goto err_registerdev; 172262306a36Sopenharmony_ci } 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci if (mwifiex_init_hw_fw(adapter, true)) { 172562306a36Sopenharmony_ci pr_err("%s: firmware init failed\n", __func__); 172662306a36Sopenharmony_ci goto err_init_fw; 172762306a36Sopenharmony_ci } 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci return 0; 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_cierr_init_fw: 173262306a36Sopenharmony_ci pr_debug("info: %s: unregister device\n", __func__); 173362306a36Sopenharmony_ci if (adapter->if_ops.unregister_dev) 173462306a36Sopenharmony_ci adapter->if_ops.unregister_dev(adapter); 173562306a36Sopenharmony_cierr_registerdev: 173662306a36Sopenharmony_ci set_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags); 173762306a36Sopenharmony_ci mwifiex_terminate_workqueue(adapter); 173862306a36Sopenharmony_ci if (adapter->hw_status == MWIFIEX_HW_STATUS_READY) { 173962306a36Sopenharmony_ci pr_debug("info: %s: shutdown mwifiex\n", __func__); 174062306a36Sopenharmony_ci mwifiex_shutdown_drv(adapter); 174162306a36Sopenharmony_ci mwifiex_free_cmd_buffers(adapter); 174262306a36Sopenharmony_ci } 174362306a36Sopenharmony_cierr_kmalloc: 174462306a36Sopenharmony_ci if (adapter->irq_wakeup >= 0) 174562306a36Sopenharmony_ci device_init_wakeup(adapter->dev, false); 174662306a36Sopenharmony_ci mwifiex_free_adapter(adapter); 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_cierr_init_sw: 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci return -1; 175162306a36Sopenharmony_ci} 175262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_add_card); 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci/* 175562306a36Sopenharmony_ci * This function removes the card. 175662306a36Sopenharmony_ci * 175762306a36Sopenharmony_ci * This function follows the following major steps to remove the device - 175862306a36Sopenharmony_ci * - Stop data traffic 175962306a36Sopenharmony_ci * - Shutdown firmware 176062306a36Sopenharmony_ci * - Remove the logical interfaces 176162306a36Sopenharmony_ci * - Terminate the work queue 176262306a36Sopenharmony_ci * - Unregister the device 176362306a36Sopenharmony_ci * - Free the adapter structure 176462306a36Sopenharmony_ci */ 176562306a36Sopenharmony_ciint mwifiex_remove_card(struct mwifiex_adapter *adapter) 176662306a36Sopenharmony_ci{ 176762306a36Sopenharmony_ci if (!adapter) 176862306a36Sopenharmony_ci return 0; 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci if (adapter->is_up) 177162306a36Sopenharmony_ci mwifiex_uninit_sw(adapter); 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci if (adapter->irq_wakeup >= 0) 177462306a36Sopenharmony_ci device_init_wakeup(adapter->dev, false); 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci /* Unregister device */ 177762306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, 177862306a36Sopenharmony_ci "info: unregister device\n"); 177962306a36Sopenharmony_ci if (adapter->if_ops.unregister_dev) 178062306a36Sopenharmony_ci adapter->if_ops.unregister_dev(adapter); 178162306a36Sopenharmony_ci /* Free adapter structure */ 178262306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, 178362306a36Sopenharmony_ci "info: free adapter\n"); 178462306a36Sopenharmony_ci mwifiex_free_adapter(adapter); 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci return 0; 178762306a36Sopenharmony_ci} 178862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_remove_card); 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_civoid _mwifiex_dbg(const struct mwifiex_adapter *adapter, int mask, 179162306a36Sopenharmony_ci const char *fmt, ...) 179262306a36Sopenharmony_ci{ 179362306a36Sopenharmony_ci struct va_format vaf; 179462306a36Sopenharmony_ci va_list args; 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci if (!(adapter->debug_mask & mask)) 179762306a36Sopenharmony_ci return; 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci va_start(args, fmt); 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci vaf.fmt = fmt; 180262306a36Sopenharmony_ci vaf.va = &args; 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci if (adapter->dev) 180562306a36Sopenharmony_ci dev_info(adapter->dev, "%pV", &vaf); 180662306a36Sopenharmony_ci else 180762306a36Sopenharmony_ci pr_info("%pV", &vaf); 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci va_end(args); 181062306a36Sopenharmony_ci} 181162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(_mwifiex_dbg); 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci/* 181462306a36Sopenharmony_ci * This function initializes the module. 181562306a36Sopenharmony_ci * 181662306a36Sopenharmony_ci * The debug FS is also initialized if configured. 181762306a36Sopenharmony_ci */ 181862306a36Sopenharmony_cistatic int 181962306a36Sopenharmony_cimwifiex_init_module(void) 182062306a36Sopenharmony_ci{ 182162306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 182262306a36Sopenharmony_ci mwifiex_debugfs_init(); 182362306a36Sopenharmony_ci#endif 182462306a36Sopenharmony_ci return 0; 182562306a36Sopenharmony_ci} 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci/* 182862306a36Sopenharmony_ci * This function cleans up the module. 182962306a36Sopenharmony_ci * 183062306a36Sopenharmony_ci * The debug FS is removed if available. 183162306a36Sopenharmony_ci */ 183262306a36Sopenharmony_cistatic void 183362306a36Sopenharmony_cimwifiex_cleanup_module(void) 183462306a36Sopenharmony_ci{ 183562306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 183662306a36Sopenharmony_ci mwifiex_debugfs_remove(); 183762306a36Sopenharmony_ci#endif 183862306a36Sopenharmony_ci} 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_cimodule_init(mwifiex_init_module); 184162306a36Sopenharmony_cimodule_exit(mwifiex_cleanup_module); 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ciMODULE_AUTHOR("Marvell International Ltd."); 184462306a36Sopenharmony_ciMODULE_DESCRIPTION("Marvell WiFi-Ex Driver version " VERSION); 184562306a36Sopenharmony_ciMODULE_VERSION(VERSION); 184662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1847