18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * NXP Wireless LAN device driver: major functions
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright 2011-2020 NXP
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * This software file (the "File") is distributed by NXP
78c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License Version 2, June 1991
88c2ecf20Sopenharmony_ci * (the "License").  You may use, redistribute and/or modify this File in
98c2ecf20Sopenharmony_ci * accordance with the terms and conditions of the License, a copy of which
108c2ecf20Sopenharmony_ci * is available by writing to the Free Software Foundation, Inc.,
118c2ecf20Sopenharmony_ci * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
128c2ecf20Sopenharmony_ci * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
158c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
168c2ecf20Sopenharmony_ci * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
178c2ecf20Sopenharmony_ci * this warranty disclaimer.
188c2ecf20Sopenharmony_ci */
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <linux/suspend.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include "main.h"
238c2ecf20Sopenharmony_ci#include "wmm.h"
248c2ecf20Sopenharmony_ci#include "cfg80211.h"
258c2ecf20Sopenharmony_ci#include "11n.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define VERSION	"1.0"
288c2ecf20Sopenharmony_ci#define MFG_FIRMWARE	"mwifiex_mfg.bin"
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic unsigned int debug_mask = MWIFIEX_DEFAULT_DEBUG_MASK;
318c2ecf20Sopenharmony_cimodule_param(debug_mask, uint, 0);
328c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug_mask, "bitmap for debug flags");
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ciconst char driver_version[] = "mwifiex " VERSION " (%s) ";
358c2ecf20Sopenharmony_cistatic char *cal_data_cfg;
368c2ecf20Sopenharmony_cimodule_param(cal_data_cfg, charp, 0);
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic unsigned short driver_mode;
398c2ecf20Sopenharmony_cimodule_param(driver_mode, ushort, 0);
408c2ecf20Sopenharmony_ciMODULE_PARM_DESC(driver_mode,
418c2ecf20Sopenharmony_ci		 "station=0x1(default), ap-sta=0x3, station-p2p=0x5, ap-sta-p2p=0x7");
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cibool mfg_mode;
448c2ecf20Sopenharmony_cimodule_param(mfg_mode, bool, 0);
458c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mfg_mode, "manufacturing mode enable:1, disable:0");
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cibool aggr_ctrl;
488c2ecf20Sopenharmony_cimodule_param(aggr_ctrl, bool, 0000);
498c2ecf20Sopenharmony_ciMODULE_PARM_DESC(aggr_ctrl, "usb tx aggregation enable:1, disable:0");
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ciconst u16 mwifiex_1d_to_wmm_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci/*
548c2ecf20Sopenharmony_ci * This function registers the device and performs all the necessary
558c2ecf20Sopenharmony_ci * initializations.
568c2ecf20Sopenharmony_ci *
578c2ecf20Sopenharmony_ci * The following initialization operations are performed -
588c2ecf20Sopenharmony_ci *      - Allocate adapter structure
598c2ecf20Sopenharmony_ci *      - Save interface specific operations table in adapter
608c2ecf20Sopenharmony_ci *      - Call interface specific initialization routine
618c2ecf20Sopenharmony_ci *      - Allocate private structures
628c2ecf20Sopenharmony_ci *      - Set default adapter structure parameters
638c2ecf20Sopenharmony_ci *      - Initialize locks
648c2ecf20Sopenharmony_ci *
658c2ecf20Sopenharmony_ci * In case of any errors during inittialization, this function also ensures
668c2ecf20Sopenharmony_ci * proper cleanup before exiting.
678c2ecf20Sopenharmony_ci */
688c2ecf20Sopenharmony_cistatic int mwifiex_register(void *card, struct device *dev,
698c2ecf20Sopenharmony_ci			    struct mwifiex_if_ops *if_ops, void **padapter)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	struct mwifiex_adapter *adapter;
728c2ecf20Sopenharmony_ci	int i;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	adapter = kzalloc(sizeof(struct mwifiex_adapter), GFP_KERNEL);
758c2ecf20Sopenharmony_ci	if (!adapter)
768c2ecf20Sopenharmony_ci		return -ENOMEM;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	*padapter = adapter;
798c2ecf20Sopenharmony_ci	adapter->dev = dev;
808c2ecf20Sopenharmony_ci	adapter->card = card;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	/* Save interface specific operations in adapter */
838c2ecf20Sopenharmony_ci	memmove(&adapter->if_ops, if_ops, sizeof(struct mwifiex_if_ops));
848c2ecf20Sopenharmony_ci	adapter->debug_mask = debug_mask;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	/* card specific initialization has been deferred until now .. */
878c2ecf20Sopenharmony_ci	if (adapter->if_ops.init_if)
888c2ecf20Sopenharmony_ci		if (adapter->if_ops.init_if(adapter))
898c2ecf20Sopenharmony_ci			goto error;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	adapter->priv_num = 0;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) {
948c2ecf20Sopenharmony_ci		/* Allocate memory for private structure */
958c2ecf20Sopenharmony_ci		adapter->priv[i] =
968c2ecf20Sopenharmony_ci			kzalloc(sizeof(struct mwifiex_private), GFP_KERNEL);
978c2ecf20Sopenharmony_ci		if (!adapter->priv[i])
988c2ecf20Sopenharmony_ci			goto error;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci		adapter->priv[i]->adapter = adapter;
1018c2ecf20Sopenharmony_ci		adapter->priv_num++;
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci	mwifiex_init_lock_list(adapter);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	timer_setup(&adapter->cmd_timer, mwifiex_cmd_timeout_func, 0);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	return 0;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cierror:
1108c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, ERROR,
1118c2ecf20Sopenharmony_ci		    "info: leave mwifiex_register with error\n");
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	for (i = 0; i < adapter->priv_num; i++)
1148c2ecf20Sopenharmony_ci		kfree(adapter->priv[i]);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	kfree(adapter);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	return -1;
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci/*
1228c2ecf20Sopenharmony_ci * This function unregisters the device and performs all the necessary
1238c2ecf20Sopenharmony_ci * cleanups.
1248c2ecf20Sopenharmony_ci *
1258c2ecf20Sopenharmony_ci * The following cleanup operations are performed -
1268c2ecf20Sopenharmony_ci *      - Free the timers
1278c2ecf20Sopenharmony_ci *      - Free beacon buffers
1288c2ecf20Sopenharmony_ci *      - Free private structures
1298c2ecf20Sopenharmony_ci *      - Free adapter structure
1308c2ecf20Sopenharmony_ci */
1318c2ecf20Sopenharmony_cistatic int mwifiex_unregister(struct mwifiex_adapter *adapter)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	s32 i;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	if (adapter->if_ops.cleanup_if)
1368c2ecf20Sopenharmony_ci		adapter->if_ops.cleanup_if(adapter);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	del_timer_sync(&adapter->cmd_timer);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	/* Free private structures */
1418c2ecf20Sopenharmony_ci	for (i = 0; i < adapter->priv_num; i++) {
1428c2ecf20Sopenharmony_ci		if (adapter->priv[i]) {
1438c2ecf20Sopenharmony_ci			mwifiex_free_curr_bcn(adapter->priv[i]);
1448c2ecf20Sopenharmony_ci			kfree(adapter->priv[i]);
1458c2ecf20Sopenharmony_ci		}
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	if (adapter->nd_info) {
1498c2ecf20Sopenharmony_ci		for (i = 0 ; i < adapter->nd_info->n_matches ; i++)
1508c2ecf20Sopenharmony_ci			kfree(adapter->nd_info->matches[i]);
1518c2ecf20Sopenharmony_ci		kfree(adapter->nd_info);
1528c2ecf20Sopenharmony_ci		adapter->nd_info = NULL;
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	kfree(adapter->regd);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	kfree(adapter);
1588c2ecf20Sopenharmony_ci	return 0;
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_civoid mwifiex_queue_main_work(struct mwifiex_adapter *adapter)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	unsigned long flags;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	spin_lock_irqsave(&adapter->main_proc_lock, flags);
1668c2ecf20Sopenharmony_ci	if (adapter->mwifiex_processing) {
1678c2ecf20Sopenharmony_ci		adapter->more_task_flag = true;
1688c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
1698c2ecf20Sopenharmony_ci	} else {
1708c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
1718c2ecf20Sopenharmony_ci		queue_work(adapter->workqueue, &adapter->main_work);
1728c2ecf20Sopenharmony_ci	}
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_queue_main_work);
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic void mwifiex_queue_rx_work(struct mwifiex_adapter *adapter)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	spin_lock_bh(&adapter->rx_proc_lock);
1798c2ecf20Sopenharmony_ci	if (adapter->rx_processing) {
1808c2ecf20Sopenharmony_ci		spin_unlock_bh(&adapter->rx_proc_lock);
1818c2ecf20Sopenharmony_ci	} else {
1828c2ecf20Sopenharmony_ci		spin_unlock_bh(&adapter->rx_proc_lock);
1838c2ecf20Sopenharmony_ci		queue_work(adapter->rx_workqueue, &adapter->rx_work);
1848c2ecf20Sopenharmony_ci	}
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic int mwifiex_process_rx(struct mwifiex_adapter *adapter)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	struct sk_buff *skb;
1908c2ecf20Sopenharmony_ci	struct mwifiex_rxinfo *rx_info;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	spin_lock_bh(&adapter->rx_proc_lock);
1938c2ecf20Sopenharmony_ci	if (adapter->rx_processing || adapter->rx_locked) {
1948c2ecf20Sopenharmony_ci		spin_unlock_bh(&adapter->rx_proc_lock);
1958c2ecf20Sopenharmony_ci		goto exit_rx_proc;
1968c2ecf20Sopenharmony_ci	} else {
1978c2ecf20Sopenharmony_ci		adapter->rx_processing = true;
1988c2ecf20Sopenharmony_ci		spin_unlock_bh(&adapter->rx_proc_lock);
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	/* Check for Rx data */
2028c2ecf20Sopenharmony_ci	while ((skb = skb_dequeue(&adapter->rx_data_q))) {
2038c2ecf20Sopenharmony_ci		atomic_dec(&adapter->rx_pending);
2048c2ecf20Sopenharmony_ci		if ((adapter->delay_main_work ||
2058c2ecf20Sopenharmony_ci		     adapter->iface_type == MWIFIEX_USB) &&
2068c2ecf20Sopenharmony_ci		    (atomic_read(&adapter->rx_pending) < LOW_RX_PENDING)) {
2078c2ecf20Sopenharmony_ci			if (adapter->if_ops.submit_rem_rx_urbs)
2088c2ecf20Sopenharmony_ci				adapter->if_ops.submit_rem_rx_urbs(adapter);
2098c2ecf20Sopenharmony_ci			adapter->delay_main_work = false;
2108c2ecf20Sopenharmony_ci			mwifiex_queue_main_work(adapter);
2118c2ecf20Sopenharmony_ci		}
2128c2ecf20Sopenharmony_ci		rx_info = MWIFIEX_SKB_RXCB(skb);
2138c2ecf20Sopenharmony_ci		if (rx_info->buf_type == MWIFIEX_TYPE_AGGR_DATA) {
2148c2ecf20Sopenharmony_ci			if (adapter->if_ops.deaggr_pkt)
2158c2ecf20Sopenharmony_ci				adapter->if_ops.deaggr_pkt(adapter, skb);
2168c2ecf20Sopenharmony_ci			dev_kfree_skb_any(skb);
2178c2ecf20Sopenharmony_ci		} else {
2188c2ecf20Sopenharmony_ci			mwifiex_handle_rx_packet(adapter, skb);
2198c2ecf20Sopenharmony_ci		}
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci	spin_lock_bh(&adapter->rx_proc_lock);
2228c2ecf20Sopenharmony_ci	adapter->rx_processing = false;
2238c2ecf20Sopenharmony_ci	spin_unlock_bh(&adapter->rx_proc_lock);
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ciexit_rx_proc:
2268c2ecf20Sopenharmony_ci	return 0;
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci/*
2308c2ecf20Sopenharmony_ci * The main process.
2318c2ecf20Sopenharmony_ci *
2328c2ecf20Sopenharmony_ci * This function is the main procedure of the driver and handles various driver
2338c2ecf20Sopenharmony_ci * operations. It runs in a loop and provides the core functionalities.
2348c2ecf20Sopenharmony_ci *
2358c2ecf20Sopenharmony_ci * The main responsibilities of this function are -
2368c2ecf20Sopenharmony_ci *      - Ensure concurrency control
2378c2ecf20Sopenharmony_ci *      - Handle pending interrupts and call interrupt handlers
2388c2ecf20Sopenharmony_ci *      - Wake up the card if required
2398c2ecf20Sopenharmony_ci *      - Handle command responses and call response handlers
2408c2ecf20Sopenharmony_ci *      - Handle events and call event handlers
2418c2ecf20Sopenharmony_ci *      - Execute pending commands
2428c2ecf20Sopenharmony_ci *      - Transmit pending data packets
2438c2ecf20Sopenharmony_ci */
2448c2ecf20Sopenharmony_ciint mwifiex_main_process(struct mwifiex_adapter *adapter)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	int ret = 0;
2478c2ecf20Sopenharmony_ci	unsigned long flags;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	spin_lock_irqsave(&adapter->main_proc_lock, flags);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	/* Check if already processing */
2528c2ecf20Sopenharmony_ci	if (adapter->mwifiex_processing || adapter->main_locked) {
2538c2ecf20Sopenharmony_ci		adapter->more_task_flag = true;
2548c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
2558c2ecf20Sopenharmony_ci		return 0;
2568c2ecf20Sopenharmony_ci	} else {
2578c2ecf20Sopenharmony_ci		adapter->mwifiex_processing = true;
2588c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
2598c2ecf20Sopenharmony_ci	}
2608c2ecf20Sopenharmony_ciprocess_start:
2618c2ecf20Sopenharmony_ci	do {
2628c2ecf20Sopenharmony_ci		if (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY)
2638c2ecf20Sopenharmony_ci			break;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci		/* For non-USB interfaces, If we process interrupts first, it
2668c2ecf20Sopenharmony_ci		 * would increase RX pending even further. Avoid this by
2678c2ecf20Sopenharmony_ci		 * checking if rx_pending has crossed high threshold and
2688c2ecf20Sopenharmony_ci		 * schedule rx work queue and then process interrupts.
2698c2ecf20Sopenharmony_ci		 * For USB interface, there are no interrupts. We already have
2708c2ecf20Sopenharmony_ci		 * HIGH_RX_PENDING check in usb.c
2718c2ecf20Sopenharmony_ci		 */
2728c2ecf20Sopenharmony_ci		if (atomic_read(&adapter->rx_pending) >= HIGH_RX_PENDING &&
2738c2ecf20Sopenharmony_ci		    adapter->iface_type != MWIFIEX_USB) {
2748c2ecf20Sopenharmony_ci			adapter->delay_main_work = true;
2758c2ecf20Sopenharmony_ci			mwifiex_queue_rx_work(adapter);
2768c2ecf20Sopenharmony_ci			break;
2778c2ecf20Sopenharmony_ci		}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci		/* Handle pending interrupt if any */
2808c2ecf20Sopenharmony_ci		if (adapter->int_status) {
2818c2ecf20Sopenharmony_ci			if (adapter->hs_activated)
2828c2ecf20Sopenharmony_ci				mwifiex_process_hs_config(adapter);
2838c2ecf20Sopenharmony_ci			if (adapter->if_ops.process_int_status)
2848c2ecf20Sopenharmony_ci				adapter->if_ops.process_int_status(adapter);
2858c2ecf20Sopenharmony_ci		}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci		if (adapter->rx_work_enabled && adapter->data_received)
2888c2ecf20Sopenharmony_ci			mwifiex_queue_rx_work(adapter);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci		/* Need to wake up the card ? */
2918c2ecf20Sopenharmony_ci		if ((adapter->ps_state == PS_STATE_SLEEP) &&
2928c2ecf20Sopenharmony_ci		    (adapter->pm_wakeup_card_req &&
2938c2ecf20Sopenharmony_ci		     !adapter->pm_wakeup_fw_try) &&
2948c2ecf20Sopenharmony_ci		    (is_command_pending(adapter) ||
2958c2ecf20Sopenharmony_ci		     !skb_queue_empty(&adapter->tx_data_q) ||
2968c2ecf20Sopenharmony_ci		     !mwifiex_bypass_txlist_empty(adapter) ||
2978c2ecf20Sopenharmony_ci		     !mwifiex_wmm_lists_empty(adapter))) {
2988c2ecf20Sopenharmony_ci			adapter->pm_wakeup_fw_try = true;
2998c2ecf20Sopenharmony_ci			mod_timer(&adapter->wakeup_timer, jiffies + (HZ*3));
3008c2ecf20Sopenharmony_ci			adapter->if_ops.wakeup(adapter);
3018c2ecf20Sopenharmony_ci			continue;
3028c2ecf20Sopenharmony_ci		}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci		if (IS_CARD_RX_RCVD(adapter)) {
3058c2ecf20Sopenharmony_ci			adapter->data_received = false;
3068c2ecf20Sopenharmony_ci			adapter->pm_wakeup_fw_try = false;
3078c2ecf20Sopenharmony_ci			del_timer(&adapter->wakeup_timer);
3088c2ecf20Sopenharmony_ci			if (adapter->ps_state == PS_STATE_SLEEP)
3098c2ecf20Sopenharmony_ci				adapter->ps_state = PS_STATE_AWAKE;
3108c2ecf20Sopenharmony_ci		} else {
3118c2ecf20Sopenharmony_ci			/* We have tried to wakeup the card already */
3128c2ecf20Sopenharmony_ci			if (adapter->pm_wakeup_fw_try)
3138c2ecf20Sopenharmony_ci				break;
3148c2ecf20Sopenharmony_ci			if (adapter->ps_state == PS_STATE_PRE_SLEEP)
3158c2ecf20Sopenharmony_ci				mwifiex_check_ps_cond(adapter);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci			if (adapter->ps_state != PS_STATE_AWAKE)
3188c2ecf20Sopenharmony_ci				break;
3198c2ecf20Sopenharmony_ci			if (adapter->tx_lock_flag) {
3208c2ecf20Sopenharmony_ci				if (adapter->iface_type == MWIFIEX_USB) {
3218c2ecf20Sopenharmony_ci					if (!adapter->usb_mc_setup)
3228c2ecf20Sopenharmony_ci						break;
3238c2ecf20Sopenharmony_ci				} else
3248c2ecf20Sopenharmony_ci					break;
3258c2ecf20Sopenharmony_ci			}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci			if ((!adapter->scan_chan_gap_enabled &&
3288c2ecf20Sopenharmony_ci			     adapter->scan_processing) || adapter->data_sent ||
3298c2ecf20Sopenharmony_ci			     mwifiex_is_tdls_chan_switching
3308c2ecf20Sopenharmony_ci			     (mwifiex_get_priv(adapter,
3318c2ecf20Sopenharmony_ci					       MWIFIEX_BSS_ROLE_STA)) ||
3328c2ecf20Sopenharmony_ci			    (mwifiex_wmm_lists_empty(adapter) &&
3338c2ecf20Sopenharmony_ci			     mwifiex_bypass_txlist_empty(adapter) &&
3348c2ecf20Sopenharmony_ci			     skb_queue_empty(&adapter->tx_data_q))) {
3358c2ecf20Sopenharmony_ci				if (adapter->cmd_sent || adapter->curr_cmd ||
3368c2ecf20Sopenharmony_ci					!mwifiex_is_send_cmd_allowed
3378c2ecf20Sopenharmony_ci						(mwifiex_get_priv(adapter,
3388c2ecf20Sopenharmony_ci						MWIFIEX_BSS_ROLE_STA)) ||
3398c2ecf20Sopenharmony_ci				    (!is_command_pending(adapter)))
3408c2ecf20Sopenharmony_ci					break;
3418c2ecf20Sopenharmony_ci			}
3428c2ecf20Sopenharmony_ci		}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci		/* Check for event */
3458c2ecf20Sopenharmony_ci		if (adapter->event_received) {
3468c2ecf20Sopenharmony_ci			adapter->event_received = false;
3478c2ecf20Sopenharmony_ci			mwifiex_process_event(adapter);
3488c2ecf20Sopenharmony_ci		}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci		/* Check for Cmd Resp */
3518c2ecf20Sopenharmony_ci		if (adapter->cmd_resp_received) {
3528c2ecf20Sopenharmony_ci			adapter->cmd_resp_received = false;
3538c2ecf20Sopenharmony_ci			mwifiex_process_cmdresp(adapter);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci			/* call mwifiex back when init_fw is done */
3568c2ecf20Sopenharmony_ci			if (adapter->hw_status == MWIFIEX_HW_STATUS_INIT_DONE) {
3578c2ecf20Sopenharmony_ci				adapter->hw_status = MWIFIEX_HW_STATUS_READY;
3588c2ecf20Sopenharmony_ci				mwifiex_init_fw_complete(adapter);
3598c2ecf20Sopenharmony_ci			}
3608c2ecf20Sopenharmony_ci		}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci		/* Check if we need to confirm Sleep Request
3638c2ecf20Sopenharmony_ci		   received previously */
3648c2ecf20Sopenharmony_ci		if (adapter->ps_state == PS_STATE_PRE_SLEEP)
3658c2ecf20Sopenharmony_ci			mwifiex_check_ps_cond(adapter);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci		/* * The ps_state may have been changed during processing of
3688c2ecf20Sopenharmony_ci		 * Sleep Request event.
3698c2ecf20Sopenharmony_ci		 */
3708c2ecf20Sopenharmony_ci		if ((adapter->ps_state == PS_STATE_SLEEP) ||
3718c2ecf20Sopenharmony_ci		    (adapter->ps_state == PS_STATE_PRE_SLEEP) ||
3728c2ecf20Sopenharmony_ci		    (adapter->ps_state == PS_STATE_SLEEP_CFM)) {
3738c2ecf20Sopenharmony_ci			continue;
3748c2ecf20Sopenharmony_ci		}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci		if (adapter->tx_lock_flag) {
3778c2ecf20Sopenharmony_ci			if (adapter->iface_type == MWIFIEX_USB) {
3788c2ecf20Sopenharmony_ci				if (!adapter->usb_mc_setup)
3798c2ecf20Sopenharmony_ci					continue;
3808c2ecf20Sopenharmony_ci			} else
3818c2ecf20Sopenharmony_ci				continue;
3828c2ecf20Sopenharmony_ci		}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci		if (!adapter->cmd_sent && !adapter->curr_cmd &&
3858c2ecf20Sopenharmony_ci		    mwifiex_is_send_cmd_allowed
3868c2ecf20Sopenharmony_ci		    (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA))) {
3878c2ecf20Sopenharmony_ci			if (mwifiex_exec_next_cmd(adapter) == -1) {
3888c2ecf20Sopenharmony_ci				ret = -1;
3898c2ecf20Sopenharmony_ci				break;
3908c2ecf20Sopenharmony_ci			}
3918c2ecf20Sopenharmony_ci		}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci		/** If USB Multi channel setup ongoing,
3948c2ecf20Sopenharmony_ci		 *  wait for ready to tx data.
3958c2ecf20Sopenharmony_ci		 */
3968c2ecf20Sopenharmony_ci		if (adapter->iface_type == MWIFIEX_USB &&
3978c2ecf20Sopenharmony_ci		    adapter->usb_mc_setup)
3988c2ecf20Sopenharmony_ci			continue;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci		if ((adapter->scan_chan_gap_enabled ||
4018c2ecf20Sopenharmony_ci		     !adapter->scan_processing) &&
4028c2ecf20Sopenharmony_ci		    !adapter->data_sent &&
4038c2ecf20Sopenharmony_ci		    !skb_queue_empty(&adapter->tx_data_q)) {
4048c2ecf20Sopenharmony_ci			mwifiex_process_tx_queue(adapter);
4058c2ecf20Sopenharmony_ci			if (adapter->hs_activated) {
4068c2ecf20Sopenharmony_ci				clear_bit(MWIFIEX_IS_HS_CONFIGURED,
4078c2ecf20Sopenharmony_ci					  &adapter->work_flags);
4088c2ecf20Sopenharmony_ci				mwifiex_hs_activated_event
4098c2ecf20Sopenharmony_ci					(mwifiex_get_priv
4108c2ecf20Sopenharmony_ci					(adapter, MWIFIEX_BSS_ROLE_ANY),
4118c2ecf20Sopenharmony_ci					false);
4128c2ecf20Sopenharmony_ci			}
4138c2ecf20Sopenharmony_ci		}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci		if ((adapter->scan_chan_gap_enabled ||
4168c2ecf20Sopenharmony_ci		     !adapter->scan_processing) &&
4178c2ecf20Sopenharmony_ci		    !adapter->data_sent &&
4188c2ecf20Sopenharmony_ci		    !mwifiex_bypass_txlist_empty(adapter) &&
4198c2ecf20Sopenharmony_ci		    !mwifiex_is_tdls_chan_switching
4208c2ecf20Sopenharmony_ci			(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA))) {
4218c2ecf20Sopenharmony_ci			mwifiex_process_bypass_tx(adapter);
4228c2ecf20Sopenharmony_ci			if (adapter->hs_activated) {
4238c2ecf20Sopenharmony_ci				clear_bit(MWIFIEX_IS_HS_CONFIGURED,
4248c2ecf20Sopenharmony_ci					  &adapter->work_flags);
4258c2ecf20Sopenharmony_ci				mwifiex_hs_activated_event
4268c2ecf20Sopenharmony_ci					(mwifiex_get_priv
4278c2ecf20Sopenharmony_ci					 (adapter, MWIFIEX_BSS_ROLE_ANY),
4288c2ecf20Sopenharmony_ci					 false);
4298c2ecf20Sopenharmony_ci			}
4308c2ecf20Sopenharmony_ci		}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci		if ((adapter->scan_chan_gap_enabled ||
4338c2ecf20Sopenharmony_ci		     !adapter->scan_processing) &&
4348c2ecf20Sopenharmony_ci		    !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter) &&
4358c2ecf20Sopenharmony_ci		    !mwifiex_is_tdls_chan_switching
4368c2ecf20Sopenharmony_ci			(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA))) {
4378c2ecf20Sopenharmony_ci			mwifiex_wmm_process_tx(adapter);
4388c2ecf20Sopenharmony_ci			if (adapter->hs_activated) {
4398c2ecf20Sopenharmony_ci				clear_bit(MWIFIEX_IS_HS_CONFIGURED,
4408c2ecf20Sopenharmony_ci					  &adapter->work_flags);
4418c2ecf20Sopenharmony_ci				mwifiex_hs_activated_event
4428c2ecf20Sopenharmony_ci					(mwifiex_get_priv
4438c2ecf20Sopenharmony_ci					 (adapter, MWIFIEX_BSS_ROLE_ANY),
4448c2ecf20Sopenharmony_ci					 false);
4458c2ecf20Sopenharmony_ci			}
4468c2ecf20Sopenharmony_ci		}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci		if (adapter->delay_null_pkt && !adapter->cmd_sent &&
4498c2ecf20Sopenharmony_ci		    !adapter->curr_cmd && !is_command_pending(adapter) &&
4508c2ecf20Sopenharmony_ci		    (mwifiex_wmm_lists_empty(adapter) &&
4518c2ecf20Sopenharmony_ci		     mwifiex_bypass_txlist_empty(adapter) &&
4528c2ecf20Sopenharmony_ci		     skb_queue_empty(&adapter->tx_data_q))) {
4538c2ecf20Sopenharmony_ci			if (!mwifiex_send_null_packet
4548c2ecf20Sopenharmony_ci			    (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
4558c2ecf20Sopenharmony_ci			     MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET |
4568c2ecf20Sopenharmony_ci			     MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET)) {
4578c2ecf20Sopenharmony_ci				adapter->delay_null_pkt = false;
4588c2ecf20Sopenharmony_ci				adapter->ps_state = PS_STATE_SLEEP;
4598c2ecf20Sopenharmony_ci			}
4608c2ecf20Sopenharmony_ci			break;
4618c2ecf20Sopenharmony_ci		}
4628c2ecf20Sopenharmony_ci	} while (true);
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	spin_lock_irqsave(&adapter->main_proc_lock, flags);
4658c2ecf20Sopenharmony_ci	if (adapter->more_task_flag) {
4668c2ecf20Sopenharmony_ci		adapter->more_task_flag = false;
4678c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
4688c2ecf20Sopenharmony_ci		goto process_start;
4698c2ecf20Sopenharmony_ci	}
4708c2ecf20Sopenharmony_ci	adapter->mwifiex_processing = false;
4718c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	return ret;
4748c2ecf20Sopenharmony_ci}
4758c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_main_process);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci/*
4788c2ecf20Sopenharmony_ci * This function frees the adapter structure.
4798c2ecf20Sopenharmony_ci *
4808c2ecf20Sopenharmony_ci * Additionally, this closes the netlink socket, frees the timers
4818c2ecf20Sopenharmony_ci * and private structures.
4828c2ecf20Sopenharmony_ci */
4838c2ecf20Sopenharmony_cistatic void mwifiex_free_adapter(struct mwifiex_adapter *adapter)
4848c2ecf20Sopenharmony_ci{
4858c2ecf20Sopenharmony_ci	if (!adapter) {
4868c2ecf20Sopenharmony_ci		pr_err("%s: adapter is NULL\n", __func__);
4878c2ecf20Sopenharmony_ci		return;
4888c2ecf20Sopenharmony_ci	}
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	mwifiex_unregister(adapter);
4918c2ecf20Sopenharmony_ci	pr_debug("info: %s: free adapter\n", __func__);
4928c2ecf20Sopenharmony_ci}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci/*
4958c2ecf20Sopenharmony_ci * This function cancels all works in the queue and destroys
4968c2ecf20Sopenharmony_ci * the main workqueue.
4978c2ecf20Sopenharmony_ci */
4988c2ecf20Sopenharmony_cistatic void mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter)
4998c2ecf20Sopenharmony_ci{
5008c2ecf20Sopenharmony_ci	if (adapter->workqueue) {
5018c2ecf20Sopenharmony_ci		flush_workqueue(adapter->workqueue);
5028c2ecf20Sopenharmony_ci		destroy_workqueue(adapter->workqueue);
5038c2ecf20Sopenharmony_ci		adapter->workqueue = NULL;
5048c2ecf20Sopenharmony_ci	}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	if (adapter->rx_workqueue) {
5078c2ecf20Sopenharmony_ci		flush_workqueue(adapter->rx_workqueue);
5088c2ecf20Sopenharmony_ci		destroy_workqueue(adapter->rx_workqueue);
5098c2ecf20Sopenharmony_ci		adapter->rx_workqueue = NULL;
5108c2ecf20Sopenharmony_ci	}
5118c2ecf20Sopenharmony_ci}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci/*
5148c2ecf20Sopenharmony_ci * This function gets firmware and initializes it.
5158c2ecf20Sopenharmony_ci *
5168c2ecf20Sopenharmony_ci * The main initialization steps followed are -
5178c2ecf20Sopenharmony_ci *      - Download the correct firmware to card
5188c2ecf20Sopenharmony_ci *      - Issue the init commands to firmware
5198c2ecf20Sopenharmony_ci */
5208c2ecf20Sopenharmony_cistatic int _mwifiex_fw_dpc(const struct firmware *firmware, void *context)
5218c2ecf20Sopenharmony_ci{
5228c2ecf20Sopenharmony_ci	int ret;
5238c2ecf20Sopenharmony_ci	char fmt[64];
5248c2ecf20Sopenharmony_ci	struct mwifiex_adapter *adapter = context;
5258c2ecf20Sopenharmony_ci	struct mwifiex_fw_image fw;
5268c2ecf20Sopenharmony_ci	bool init_failed = false;
5278c2ecf20Sopenharmony_ci	struct wireless_dev *wdev;
5288c2ecf20Sopenharmony_ci	struct completion *fw_done = adapter->fw_done;
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	if (!firmware) {
5318c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
5328c2ecf20Sopenharmony_ci			    "Failed to get firmware %s\n", adapter->fw_name);
5338c2ecf20Sopenharmony_ci		goto err_dnld_fw;
5348c2ecf20Sopenharmony_ci	}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	memset(&fw, 0, sizeof(struct mwifiex_fw_image));
5378c2ecf20Sopenharmony_ci	adapter->firmware = firmware;
5388c2ecf20Sopenharmony_ci	fw.fw_buf = (u8 *) adapter->firmware->data;
5398c2ecf20Sopenharmony_ci	fw.fw_len = adapter->firmware->size;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	if (adapter->if_ops.dnld_fw) {
5428c2ecf20Sopenharmony_ci		ret = adapter->if_ops.dnld_fw(adapter, &fw);
5438c2ecf20Sopenharmony_ci	} else {
5448c2ecf20Sopenharmony_ci		ret = mwifiex_dnld_fw(adapter, &fw);
5458c2ecf20Sopenharmony_ci	}
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	if (ret == -1)
5488c2ecf20Sopenharmony_ci		goto err_dnld_fw;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, MSG, "WLAN FW is active\n");
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	if (cal_data_cfg) {
5538c2ecf20Sopenharmony_ci		if ((request_firmware(&adapter->cal_data, cal_data_cfg,
5548c2ecf20Sopenharmony_ci				      adapter->dev)) < 0)
5558c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
5568c2ecf20Sopenharmony_ci				    "Cal data request_firmware() failed\n");
5578c2ecf20Sopenharmony_ci	}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	/* enable host interrupt after fw dnld is successful */
5608c2ecf20Sopenharmony_ci	if (adapter->if_ops.enable_int) {
5618c2ecf20Sopenharmony_ci		if (adapter->if_ops.enable_int(adapter))
5628c2ecf20Sopenharmony_ci			goto err_dnld_fw;
5638c2ecf20Sopenharmony_ci	}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	adapter->init_wait_q_woken = false;
5668c2ecf20Sopenharmony_ci	ret = mwifiex_init_fw(adapter);
5678c2ecf20Sopenharmony_ci	if (ret == -1) {
5688c2ecf20Sopenharmony_ci		goto err_init_fw;
5698c2ecf20Sopenharmony_ci	} else if (!ret) {
5708c2ecf20Sopenharmony_ci		adapter->hw_status = MWIFIEX_HW_STATUS_READY;
5718c2ecf20Sopenharmony_ci		goto done;
5728c2ecf20Sopenharmony_ci	}
5738c2ecf20Sopenharmony_ci	/* Wait for mwifiex_init to complete */
5748c2ecf20Sopenharmony_ci	if (!adapter->mfg_mode) {
5758c2ecf20Sopenharmony_ci		wait_event_interruptible(adapter->init_wait_q,
5768c2ecf20Sopenharmony_ci					 adapter->init_wait_q_woken);
5778c2ecf20Sopenharmony_ci		if (adapter->hw_status != MWIFIEX_HW_STATUS_READY)
5788c2ecf20Sopenharmony_ci			goto err_init_fw;
5798c2ecf20Sopenharmony_ci	}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	if (!adapter->wiphy) {
5828c2ecf20Sopenharmony_ci		if (mwifiex_register_cfg80211(adapter)) {
5838c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
5848c2ecf20Sopenharmony_ci				    "cannot register with cfg80211\n");
5858c2ecf20Sopenharmony_ci			goto err_init_fw;
5868c2ecf20Sopenharmony_ci		}
5878c2ecf20Sopenharmony_ci	}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	if (mwifiex_init_channel_scan_gap(adapter)) {
5908c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
5918c2ecf20Sopenharmony_ci			    "could not init channel stats table\n");
5928c2ecf20Sopenharmony_ci		goto err_init_chan_scan;
5938c2ecf20Sopenharmony_ci	}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	if (driver_mode) {
5968c2ecf20Sopenharmony_ci		driver_mode &= MWIFIEX_DRIVER_MODE_BITMASK;
5978c2ecf20Sopenharmony_ci		driver_mode |= MWIFIEX_DRIVER_MODE_STA;
5988c2ecf20Sopenharmony_ci	}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	rtnl_lock();
6018c2ecf20Sopenharmony_ci	/* Create station interface by default */
6028c2ecf20Sopenharmony_ci	wdev = mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d", NET_NAME_ENUM,
6038c2ecf20Sopenharmony_ci					NL80211_IFTYPE_STATION, NULL);
6048c2ecf20Sopenharmony_ci	if (IS_ERR(wdev)) {
6058c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
6068c2ecf20Sopenharmony_ci			    "cannot create default STA interface\n");
6078c2ecf20Sopenharmony_ci		rtnl_unlock();
6088c2ecf20Sopenharmony_ci		goto err_add_intf;
6098c2ecf20Sopenharmony_ci	}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	if (driver_mode & MWIFIEX_DRIVER_MODE_UAP) {
6128c2ecf20Sopenharmony_ci		wdev = mwifiex_add_virtual_intf(adapter->wiphy, "uap%d", NET_NAME_ENUM,
6138c2ecf20Sopenharmony_ci						NL80211_IFTYPE_AP, NULL);
6148c2ecf20Sopenharmony_ci		if (IS_ERR(wdev)) {
6158c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
6168c2ecf20Sopenharmony_ci				    "cannot create AP interface\n");
6178c2ecf20Sopenharmony_ci			rtnl_unlock();
6188c2ecf20Sopenharmony_ci			goto err_add_intf;
6198c2ecf20Sopenharmony_ci		}
6208c2ecf20Sopenharmony_ci	}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	if (driver_mode & MWIFIEX_DRIVER_MODE_P2P) {
6238c2ecf20Sopenharmony_ci		wdev = mwifiex_add_virtual_intf(adapter->wiphy, "p2p%d", NET_NAME_ENUM,
6248c2ecf20Sopenharmony_ci						NL80211_IFTYPE_P2P_CLIENT, NULL);
6258c2ecf20Sopenharmony_ci		if (IS_ERR(wdev)) {
6268c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
6278c2ecf20Sopenharmony_ci				    "cannot create p2p client interface\n");
6288c2ecf20Sopenharmony_ci			rtnl_unlock();
6298c2ecf20Sopenharmony_ci			goto err_add_intf;
6308c2ecf20Sopenharmony_ci		}
6318c2ecf20Sopenharmony_ci	}
6328c2ecf20Sopenharmony_ci	rtnl_unlock();
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1);
6358c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, MSG, "driver_version = %s\n", fmt);
6368c2ecf20Sopenharmony_ci	adapter->is_up = true;
6378c2ecf20Sopenharmony_ci	goto done;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_cierr_add_intf:
6408c2ecf20Sopenharmony_ci	vfree(adapter->chan_stats);
6418c2ecf20Sopenharmony_cierr_init_chan_scan:
6428c2ecf20Sopenharmony_ci	wiphy_unregister(adapter->wiphy);
6438c2ecf20Sopenharmony_ci	wiphy_free(adapter->wiphy);
6448c2ecf20Sopenharmony_cierr_init_fw:
6458c2ecf20Sopenharmony_ci	if (adapter->if_ops.disable_int)
6468c2ecf20Sopenharmony_ci		adapter->if_ops.disable_int(adapter);
6478c2ecf20Sopenharmony_cierr_dnld_fw:
6488c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, ERROR,
6498c2ecf20Sopenharmony_ci		    "info: %s: unregister device\n", __func__);
6508c2ecf20Sopenharmony_ci	if (adapter->if_ops.unregister_dev)
6518c2ecf20Sopenharmony_ci		adapter->if_ops.unregister_dev(adapter);
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	set_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags);
6548c2ecf20Sopenharmony_ci	mwifiex_terminate_workqueue(adapter);
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	if (adapter->hw_status == MWIFIEX_HW_STATUS_READY) {
6578c2ecf20Sopenharmony_ci		pr_debug("info: %s: shutdown mwifiex\n", __func__);
6588c2ecf20Sopenharmony_ci		mwifiex_shutdown_drv(adapter);
6598c2ecf20Sopenharmony_ci		mwifiex_free_cmd_buffers(adapter);
6608c2ecf20Sopenharmony_ci	}
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	init_failed = true;
6638c2ecf20Sopenharmony_cidone:
6648c2ecf20Sopenharmony_ci	if (adapter->cal_data) {
6658c2ecf20Sopenharmony_ci		release_firmware(adapter->cal_data);
6668c2ecf20Sopenharmony_ci		adapter->cal_data = NULL;
6678c2ecf20Sopenharmony_ci	}
6688c2ecf20Sopenharmony_ci	if (adapter->firmware) {
6698c2ecf20Sopenharmony_ci		release_firmware(adapter->firmware);
6708c2ecf20Sopenharmony_ci		adapter->firmware = NULL;
6718c2ecf20Sopenharmony_ci	}
6728c2ecf20Sopenharmony_ci	if (init_failed) {
6738c2ecf20Sopenharmony_ci		if (adapter->irq_wakeup >= 0)
6748c2ecf20Sopenharmony_ci			device_init_wakeup(adapter->dev, false);
6758c2ecf20Sopenharmony_ci		mwifiex_free_adapter(adapter);
6768c2ecf20Sopenharmony_ci	}
6778c2ecf20Sopenharmony_ci	/* Tell all current and future waiters we're finished */
6788c2ecf20Sopenharmony_ci	complete_all(fw_done);
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	return init_failed ? -EIO : 0;
6818c2ecf20Sopenharmony_ci}
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_cistatic void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
6848c2ecf20Sopenharmony_ci{
6858c2ecf20Sopenharmony_ci	_mwifiex_fw_dpc(firmware, context);
6868c2ecf20Sopenharmony_ci}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci/*
6898c2ecf20Sopenharmony_ci * This function gets the firmware and (if called asynchronously) kicks off the
6908c2ecf20Sopenharmony_ci * HW init when done.
6918c2ecf20Sopenharmony_ci */
6928c2ecf20Sopenharmony_cistatic int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter,
6938c2ecf20Sopenharmony_ci			      bool req_fw_nowait)
6948c2ecf20Sopenharmony_ci{
6958c2ecf20Sopenharmony_ci	int ret;
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	/* Override default firmware with manufacturing one if
6988c2ecf20Sopenharmony_ci	 * manufacturing mode is enabled
6998c2ecf20Sopenharmony_ci	 */
7008c2ecf20Sopenharmony_ci	if (mfg_mode) {
7018c2ecf20Sopenharmony_ci		if (strlcpy(adapter->fw_name, MFG_FIRMWARE,
7028c2ecf20Sopenharmony_ci			    sizeof(adapter->fw_name)) >=
7038c2ecf20Sopenharmony_ci			    sizeof(adapter->fw_name)) {
7048c2ecf20Sopenharmony_ci			pr_err("%s: fw_name too long!\n", __func__);
7058c2ecf20Sopenharmony_ci			return -1;
7068c2ecf20Sopenharmony_ci		}
7078c2ecf20Sopenharmony_ci	}
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	if (req_fw_nowait) {
7108c2ecf20Sopenharmony_ci		ret = request_firmware_nowait(THIS_MODULE, 1, adapter->fw_name,
7118c2ecf20Sopenharmony_ci					      adapter->dev, GFP_KERNEL, adapter,
7128c2ecf20Sopenharmony_ci					      mwifiex_fw_dpc);
7138c2ecf20Sopenharmony_ci	} else {
7148c2ecf20Sopenharmony_ci		ret = request_firmware(&adapter->firmware,
7158c2ecf20Sopenharmony_ci				       adapter->fw_name,
7168c2ecf20Sopenharmony_ci				       adapter->dev);
7178c2ecf20Sopenharmony_ci	}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	if (ret < 0)
7208c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR, "request_firmware%s error %d\n",
7218c2ecf20Sopenharmony_ci			    req_fw_nowait ? "_nowait" : "", ret);
7228c2ecf20Sopenharmony_ci	return ret;
7238c2ecf20Sopenharmony_ci}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci/*
7268c2ecf20Sopenharmony_ci * CFG802.11 network device handler for open.
7278c2ecf20Sopenharmony_ci *
7288c2ecf20Sopenharmony_ci * Starts the data queue.
7298c2ecf20Sopenharmony_ci */
7308c2ecf20Sopenharmony_cistatic int
7318c2ecf20Sopenharmony_cimwifiex_open(struct net_device *dev)
7328c2ecf20Sopenharmony_ci{
7338c2ecf20Sopenharmony_ci	netif_carrier_off(dev);
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	return 0;
7368c2ecf20Sopenharmony_ci}
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci/*
7398c2ecf20Sopenharmony_ci * CFG802.11 network device handler for close.
7408c2ecf20Sopenharmony_ci */
7418c2ecf20Sopenharmony_cistatic int
7428c2ecf20Sopenharmony_cimwifiex_close(struct net_device *dev)
7438c2ecf20Sopenharmony_ci{
7448c2ecf20Sopenharmony_ci	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	if (priv->scan_request) {
7478c2ecf20Sopenharmony_ci		struct cfg80211_scan_info info = {
7488c2ecf20Sopenharmony_ci			.aborted = true,
7498c2ecf20Sopenharmony_ci		};
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci		mwifiex_dbg(priv->adapter, INFO,
7528c2ecf20Sopenharmony_ci			    "aborting scan on ndo_stop\n");
7538c2ecf20Sopenharmony_ci		cfg80211_scan_done(priv->scan_request, &info);
7548c2ecf20Sopenharmony_ci		priv->scan_request = NULL;
7558c2ecf20Sopenharmony_ci		priv->scan_aborting = true;
7568c2ecf20Sopenharmony_ci	}
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	if (priv->sched_scanning) {
7598c2ecf20Sopenharmony_ci		mwifiex_dbg(priv->adapter, INFO,
7608c2ecf20Sopenharmony_ci			    "aborting bgscan on ndo_stop\n");
7618c2ecf20Sopenharmony_ci		mwifiex_stop_bg_scan(priv);
7628c2ecf20Sopenharmony_ci		cfg80211_sched_scan_stopped(priv->wdev.wiphy, 0);
7638c2ecf20Sopenharmony_ci	}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	return 0;
7668c2ecf20Sopenharmony_ci}
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_cistatic bool
7698c2ecf20Sopenharmony_cimwifiex_bypass_tx_queue(struct mwifiex_private *priv,
7708c2ecf20Sopenharmony_ci			struct sk_buff *skb)
7718c2ecf20Sopenharmony_ci{
7728c2ecf20Sopenharmony_ci	struct ethhdr *eth_hdr = (struct ethhdr *)skb->data;
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	if (ntohs(eth_hdr->h_proto) == ETH_P_PAE ||
7758c2ecf20Sopenharmony_ci	    mwifiex_is_skb_mgmt_frame(skb) ||
7768c2ecf20Sopenharmony_ci	    (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA &&
7778c2ecf20Sopenharmony_ci	     ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
7788c2ecf20Sopenharmony_ci	     (ntohs(eth_hdr->h_proto) == ETH_P_TDLS))) {
7798c2ecf20Sopenharmony_ci		mwifiex_dbg(priv->adapter, DATA,
7808c2ecf20Sopenharmony_ci			    "bypass txqueue; eth type %#x, mgmt %d\n",
7818c2ecf20Sopenharmony_ci			     ntohs(eth_hdr->h_proto),
7828c2ecf20Sopenharmony_ci			     mwifiex_is_skb_mgmt_frame(skb));
7838c2ecf20Sopenharmony_ci		return true;
7848c2ecf20Sopenharmony_ci	}
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	return false;
7878c2ecf20Sopenharmony_ci}
7888c2ecf20Sopenharmony_ci/*
7898c2ecf20Sopenharmony_ci * Add buffer into wmm tx queue and queue work to transmit it.
7908c2ecf20Sopenharmony_ci */
7918c2ecf20Sopenharmony_ciint mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb)
7928c2ecf20Sopenharmony_ci{
7938c2ecf20Sopenharmony_ci	struct netdev_queue *txq;
7948c2ecf20Sopenharmony_ci	int index = mwifiex_1d_to_wmm_queue[skb->priority];
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	if (atomic_inc_return(&priv->wmm_tx_pending[index]) >= MAX_TX_PENDING) {
7978c2ecf20Sopenharmony_ci		txq = netdev_get_tx_queue(priv->netdev, index);
7988c2ecf20Sopenharmony_ci		if (!netif_tx_queue_stopped(txq)) {
7998c2ecf20Sopenharmony_ci			netif_tx_stop_queue(txq);
8008c2ecf20Sopenharmony_ci			mwifiex_dbg(priv->adapter, DATA,
8018c2ecf20Sopenharmony_ci				    "stop queue: %d\n", index);
8028c2ecf20Sopenharmony_ci		}
8038c2ecf20Sopenharmony_ci	}
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	if (mwifiex_bypass_tx_queue(priv, skb)) {
8068c2ecf20Sopenharmony_ci		atomic_inc(&priv->adapter->tx_pending);
8078c2ecf20Sopenharmony_ci		atomic_inc(&priv->adapter->bypass_tx_pending);
8088c2ecf20Sopenharmony_ci		mwifiex_wmm_add_buf_bypass_txqueue(priv, skb);
8098c2ecf20Sopenharmony_ci	 } else {
8108c2ecf20Sopenharmony_ci		atomic_inc(&priv->adapter->tx_pending);
8118c2ecf20Sopenharmony_ci		mwifiex_wmm_add_buf_txqueue(priv, skb);
8128c2ecf20Sopenharmony_ci	 }
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	mwifiex_queue_main_work(priv->adapter);
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	return 0;
8178c2ecf20Sopenharmony_ci}
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_cistruct sk_buff *
8208c2ecf20Sopenharmony_cimwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv,
8218c2ecf20Sopenharmony_ci				struct sk_buff *skb, u8 flag, u64 *cookie)
8228c2ecf20Sopenharmony_ci{
8238c2ecf20Sopenharmony_ci	struct sk_buff *orig_skb = skb;
8248c2ecf20Sopenharmony_ci	struct mwifiex_txinfo *tx_info, *orig_tx_info;
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	skb = skb_clone(skb, GFP_ATOMIC);
8278c2ecf20Sopenharmony_ci	if (skb) {
8288c2ecf20Sopenharmony_ci		int id;
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci		spin_lock_bh(&priv->ack_status_lock);
8318c2ecf20Sopenharmony_ci		id = idr_alloc(&priv->ack_status_frames, orig_skb,
8328c2ecf20Sopenharmony_ci			       1, 0x10, GFP_ATOMIC);
8338c2ecf20Sopenharmony_ci		spin_unlock_bh(&priv->ack_status_lock);
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci		if (id >= 0) {
8368c2ecf20Sopenharmony_ci			tx_info = MWIFIEX_SKB_TXCB(skb);
8378c2ecf20Sopenharmony_ci			tx_info->ack_frame_id = id;
8388c2ecf20Sopenharmony_ci			tx_info->flags |= flag;
8398c2ecf20Sopenharmony_ci			orig_tx_info = MWIFIEX_SKB_TXCB(orig_skb);
8408c2ecf20Sopenharmony_ci			orig_tx_info->ack_frame_id = id;
8418c2ecf20Sopenharmony_ci			orig_tx_info->flags |= flag;
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci			if (flag == MWIFIEX_BUF_FLAG_ACTION_TX_STATUS && cookie)
8448c2ecf20Sopenharmony_ci				orig_tx_info->cookie = *cookie;
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci		} else if (skb_shared(skb)) {
8478c2ecf20Sopenharmony_ci			kfree_skb(orig_skb);
8488c2ecf20Sopenharmony_ci		} else {
8498c2ecf20Sopenharmony_ci			kfree_skb(skb);
8508c2ecf20Sopenharmony_ci			skb = orig_skb;
8518c2ecf20Sopenharmony_ci		}
8528c2ecf20Sopenharmony_ci	} else {
8538c2ecf20Sopenharmony_ci		/* couldn't clone -- lose tx status ... */
8548c2ecf20Sopenharmony_ci		skb = orig_skb;
8558c2ecf20Sopenharmony_ci	}
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	return skb;
8588c2ecf20Sopenharmony_ci}
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci/*
8618c2ecf20Sopenharmony_ci * CFG802.11 network device handler for data transmission.
8628c2ecf20Sopenharmony_ci */
8638c2ecf20Sopenharmony_cistatic netdev_tx_t
8648c2ecf20Sopenharmony_cimwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
8658c2ecf20Sopenharmony_ci{
8668c2ecf20Sopenharmony_ci	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
8678c2ecf20Sopenharmony_ci	struct sk_buff *new_skb;
8688c2ecf20Sopenharmony_ci	struct mwifiex_txinfo *tx_info;
8698c2ecf20Sopenharmony_ci	bool multicast;
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	mwifiex_dbg(priv->adapter, DATA,
8728c2ecf20Sopenharmony_ci		    "data: %lu BSS(%d-%d): Data <= kernel\n",
8738c2ecf20Sopenharmony_ci		    jiffies, priv->bss_type, priv->bss_num);
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	if (test_bit(MWIFIEX_SURPRISE_REMOVED, &priv->adapter->work_flags)) {
8768c2ecf20Sopenharmony_ci		kfree_skb(skb);
8778c2ecf20Sopenharmony_ci		priv->stats.tx_dropped++;
8788c2ecf20Sopenharmony_ci		return 0;
8798c2ecf20Sopenharmony_ci	}
8808c2ecf20Sopenharmony_ci	if (!skb->len || (skb->len > ETH_FRAME_LEN)) {
8818c2ecf20Sopenharmony_ci		mwifiex_dbg(priv->adapter, ERROR,
8828c2ecf20Sopenharmony_ci			    "Tx: bad skb len %d\n", skb->len);
8838c2ecf20Sopenharmony_ci		kfree_skb(skb);
8848c2ecf20Sopenharmony_ci		priv->stats.tx_dropped++;
8858c2ecf20Sopenharmony_ci		return 0;
8868c2ecf20Sopenharmony_ci	}
8878c2ecf20Sopenharmony_ci	if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) {
8888c2ecf20Sopenharmony_ci		mwifiex_dbg(priv->adapter, DATA,
8898c2ecf20Sopenharmony_ci			    "data: Tx: insufficient skb headroom %d\n",
8908c2ecf20Sopenharmony_ci			    skb_headroom(skb));
8918c2ecf20Sopenharmony_ci		/* Insufficient skb headroom - allocate a new skb */
8928c2ecf20Sopenharmony_ci		new_skb =
8938c2ecf20Sopenharmony_ci			skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
8948c2ecf20Sopenharmony_ci		if (unlikely(!new_skb)) {
8958c2ecf20Sopenharmony_ci			mwifiex_dbg(priv->adapter, ERROR,
8968c2ecf20Sopenharmony_ci				    "Tx: cannot alloca new_skb\n");
8978c2ecf20Sopenharmony_ci			kfree_skb(skb);
8988c2ecf20Sopenharmony_ci			priv->stats.tx_dropped++;
8998c2ecf20Sopenharmony_ci			return 0;
9008c2ecf20Sopenharmony_ci		}
9018c2ecf20Sopenharmony_ci		kfree_skb(skb);
9028c2ecf20Sopenharmony_ci		skb = new_skb;
9038c2ecf20Sopenharmony_ci		mwifiex_dbg(priv->adapter, INFO,
9048c2ecf20Sopenharmony_ci			    "info: new skb headroomd %d\n",
9058c2ecf20Sopenharmony_ci			    skb_headroom(skb));
9068c2ecf20Sopenharmony_ci	}
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	tx_info = MWIFIEX_SKB_TXCB(skb);
9098c2ecf20Sopenharmony_ci	memset(tx_info, 0, sizeof(*tx_info));
9108c2ecf20Sopenharmony_ci	tx_info->bss_num = priv->bss_num;
9118c2ecf20Sopenharmony_ci	tx_info->bss_type = priv->bss_type;
9128c2ecf20Sopenharmony_ci	tx_info->pkt_len = skb->len;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	multicast = is_multicast_ether_addr(skb->data);
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	if (unlikely(!multicast && skb->sk &&
9178c2ecf20Sopenharmony_ci		     skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS &&
9188c2ecf20Sopenharmony_ci		     priv->adapter->fw_api_ver == MWIFIEX_FW_V15))
9198c2ecf20Sopenharmony_ci		skb = mwifiex_clone_skb_for_tx_status(priv,
9208c2ecf20Sopenharmony_ci						      skb,
9218c2ecf20Sopenharmony_ci					MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS, NULL);
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	/* Record the current time the packet was queued; used to
9248c2ecf20Sopenharmony_ci	 * determine the amount of time the packet was queued in
9258c2ecf20Sopenharmony_ci	 * the driver before it was sent to the firmware.
9268c2ecf20Sopenharmony_ci	 * The delay is then sent along with the packet to the
9278c2ecf20Sopenharmony_ci	 * firmware for aggregate delay calculation for stats and
9288c2ecf20Sopenharmony_ci	 * MSDU lifetime expiry.
9298c2ecf20Sopenharmony_ci	 */
9308c2ecf20Sopenharmony_ci	__net_timestamp(skb);
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
9338c2ecf20Sopenharmony_ci	    priv->bss_type == MWIFIEX_BSS_TYPE_STA &&
9348c2ecf20Sopenharmony_ci	    !ether_addr_equal_unaligned(priv->cfg_bssid, skb->data)) {
9358c2ecf20Sopenharmony_ci		if (priv->adapter->auto_tdls && priv->check_tdls_tx)
9368c2ecf20Sopenharmony_ci			mwifiex_tdls_check_tx(priv, skb);
9378c2ecf20Sopenharmony_ci	}
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	mwifiex_queue_tx_pkt(priv, skb);
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	return 0;
9428c2ecf20Sopenharmony_ci}
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ciint mwifiex_set_mac_address(struct mwifiex_private *priv,
9458c2ecf20Sopenharmony_ci			    struct net_device *dev, bool external,
9468c2ecf20Sopenharmony_ci			    u8 *new_mac)
9478c2ecf20Sopenharmony_ci{
9488c2ecf20Sopenharmony_ci	int ret;
9498c2ecf20Sopenharmony_ci	u64 mac_addr, old_mac_addr;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	old_mac_addr = ether_addr_to_u64(priv->curr_addr);
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	if (external) {
9548c2ecf20Sopenharmony_ci		mac_addr = ether_addr_to_u64(new_mac);
9558c2ecf20Sopenharmony_ci	} else {
9568c2ecf20Sopenharmony_ci		/* Internal mac address change */
9578c2ecf20Sopenharmony_ci		if (priv->bss_type == MWIFIEX_BSS_TYPE_ANY)
9588c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci		mac_addr = old_mac_addr;
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci		if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P) {
9638c2ecf20Sopenharmony_ci			mac_addr |= BIT_ULL(MWIFIEX_MAC_LOCAL_ADMIN_BIT);
9648c2ecf20Sopenharmony_ci			mac_addr += priv->bss_num;
9658c2ecf20Sopenharmony_ci		} else if (priv->adapter->priv[0] != priv) {
9668c2ecf20Sopenharmony_ci			/* Set mac address based on bss_type/bss_num */
9678c2ecf20Sopenharmony_ci			mac_addr ^= BIT_ULL(priv->bss_type + 8);
9688c2ecf20Sopenharmony_ci			mac_addr += priv->bss_num;
9698c2ecf20Sopenharmony_ci		}
9708c2ecf20Sopenharmony_ci	}
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	u64_to_ether_addr(mac_addr, priv->curr_addr);
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	/* Send request to firmware */
9758c2ecf20Sopenharmony_ci	ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_MAC_ADDRESS,
9768c2ecf20Sopenharmony_ci			       HostCmd_ACT_GEN_SET, 0, NULL, true);
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	if (ret) {
9798c2ecf20Sopenharmony_ci		u64_to_ether_addr(old_mac_addr, priv->curr_addr);
9808c2ecf20Sopenharmony_ci		mwifiex_dbg(priv->adapter, ERROR,
9818c2ecf20Sopenharmony_ci			    "set mac address failed: ret=%d\n", ret);
9828c2ecf20Sopenharmony_ci		return ret;
9838c2ecf20Sopenharmony_ci	}
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	ether_addr_copy(dev->dev_addr, priv->curr_addr);
9868c2ecf20Sopenharmony_ci	return 0;
9878c2ecf20Sopenharmony_ci}
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci/* CFG802.11 network device handler for setting MAC address.
9908c2ecf20Sopenharmony_ci */
9918c2ecf20Sopenharmony_cistatic int
9928c2ecf20Sopenharmony_cimwifiex_ndo_set_mac_address(struct net_device *dev, void *addr)
9938c2ecf20Sopenharmony_ci{
9948c2ecf20Sopenharmony_ci	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
9958c2ecf20Sopenharmony_ci	struct sockaddr *hw_addr = addr;
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	return mwifiex_set_mac_address(priv, dev, true, hw_addr->sa_data);
9988c2ecf20Sopenharmony_ci}
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci/*
10018c2ecf20Sopenharmony_ci * CFG802.11 network device handler for setting multicast list.
10028c2ecf20Sopenharmony_ci */
10038c2ecf20Sopenharmony_cistatic void mwifiex_set_multicast_list(struct net_device *dev)
10048c2ecf20Sopenharmony_ci{
10058c2ecf20Sopenharmony_ci	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
10068c2ecf20Sopenharmony_ci	struct mwifiex_multicast_list mcast_list;
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	if (dev->flags & IFF_PROMISC) {
10098c2ecf20Sopenharmony_ci		mcast_list.mode = MWIFIEX_PROMISC_MODE;
10108c2ecf20Sopenharmony_ci	} else if (dev->flags & IFF_ALLMULTI ||
10118c2ecf20Sopenharmony_ci		   netdev_mc_count(dev) > MWIFIEX_MAX_MULTICAST_LIST_SIZE) {
10128c2ecf20Sopenharmony_ci		mcast_list.mode = MWIFIEX_ALL_MULTI_MODE;
10138c2ecf20Sopenharmony_ci	} else {
10148c2ecf20Sopenharmony_ci		mcast_list.mode = MWIFIEX_MULTICAST_MODE;
10158c2ecf20Sopenharmony_ci		mcast_list.num_multicast_addr =
10168c2ecf20Sopenharmony_ci			mwifiex_copy_mcast_addr(&mcast_list, dev);
10178c2ecf20Sopenharmony_ci	}
10188c2ecf20Sopenharmony_ci	mwifiex_request_set_multicast_list(priv, &mcast_list);
10198c2ecf20Sopenharmony_ci}
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci/*
10228c2ecf20Sopenharmony_ci * CFG802.11 network device handler for transmission timeout.
10238c2ecf20Sopenharmony_ci */
10248c2ecf20Sopenharmony_cistatic void
10258c2ecf20Sopenharmony_cimwifiex_tx_timeout(struct net_device *dev, unsigned int txqueue)
10268c2ecf20Sopenharmony_ci{
10278c2ecf20Sopenharmony_ci	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	priv->num_tx_timeout++;
10308c2ecf20Sopenharmony_ci	priv->tx_timeout_cnt++;
10318c2ecf20Sopenharmony_ci	mwifiex_dbg(priv->adapter, ERROR,
10328c2ecf20Sopenharmony_ci		    "%lu : Tx timeout(#%d), bss_type-num = %d-%d\n",
10338c2ecf20Sopenharmony_ci		    jiffies, priv->tx_timeout_cnt, priv->bss_type,
10348c2ecf20Sopenharmony_ci		    priv->bss_num);
10358c2ecf20Sopenharmony_ci	mwifiex_set_trans_start(dev);
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	if (priv->tx_timeout_cnt > TX_TIMEOUT_THRESHOLD &&
10388c2ecf20Sopenharmony_ci	    priv->adapter->if_ops.card_reset) {
10398c2ecf20Sopenharmony_ci		mwifiex_dbg(priv->adapter, ERROR,
10408c2ecf20Sopenharmony_ci			    "tx_timeout_cnt exceeds threshold.\t"
10418c2ecf20Sopenharmony_ci			    "Triggering card reset!\n");
10428c2ecf20Sopenharmony_ci		priv->adapter->if_ops.card_reset(priv->adapter);
10438c2ecf20Sopenharmony_ci	}
10448c2ecf20Sopenharmony_ci}
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_civoid mwifiex_multi_chan_resync(struct mwifiex_adapter *adapter)
10478c2ecf20Sopenharmony_ci{
10488c2ecf20Sopenharmony_ci	struct usb_card_rec *card = adapter->card;
10498c2ecf20Sopenharmony_ci	struct mwifiex_private *priv;
10508c2ecf20Sopenharmony_ci	u16 tx_buf_size;
10518c2ecf20Sopenharmony_ci	int i, ret;
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	card->mc_resync_flag = true;
10548c2ecf20Sopenharmony_ci	for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) {
10558c2ecf20Sopenharmony_ci		if (atomic_read(&card->port[i].tx_data_urb_pending)) {
10568c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, WARN, "pending data urb in sys\n");
10578c2ecf20Sopenharmony_ci			return;
10588c2ecf20Sopenharmony_ci		}
10598c2ecf20Sopenharmony_ci	}
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	card->mc_resync_flag = false;
10628c2ecf20Sopenharmony_ci	tx_buf_size = 0xffff;
10638c2ecf20Sopenharmony_ci	priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
10648c2ecf20Sopenharmony_ci	ret = mwifiex_send_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
10658c2ecf20Sopenharmony_ci			       HostCmd_ACT_GEN_SET, 0, &tx_buf_size, false);
10668c2ecf20Sopenharmony_ci	if (ret)
10678c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
10688c2ecf20Sopenharmony_ci			    "send reconfig tx buf size cmd err\n");
10698c2ecf20Sopenharmony_ci}
10708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_multi_chan_resync);
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_civoid mwifiex_upload_device_dump(struct mwifiex_adapter *adapter)
10738c2ecf20Sopenharmony_ci{
10748c2ecf20Sopenharmony_ci	/* Dump all the memory data into single file, a userspace script will
10758c2ecf20Sopenharmony_ci	 * be used to split all the memory data to multiple files
10768c2ecf20Sopenharmony_ci	 */
10778c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, MSG,
10788c2ecf20Sopenharmony_ci		    "== mwifiex dump information to /sys/class/devcoredump start\n");
10798c2ecf20Sopenharmony_ci	dev_coredumpv(adapter->dev, adapter->devdump_data, adapter->devdump_len,
10808c2ecf20Sopenharmony_ci		      GFP_KERNEL);
10818c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, MSG,
10828c2ecf20Sopenharmony_ci		    "== mwifiex dump information to /sys/class/devcoredump end\n");
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	/* Device dump data will be freed in device coredump release function
10858c2ecf20Sopenharmony_ci	 * after 5 min. Here reset adapter->devdump_data and ->devdump_len
10868c2ecf20Sopenharmony_ci	 * to avoid it been accidentally reused.
10878c2ecf20Sopenharmony_ci	 */
10888c2ecf20Sopenharmony_ci	adapter->devdump_data = NULL;
10898c2ecf20Sopenharmony_ci	adapter->devdump_len = 0;
10908c2ecf20Sopenharmony_ci}
10918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_upload_device_dump);
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_civoid mwifiex_drv_info_dump(struct mwifiex_adapter *adapter)
10948c2ecf20Sopenharmony_ci{
10958c2ecf20Sopenharmony_ci	char *p;
10968c2ecf20Sopenharmony_ci	char drv_version[64];
10978c2ecf20Sopenharmony_ci	struct usb_card_rec *cardp;
10988c2ecf20Sopenharmony_ci	struct sdio_mmc_card *sdio_card;
10998c2ecf20Sopenharmony_ci	struct mwifiex_private *priv;
11008c2ecf20Sopenharmony_ci	int i, idx;
11018c2ecf20Sopenharmony_ci	struct netdev_queue *txq;
11028c2ecf20Sopenharmony_ci	struct mwifiex_debug_info *debug_info;
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, MSG, "===mwifiex driverinfo dump start===\n");
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	p = adapter->devdump_data;
11078c2ecf20Sopenharmony_ci	strcpy(p, "========Start dump driverinfo========\n");
11088c2ecf20Sopenharmony_ci	p += strlen("========Start dump driverinfo========\n");
11098c2ecf20Sopenharmony_ci	p += sprintf(p, "driver_name = " "\"mwifiex\"\n");
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	mwifiex_drv_get_driver_version(adapter, drv_version,
11128c2ecf20Sopenharmony_ci				       sizeof(drv_version) - 1);
11138c2ecf20Sopenharmony_ci	p += sprintf(p, "driver_version = %s\n", drv_version);
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	if (adapter->iface_type == MWIFIEX_USB) {
11168c2ecf20Sopenharmony_ci		cardp = (struct usb_card_rec *)adapter->card;
11178c2ecf20Sopenharmony_ci		p += sprintf(p, "tx_cmd_urb_pending = %d\n",
11188c2ecf20Sopenharmony_ci			     atomic_read(&cardp->tx_cmd_urb_pending));
11198c2ecf20Sopenharmony_ci		p += sprintf(p, "tx_data_urb_pending_port_0 = %d\n",
11208c2ecf20Sopenharmony_ci			     atomic_read(&cardp->port[0].tx_data_urb_pending));
11218c2ecf20Sopenharmony_ci		p += sprintf(p, "tx_data_urb_pending_port_1 = %d\n",
11228c2ecf20Sopenharmony_ci			     atomic_read(&cardp->port[1].tx_data_urb_pending));
11238c2ecf20Sopenharmony_ci		p += sprintf(p, "rx_cmd_urb_pending = %d\n",
11248c2ecf20Sopenharmony_ci			     atomic_read(&cardp->rx_cmd_urb_pending));
11258c2ecf20Sopenharmony_ci		p += sprintf(p, "rx_data_urb_pending = %d\n",
11268c2ecf20Sopenharmony_ci			     atomic_read(&cardp->rx_data_urb_pending));
11278c2ecf20Sopenharmony_ci	}
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	p += sprintf(p, "tx_pending = %d\n",
11308c2ecf20Sopenharmony_ci		     atomic_read(&adapter->tx_pending));
11318c2ecf20Sopenharmony_ci	p += sprintf(p, "rx_pending = %d\n",
11328c2ecf20Sopenharmony_ci		     atomic_read(&adapter->rx_pending));
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	if (adapter->iface_type == MWIFIEX_SDIO) {
11358c2ecf20Sopenharmony_ci		sdio_card = (struct sdio_mmc_card *)adapter->card;
11368c2ecf20Sopenharmony_ci		p += sprintf(p, "\nmp_rd_bitmap=0x%x curr_rd_port=0x%x\n",
11378c2ecf20Sopenharmony_ci			     sdio_card->mp_rd_bitmap, sdio_card->curr_rd_port);
11388c2ecf20Sopenharmony_ci		p += sprintf(p, "mp_wr_bitmap=0x%x curr_wr_port=0x%x\n",
11398c2ecf20Sopenharmony_ci			     sdio_card->mp_wr_bitmap, sdio_card->curr_wr_port);
11408c2ecf20Sopenharmony_ci	}
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci	for (i = 0; i < adapter->priv_num; i++) {
11438c2ecf20Sopenharmony_ci		if (!adapter->priv[i] || !adapter->priv[i]->netdev)
11448c2ecf20Sopenharmony_ci			continue;
11458c2ecf20Sopenharmony_ci		priv = adapter->priv[i];
11468c2ecf20Sopenharmony_ci		p += sprintf(p, "\n[interface  : \"%s\"]\n",
11478c2ecf20Sopenharmony_ci			     priv->netdev->name);
11488c2ecf20Sopenharmony_ci		p += sprintf(p, "wmm_tx_pending[0] = %d\n",
11498c2ecf20Sopenharmony_ci			     atomic_read(&priv->wmm_tx_pending[0]));
11508c2ecf20Sopenharmony_ci		p += sprintf(p, "wmm_tx_pending[1] = %d\n",
11518c2ecf20Sopenharmony_ci			     atomic_read(&priv->wmm_tx_pending[1]));
11528c2ecf20Sopenharmony_ci		p += sprintf(p, "wmm_tx_pending[2] = %d\n",
11538c2ecf20Sopenharmony_ci			     atomic_read(&priv->wmm_tx_pending[2]));
11548c2ecf20Sopenharmony_ci		p += sprintf(p, "wmm_tx_pending[3] = %d\n",
11558c2ecf20Sopenharmony_ci			     atomic_read(&priv->wmm_tx_pending[3]));
11568c2ecf20Sopenharmony_ci		p += sprintf(p, "media_state=\"%s\"\n", !priv->media_connected ?
11578c2ecf20Sopenharmony_ci			     "Disconnected" : "Connected");
11588c2ecf20Sopenharmony_ci		p += sprintf(p, "carrier %s\n", (netif_carrier_ok(priv->netdev)
11598c2ecf20Sopenharmony_ci			     ? "on" : "off"));
11608c2ecf20Sopenharmony_ci		for (idx = 0; idx < priv->netdev->num_tx_queues; idx++) {
11618c2ecf20Sopenharmony_ci			txq = netdev_get_tx_queue(priv->netdev, idx);
11628c2ecf20Sopenharmony_ci			p += sprintf(p, "tx queue %d:%s  ", idx,
11638c2ecf20Sopenharmony_ci				     netif_tx_queue_stopped(txq) ?
11648c2ecf20Sopenharmony_ci				     "stopped" : "started");
11658c2ecf20Sopenharmony_ci		}
11668c2ecf20Sopenharmony_ci		p += sprintf(p, "\n%s: num_tx_timeout = %d\n",
11678c2ecf20Sopenharmony_ci			     priv->netdev->name, priv->num_tx_timeout);
11688c2ecf20Sopenharmony_ci	}
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci	if (adapter->iface_type == MWIFIEX_SDIO ||
11718c2ecf20Sopenharmony_ci	    adapter->iface_type == MWIFIEX_PCIE) {
11728c2ecf20Sopenharmony_ci		p += sprintf(p, "\n=== %s register dump===\n",
11738c2ecf20Sopenharmony_ci			     adapter->iface_type == MWIFIEX_SDIO ?
11748c2ecf20Sopenharmony_ci							"SDIO" : "PCIE");
11758c2ecf20Sopenharmony_ci		if (adapter->if_ops.reg_dump)
11768c2ecf20Sopenharmony_ci			p += adapter->if_ops.reg_dump(adapter, p);
11778c2ecf20Sopenharmony_ci	}
11788c2ecf20Sopenharmony_ci	p += sprintf(p, "\n=== more debug information\n");
11798c2ecf20Sopenharmony_ci	debug_info = kzalloc(sizeof(*debug_info), GFP_KERNEL);
11808c2ecf20Sopenharmony_ci	if (debug_info) {
11818c2ecf20Sopenharmony_ci		for (i = 0; i < adapter->priv_num; i++) {
11828c2ecf20Sopenharmony_ci			if (!adapter->priv[i] || !adapter->priv[i]->netdev)
11838c2ecf20Sopenharmony_ci				continue;
11848c2ecf20Sopenharmony_ci			priv = adapter->priv[i];
11858c2ecf20Sopenharmony_ci			mwifiex_get_debug_info(priv, debug_info);
11868c2ecf20Sopenharmony_ci			p += mwifiex_debug_info_to_buffer(priv, p, debug_info);
11878c2ecf20Sopenharmony_ci			break;
11888c2ecf20Sopenharmony_ci		}
11898c2ecf20Sopenharmony_ci		kfree(debug_info);
11908c2ecf20Sopenharmony_ci	}
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_ci	strcpy(p, "\n========End dump========\n");
11938c2ecf20Sopenharmony_ci	p += strlen("\n========End dump========\n");
11948c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, MSG, "===mwifiex driverinfo dump end===\n");
11958c2ecf20Sopenharmony_ci	adapter->devdump_len = p - (char *)adapter->devdump_data;
11968c2ecf20Sopenharmony_ci}
11978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_drv_info_dump);
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_civoid mwifiex_prepare_fw_dump_info(struct mwifiex_adapter *adapter)
12008c2ecf20Sopenharmony_ci{
12018c2ecf20Sopenharmony_ci	u8 idx;
12028c2ecf20Sopenharmony_ci	char *fw_dump_ptr;
12038c2ecf20Sopenharmony_ci	u32 dump_len = 0;
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	for (idx = 0; idx < adapter->num_mem_types; idx++) {
12068c2ecf20Sopenharmony_ci		struct memory_type_mapping *entry =
12078c2ecf20Sopenharmony_ci				&adapter->mem_type_mapping_tbl[idx];
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci		if (entry->mem_ptr) {
12108c2ecf20Sopenharmony_ci			dump_len += (strlen("========Start dump ") +
12118c2ecf20Sopenharmony_ci					strlen(entry->mem_name) +
12128c2ecf20Sopenharmony_ci					strlen("========\n") +
12138c2ecf20Sopenharmony_ci					(entry->mem_size + 1) +
12148c2ecf20Sopenharmony_ci					strlen("\n========End dump========\n"));
12158c2ecf20Sopenharmony_ci		}
12168c2ecf20Sopenharmony_ci	}
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	if (dump_len + 1 + adapter->devdump_len > MWIFIEX_FW_DUMP_SIZE) {
12198c2ecf20Sopenharmony_ci		/* Realloc in case buffer overflow */
12208c2ecf20Sopenharmony_ci		fw_dump_ptr = vzalloc(dump_len + 1 + adapter->devdump_len);
12218c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, MSG, "Realloc device dump data.\n");
12228c2ecf20Sopenharmony_ci		if (!fw_dump_ptr) {
12238c2ecf20Sopenharmony_ci			vfree(adapter->devdump_data);
12248c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
12258c2ecf20Sopenharmony_ci				    "vzalloc devdump data failure!\n");
12268c2ecf20Sopenharmony_ci			return;
12278c2ecf20Sopenharmony_ci		}
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci		memmove(fw_dump_ptr, adapter->devdump_data,
12308c2ecf20Sopenharmony_ci			adapter->devdump_len);
12318c2ecf20Sopenharmony_ci		vfree(adapter->devdump_data);
12328c2ecf20Sopenharmony_ci		adapter->devdump_data = fw_dump_ptr;
12338c2ecf20Sopenharmony_ci	}
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci	fw_dump_ptr = (char *)adapter->devdump_data + adapter->devdump_len;
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	for (idx = 0; idx < adapter->num_mem_types; idx++) {
12388c2ecf20Sopenharmony_ci		struct memory_type_mapping *entry =
12398c2ecf20Sopenharmony_ci					&adapter->mem_type_mapping_tbl[idx];
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci		if (entry->mem_ptr) {
12428c2ecf20Sopenharmony_ci			strcpy(fw_dump_ptr, "========Start dump ");
12438c2ecf20Sopenharmony_ci			fw_dump_ptr += strlen("========Start dump ");
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci			strcpy(fw_dump_ptr, entry->mem_name);
12468c2ecf20Sopenharmony_ci			fw_dump_ptr += strlen(entry->mem_name);
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci			strcpy(fw_dump_ptr, "========\n");
12498c2ecf20Sopenharmony_ci			fw_dump_ptr += strlen("========\n");
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci			memcpy(fw_dump_ptr, entry->mem_ptr, entry->mem_size);
12528c2ecf20Sopenharmony_ci			fw_dump_ptr += entry->mem_size;
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci			strcpy(fw_dump_ptr, "\n========End dump========\n");
12558c2ecf20Sopenharmony_ci			fw_dump_ptr += strlen("\n========End dump========\n");
12568c2ecf20Sopenharmony_ci		}
12578c2ecf20Sopenharmony_ci	}
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	adapter->devdump_len = fw_dump_ptr - (char *)adapter->devdump_data;
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	for (idx = 0; idx < adapter->num_mem_types; idx++) {
12628c2ecf20Sopenharmony_ci		struct memory_type_mapping *entry =
12638c2ecf20Sopenharmony_ci			&adapter->mem_type_mapping_tbl[idx];
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci		vfree(entry->mem_ptr);
12668c2ecf20Sopenharmony_ci		entry->mem_ptr = NULL;
12678c2ecf20Sopenharmony_ci		entry->mem_size = 0;
12688c2ecf20Sopenharmony_ci	}
12698c2ecf20Sopenharmony_ci}
12708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_prepare_fw_dump_info);
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci/*
12738c2ecf20Sopenharmony_ci * CFG802.11 network device handler for statistics retrieval.
12748c2ecf20Sopenharmony_ci */
12758c2ecf20Sopenharmony_cistatic struct net_device_stats *mwifiex_get_stats(struct net_device *dev)
12768c2ecf20Sopenharmony_ci{
12778c2ecf20Sopenharmony_ci	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	return &priv->stats;
12808c2ecf20Sopenharmony_ci}
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_cistatic u16
12838c2ecf20Sopenharmony_cimwifiex_netdev_select_wmm_queue(struct net_device *dev, struct sk_buff *skb,
12848c2ecf20Sopenharmony_ci				struct net_device *sb_dev)
12858c2ecf20Sopenharmony_ci{
12868c2ecf20Sopenharmony_ci	skb->priority = cfg80211_classify8021d(skb, NULL);
12878c2ecf20Sopenharmony_ci	return mwifiex_1d_to_wmm_queue[skb->priority];
12888c2ecf20Sopenharmony_ci}
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci/* Network device handlers */
12918c2ecf20Sopenharmony_cistatic const struct net_device_ops mwifiex_netdev_ops = {
12928c2ecf20Sopenharmony_ci	.ndo_open = mwifiex_open,
12938c2ecf20Sopenharmony_ci	.ndo_stop = mwifiex_close,
12948c2ecf20Sopenharmony_ci	.ndo_start_xmit = mwifiex_hard_start_xmit,
12958c2ecf20Sopenharmony_ci	.ndo_set_mac_address = mwifiex_ndo_set_mac_address,
12968c2ecf20Sopenharmony_ci	.ndo_validate_addr = eth_validate_addr,
12978c2ecf20Sopenharmony_ci	.ndo_tx_timeout = mwifiex_tx_timeout,
12988c2ecf20Sopenharmony_ci	.ndo_get_stats = mwifiex_get_stats,
12998c2ecf20Sopenharmony_ci	.ndo_set_rx_mode = mwifiex_set_multicast_list,
13008c2ecf20Sopenharmony_ci	.ndo_select_queue = mwifiex_netdev_select_wmm_queue,
13018c2ecf20Sopenharmony_ci};
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci/*
13048c2ecf20Sopenharmony_ci * This function initializes the private structure parameters.
13058c2ecf20Sopenharmony_ci *
13068c2ecf20Sopenharmony_ci * The following wait queues are initialized -
13078c2ecf20Sopenharmony_ci *      - IOCTL wait queue
13088c2ecf20Sopenharmony_ci *      - Command wait queue
13098c2ecf20Sopenharmony_ci *      - Statistics wait queue
13108c2ecf20Sopenharmony_ci *
13118c2ecf20Sopenharmony_ci * ...and the following default parameters are set -
13128c2ecf20Sopenharmony_ci *      - Current key index     : Set to 0
13138c2ecf20Sopenharmony_ci *      - Rate index            : Set to auto
13148c2ecf20Sopenharmony_ci *      - Media connected       : Set to disconnected
13158c2ecf20Sopenharmony_ci *      - Adhoc link sensed     : Set to false
13168c2ecf20Sopenharmony_ci *      - Nick name             : Set to null
13178c2ecf20Sopenharmony_ci *      - Number of Tx timeout  : Set to 0
13188c2ecf20Sopenharmony_ci *      - Device address        : Set to current address
13198c2ecf20Sopenharmony_ci *      - Rx histogram statistc : Set to 0
13208c2ecf20Sopenharmony_ci *
13218c2ecf20Sopenharmony_ci * In addition, the CFG80211 work queue is also created.
13228c2ecf20Sopenharmony_ci */
13238c2ecf20Sopenharmony_civoid mwifiex_init_priv_params(struct mwifiex_private *priv,
13248c2ecf20Sopenharmony_ci			      struct net_device *dev)
13258c2ecf20Sopenharmony_ci{
13268c2ecf20Sopenharmony_ci	dev->netdev_ops = &mwifiex_netdev_ops;
13278c2ecf20Sopenharmony_ci	dev->needs_free_netdev = true;
13288c2ecf20Sopenharmony_ci	/* Initialize private structure */
13298c2ecf20Sopenharmony_ci	priv->current_key_index = 0;
13308c2ecf20Sopenharmony_ci	priv->media_connected = false;
13318c2ecf20Sopenharmony_ci	memset(priv->mgmt_ie, 0,
13328c2ecf20Sopenharmony_ci	       sizeof(struct mwifiex_ie) * MAX_MGMT_IE_INDEX);
13338c2ecf20Sopenharmony_ci	priv->beacon_idx = MWIFIEX_AUTO_IDX_MASK;
13348c2ecf20Sopenharmony_ci	priv->proberesp_idx = MWIFIEX_AUTO_IDX_MASK;
13358c2ecf20Sopenharmony_ci	priv->assocresp_idx = MWIFIEX_AUTO_IDX_MASK;
13368c2ecf20Sopenharmony_ci	priv->gen_idx = MWIFIEX_AUTO_IDX_MASK;
13378c2ecf20Sopenharmony_ci	priv->num_tx_timeout = 0;
13388c2ecf20Sopenharmony_ci	if (is_valid_ether_addr(dev->dev_addr))
13398c2ecf20Sopenharmony_ci		ether_addr_copy(priv->curr_addr, dev->dev_addr);
13408c2ecf20Sopenharmony_ci	else
13418c2ecf20Sopenharmony_ci		ether_addr_copy(priv->curr_addr, priv->adapter->perm_addr);
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci	if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA ||
13448c2ecf20Sopenharmony_ci	    GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
13458c2ecf20Sopenharmony_ci		priv->hist_data = kmalloc(sizeof(*priv->hist_data), GFP_KERNEL);
13468c2ecf20Sopenharmony_ci		if (priv->hist_data)
13478c2ecf20Sopenharmony_ci			mwifiex_hist_data_reset(priv);
13488c2ecf20Sopenharmony_ci	}
13498c2ecf20Sopenharmony_ci}
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci/*
13528c2ecf20Sopenharmony_ci * This function check if command is pending.
13538c2ecf20Sopenharmony_ci */
13548c2ecf20Sopenharmony_ciint is_command_pending(struct mwifiex_adapter *adapter)
13558c2ecf20Sopenharmony_ci{
13568c2ecf20Sopenharmony_ci	int is_cmd_pend_q_empty;
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	spin_lock_bh(&adapter->cmd_pending_q_lock);
13598c2ecf20Sopenharmony_ci	is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q);
13608c2ecf20Sopenharmony_ci	spin_unlock_bh(&adapter->cmd_pending_q_lock);
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci	return !is_cmd_pend_q_empty;
13638c2ecf20Sopenharmony_ci}
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci/*
13668c2ecf20Sopenharmony_ci * This is the RX work queue function.
13678c2ecf20Sopenharmony_ci *
13688c2ecf20Sopenharmony_ci * It handles the RX operations.
13698c2ecf20Sopenharmony_ci */
13708c2ecf20Sopenharmony_cistatic void mwifiex_rx_work_queue(struct work_struct *work)
13718c2ecf20Sopenharmony_ci{
13728c2ecf20Sopenharmony_ci	struct mwifiex_adapter *adapter =
13738c2ecf20Sopenharmony_ci		container_of(work, struct mwifiex_adapter, rx_work);
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	if (test_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags))
13768c2ecf20Sopenharmony_ci		return;
13778c2ecf20Sopenharmony_ci	mwifiex_process_rx(adapter);
13788c2ecf20Sopenharmony_ci}
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_ci/*
13818c2ecf20Sopenharmony_ci * This is the main work queue function.
13828c2ecf20Sopenharmony_ci *
13838c2ecf20Sopenharmony_ci * It handles the main process, which in turn handles the complete
13848c2ecf20Sopenharmony_ci * driver operations.
13858c2ecf20Sopenharmony_ci */
13868c2ecf20Sopenharmony_cistatic void mwifiex_main_work_queue(struct work_struct *work)
13878c2ecf20Sopenharmony_ci{
13888c2ecf20Sopenharmony_ci	struct mwifiex_adapter *adapter =
13898c2ecf20Sopenharmony_ci		container_of(work, struct mwifiex_adapter, main_work);
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	if (test_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags))
13928c2ecf20Sopenharmony_ci		return;
13938c2ecf20Sopenharmony_ci	mwifiex_main_process(adapter);
13948c2ecf20Sopenharmony_ci}
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci/* Common teardown code used for both device removal and reset */
13978c2ecf20Sopenharmony_cistatic void mwifiex_uninit_sw(struct mwifiex_adapter *adapter)
13988c2ecf20Sopenharmony_ci{
13998c2ecf20Sopenharmony_ci	struct mwifiex_private *priv;
14008c2ecf20Sopenharmony_ci	int i;
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	/* We can no longer handle interrupts once we start doing the teardown
14038c2ecf20Sopenharmony_ci	 * below.
14048c2ecf20Sopenharmony_ci	 */
14058c2ecf20Sopenharmony_ci	if (adapter->if_ops.disable_int)
14068c2ecf20Sopenharmony_ci		adapter->if_ops.disable_int(adapter);
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	set_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags);
14098c2ecf20Sopenharmony_ci	mwifiex_terminate_workqueue(adapter);
14108c2ecf20Sopenharmony_ci	adapter->int_status = 0;
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	/* Stop data */
14138c2ecf20Sopenharmony_ci	for (i = 0; i < adapter->priv_num; i++) {
14148c2ecf20Sopenharmony_ci		priv = adapter->priv[i];
14158c2ecf20Sopenharmony_ci		if (priv && priv->netdev) {
14168c2ecf20Sopenharmony_ci			mwifiex_stop_net_dev_queue(priv->netdev, adapter);
14178c2ecf20Sopenharmony_ci			if (netif_carrier_ok(priv->netdev))
14188c2ecf20Sopenharmony_ci				netif_carrier_off(priv->netdev);
14198c2ecf20Sopenharmony_ci			netif_device_detach(priv->netdev);
14208c2ecf20Sopenharmony_ci		}
14218c2ecf20Sopenharmony_ci	}
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, CMD, "cmd: calling mwifiex_shutdown_drv...\n");
14248c2ecf20Sopenharmony_ci	mwifiex_shutdown_drv(adapter);
14258c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, CMD, "cmd: mwifiex_shutdown_drv done\n");
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci	if (atomic_read(&adapter->rx_pending) ||
14288c2ecf20Sopenharmony_ci	    atomic_read(&adapter->tx_pending) ||
14298c2ecf20Sopenharmony_ci	    atomic_read(&adapter->cmd_pending)) {
14308c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
14318c2ecf20Sopenharmony_ci			    "rx_pending=%d, tx_pending=%d,\t"
14328c2ecf20Sopenharmony_ci			    "cmd_pending=%d\n",
14338c2ecf20Sopenharmony_ci			    atomic_read(&adapter->rx_pending),
14348c2ecf20Sopenharmony_ci			    atomic_read(&adapter->tx_pending),
14358c2ecf20Sopenharmony_ci			    atomic_read(&adapter->cmd_pending));
14368c2ecf20Sopenharmony_ci	}
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	for (i = 0; i < adapter->priv_num; i++) {
14398c2ecf20Sopenharmony_ci		priv = adapter->priv[i];
14408c2ecf20Sopenharmony_ci		if (!priv)
14418c2ecf20Sopenharmony_ci			continue;
14428c2ecf20Sopenharmony_ci		rtnl_lock();
14438c2ecf20Sopenharmony_ci		if (priv->netdev &&
14448c2ecf20Sopenharmony_ci		    priv->wdev.iftype != NL80211_IFTYPE_UNSPECIFIED)
14458c2ecf20Sopenharmony_ci			mwifiex_del_virtual_intf(adapter->wiphy, &priv->wdev);
14468c2ecf20Sopenharmony_ci		rtnl_unlock();
14478c2ecf20Sopenharmony_ci	}
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci	wiphy_unregister(adapter->wiphy);
14508c2ecf20Sopenharmony_ci	wiphy_free(adapter->wiphy);
14518c2ecf20Sopenharmony_ci	adapter->wiphy = NULL;
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci	vfree(adapter->chan_stats);
14548c2ecf20Sopenharmony_ci	mwifiex_free_cmd_buffers(adapter);
14558c2ecf20Sopenharmony_ci}
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci/*
14588c2ecf20Sopenharmony_ci * This function gets called during PCIe function level reset.
14598c2ecf20Sopenharmony_ci */
14608c2ecf20Sopenharmony_ciint mwifiex_shutdown_sw(struct mwifiex_adapter *adapter)
14618c2ecf20Sopenharmony_ci{
14628c2ecf20Sopenharmony_ci	struct mwifiex_private *priv;
14638c2ecf20Sopenharmony_ci
14648c2ecf20Sopenharmony_ci	if (!adapter)
14658c2ecf20Sopenharmony_ci		return 0;
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci	wait_for_completion(adapter->fw_done);
14688c2ecf20Sopenharmony_ci	/* Caller should ensure we aren't suspending while this happens */
14698c2ecf20Sopenharmony_ci	reinit_completion(adapter->fw_done);
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_ci	priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
14728c2ecf20Sopenharmony_ci	mwifiex_deauthenticate(priv, NULL);
14738c2ecf20Sopenharmony_ci
14748c2ecf20Sopenharmony_ci	mwifiex_init_shutdown_fw(priv, MWIFIEX_FUNC_SHUTDOWN);
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci	mwifiex_uninit_sw(adapter);
14778c2ecf20Sopenharmony_ci	adapter->is_up = false;
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_ci	if (adapter->if_ops.down_dev)
14808c2ecf20Sopenharmony_ci		adapter->if_ops.down_dev(adapter);
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	return 0;
14838c2ecf20Sopenharmony_ci}
14848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_shutdown_sw);
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_ci/* This function gets called during PCIe function level reset. Required
14878c2ecf20Sopenharmony_ci * code is extracted from mwifiex_add_card()
14888c2ecf20Sopenharmony_ci */
14898c2ecf20Sopenharmony_ciint
14908c2ecf20Sopenharmony_cimwifiex_reinit_sw(struct mwifiex_adapter *adapter)
14918c2ecf20Sopenharmony_ci{
14928c2ecf20Sopenharmony_ci	int ret;
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci	mwifiex_init_lock_list(adapter);
14958c2ecf20Sopenharmony_ci	if (adapter->if_ops.up_dev)
14968c2ecf20Sopenharmony_ci		adapter->if_ops.up_dev(adapter);
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci	adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
14998c2ecf20Sopenharmony_ci	clear_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags);
15008c2ecf20Sopenharmony_ci	init_waitqueue_head(&adapter->init_wait_q);
15018c2ecf20Sopenharmony_ci	clear_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags);
15028c2ecf20Sopenharmony_ci	adapter->hs_activated = false;
15038c2ecf20Sopenharmony_ci	clear_bit(MWIFIEX_IS_CMD_TIMEDOUT, &adapter->work_flags);
15048c2ecf20Sopenharmony_ci	init_waitqueue_head(&adapter->hs_activate_wait_q);
15058c2ecf20Sopenharmony_ci	init_waitqueue_head(&adapter->cmd_wait_q.wait);
15068c2ecf20Sopenharmony_ci	adapter->cmd_wait_q.status = 0;
15078c2ecf20Sopenharmony_ci	adapter->scan_wait_q_woken = false;
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci	if ((num_possible_cpus() > 1) || adapter->iface_type == MWIFIEX_USB)
15108c2ecf20Sopenharmony_ci		adapter->rx_work_enabled = true;
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci	adapter->workqueue =
15138c2ecf20Sopenharmony_ci		alloc_workqueue("MWIFIEX_WORK_QUEUE",
15148c2ecf20Sopenharmony_ci				WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
15158c2ecf20Sopenharmony_ci	if (!adapter->workqueue)
15168c2ecf20Sopenharmony_ci		goto err_kmalloc;
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	INIT_WORK(&adapter->main_work, mwifiex_main_work_queue);
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci	if (adapter->rx_work_enabled) {
15218c2ecf20Sopenharmony_ci		adapter->rx_workqueue = alloc_workqueue("MWIFIEX_RX_WORK_QUEUE",
15228c2ecf20Sopenharmony_ci							WQ_HIGHPRI |
15238c2ecf20Sopenharmony_ci							WQ_MEM_RECLAIM |
15248c2ecf20Sopenharmony_ci							WQ_UNBOUND, 1);
15258c2ecf20Sopenharmony_ci		if (!adapter->rx_workqueue)
15268c2ecf20Sopenharmony_ci			goto err_kmalloc;
15278c2ecf20Sopenharmony_ci		INIT_WORK(&adapter->rx_work, mwifiex_rx_work_queue);
15288c2ecf20Sopenharmony_ci	}
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci	/* Register the device. Fill up the private data structure with
15318c2ecf20Sopenharmony_ci	 * relevant information from the card. Some code extracted from
15328c2ecf20Sopenharmony_ci	 * mwifiex_register_dev()
15338c2ecf20Sopenharmony_ci	 */
15348c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, INFO, "%s, mwifiex_init_hw_fw()...\n", __func__);
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci	if (mwifiex_init_hw_fw(adapter, false)) {
15378c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
15388c2ecf20Sopenharmony_ci			    "%s: firmware init failed\n", __func__);
15398c2ecf20Sopenharmony_ci		goto err_init_fw;
15408c2ecf20Sopenharmony_ci	}
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci	/* _mwifiex_fw_dpc() does its own cleanup */
15438c2ecf20Sopenharmony_ci	ret = _mwifiex_fw_dpc(adapter->firmware, adapter);
15448c2ecf20Sopenharmony_ci	if (ret) {
15458c2ecf20Sopenharmony_ci		pr_err("Failed to bring up adapter: %d\n", ret);
15468c2ecf20Sopenharmony_ci		return ret;
15478c2ecf20Sopenharmony_ci	}
15488c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_ci	return 0;
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_cierr_init_fw:
15538c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, ERROR, "info: %s: unregister device\n", __func__);
15548c2ecf20Sopenharmony_ci	if (adapter->if_ops.unregister_dev)
15558c2ecf20Sopenharmony_ci		adapter->if_ops.unregister_dev(adapter);
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_cierr_kmalloc:
15588c2ecf20Sopenharmony_ci	set_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags);
15598c2ecf20Sopenharmony_ci	mwifiex_terminate_workqueue(adapter);
15608c2ecf20Sopenharmony_ci	if (adapter->hw_status == MWIFIEX_HW_STATUS_READY) {
15618c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
15628c2ecf20Sopenharmony_ci			    "info: %s: shutdown mwifiex\n", __func__);
15638c2ecf20Sopenharmony_ci		mwifiex_shutdown_drv(adapter);
15648c2ecf20Sopenharmony_ci		mwifiex_free_cmd_buffers(adapter);
15658c2ecf20Sopenharmony_ci	}
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci	complete_all(adapter->fw_done);
15688c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, INFO, "%s, error\n", __func__);
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci	return -1;
15718c2ecf20Sopenharmony_ci}
15728c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_reinit_sw);
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_cistatic irqreturn_t mwifiex_irq_wakeup_handler(int irq, void *priv)
15758c2ecf20Sopenharmony_ci{
15768c2ecf20Sopenharmony_ci	struct mwifiex_adapter *adapter = priv;
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci	dev_dbg(adapter->dev, "%s: wake by wifi", __func__);
15798c2ecf20Sopenharmony_ci	adapter->wake_by_wifi = true;
15808c2ecf20Sopenharmony_ci	disable_irq_nosync(irq);
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_ci	/* Notify PM core we are wakeup source */
15838c2ecf20Sopenharmony_ci	pm_wakeup_event(adapter->dev, 0);
15848c2ecf20Sopenharmony_ci	pm_system_wakeup();
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
15878c2ecf20Sopenharmony_ci}
15888c2ecf20Sopenharmony_ci
15898c2ecf20Sopenharmony_cistatic void mwifiex_probe_of(struct mwifiex_adapter *adapter)
15908c2ecf20Sopenharmony_ci{
15918c2ecf20Sopenharmony_ci	int ret;
15928c2ecf20Sopenharmony_ci	struct device *dev = adapter->dev;
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_ci	if (!dev->of_node)
15958c2ecf20Sopenharmony_ci		goto err_exit;
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	adapter->dt_node = dev->of_node;
15988c2ecf20Sopenharmony_ci	adapter->irq_wakeup = irq_of_parse_and_map(adapter->dt_node, 0);
15998c2ecf20Sopenharmony_ci	if (!adapter->irq_wakeup) {
16008c2ecf20Sopenharmony_ci		dev_dbg(dev, "fail to parse irq_wakeup from device tree\n");
16018c2ecf20Sopenharmony_ci		goto err_exit;
16028c2ecf20Sopenharmony_ci	}
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci	ret = devm_request_irq(dev, adapter->irq_wakeup,
16058c2ecf20Sopenharmony_ci			       mwifiex_irq_wakeup_handler, IRQF_TRIGGER_LOW,
16068c2ecf20Sopenharmony_ci			       "wifi_wake", adapter);
16078c2ecf20Sopenharmony_ci	if (ret) {
16088c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to request irq_wakeup %d (%d)\n",
16098c2ecf20Sopenharmony_ci			adapter->irq_wakeup, ret);
16108c2ecf20Sopenharmony_ci		goto err_exit;
16118c2ecf20Sopenharmony_ci	}
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci	disable_irq(adapter->irq_wakeup);
16148c2ecf20Sopenharmony_ci	if (device_init_wakeup(dev, true)) {
16158c2ecf20Sopenharmony_ci		dev_err(dev, "fail to init wakeup for mwifiex\n");
16168c2ecf20Sopenharmony_ci		goto err_exit;
16178c2ecf20Sopenharmony_ci	}
16188c2ecf20Sopenharmony_ci	return;
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_cierr_exit:
16218c2ecf20Sopenharmony_ci	adapter->irq_wakeup = -1;
16228c2ecf20Sopenharmony_ci}
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci/*
16258c2ecf20Sopenharmony_ci * This function adds the card.
16268c2ecf20Sopenharmony_ci *
16278c2ecf20Sopenharmony_ci * This function follows the following major steps to set up the device -
16288c2ecf20Sopenharmony_ci *      - Initialize software. This includes probing the card, registering
16298c2ecf20Sopenharmony_ci *        the interface operations table, and allocating/initializing the
16308c2ecf20Sopenharmony_ci *        adapter structure
16318c2ecf20Sopenharmony_ci *      - Set up the netlink socket
16328c2ecf20Sopenharmony_ci *      - Create and start the main work queue
16338c2ecf20Sopenharmony_ci *      - Register the device
16348c2ecf20Sopenharmony_ci *      - Initialize firmware and hardware
16358c2ecf20Sopenharmony_ci *      - Add logical interfaces
16368c2ecf20Sopenharmony_ci */
16378c2ecf20Sopenharmony_ciint
16388c2ecf20Sopenharmony_cimwifiex_add_card(void *card, struct completion *fw_done,
16398c2ecf20Sopenharmony_ci		 struct mwifiex_if_ops *if_ops, u8 iface_type,
16408c2ecf20Sopenharmony_ci		 struct device *dev)
16418c2ecf20Sopenharmony_ci{
16428c2ecf20Sopenharmony_ci	struct mwifiex_adapter *adapter;
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci	if (mwifiex_register(card, dev, if_ops, (void **)&adapter)) {
16458c2ecf20Sopenharmony_ci		pr_err("%s: software init failed\n", __func__);
16468c2ecf20Sopenharmony_ci		goto err_init_sw;
16478c2ecf20Sopenharmony_ci	}
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci	mwifiex_probe_of(adapter);
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci	adapter->iface_type = iface_type;
16528c2ecf20Sopenharmony_ci	adapter->fw_done = fw_done;
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci	adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
16558c2ecf20Sopenharmony_ci	clear_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags);
16568c2ecf20Sopenharmony_ci	init_waitqueue_head(&adapter->init_wait_q);
16578c2ecf20Sopenharmony_ci	clear_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags);
16588c2ecf20Sopenharmony_ci	adapter->hs_activated = false;
16598c2ecf20Sopenharmony_ci	init_waitqueue_head(&adapter->hs_activate_wait_q);
16608c2ecf20Sopenharmony_ci	init_waitqueue_head(&adapter->cmd_wait_q.wait);
16618c2ecf20Sopenharmony_ci	adapter->cmd_wait_q.status = 0;
16628c2ecf20Sopenharmony_ci	adapter->scan_wait_q_woken = false;
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci	if ((num_possible_cpus() > 1) || adapter->iface_type == MWIFIEX_USB)
16658c2ecf20Sopenharmony_ci		adapter->rx_work_enabled = true;
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci	adapter->workqueue =
16688c2ecf20Sopenharmony_ci		alloc_workqueue("MWIFIEX_WORK_QUEUE",
16698c2ecf20Sopenharmony_ci				WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
16708c2ecf20Sopenharmony_ci	if (!adapter->workqueue)
16718c2ecf20Sopenharmony_ci		goto err_kmalloc;
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci	INIT_WORK(&adapter->main_work, mwifiex_main_work_queue);
16748c2ecf20Sopenharmony_ci
16758c2ecf20Sopenharmony_ci	if (adapter->rx_work_enabled) {
16768c2ecf20Sopenharmony_ci		adapter->rx_workqueue = alloc_workqueue("MWIFIEX_RX_WORK_QUEUE",
16778c2ecf20Sopenharmony_ci							WQ_HIGHPRI |
16788c2ecf20Sopenharmony_ci							WQ_MEM_RECLAIM |
16798c2ecf20Sopenharmony_ci							WQ_UNBOUND, 1);
16808c2ecf20Sopenharmony_ci		if (!adapter->rx_workqueue)
16818c2ecf20Sopenharmony_ci			goto err_kmalloc;
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci		INIT_WORK(&adapter->rx_work, mwifiex_rx_work_queue);
16848c2ecf20Sopenharmony_ci	}
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	/* Register the device. Fill up the private data structure with relevant
16878c2ecf20Sopenharmony_ci	   information from the card. */
16888c2ecf20Sopenharmony_ci	if (adapter->if_ops.register_dev(adapter)) {
16898c2ecf20Sopenharmony_ci		pr_err("%s: failed to register mwifiex device\n", __func__);
16908c2ecf20Sopenharmony_ci		goto err_registerdev;
16918c2ecf20Sopenharmony_ci	}
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci	if (mwifiex_init_hw_fw(adapter, true)) {
16948c2ecf20Sopenharmony_ci		pr_err("%s: firmware init failed\n", __func__);
16958c2ecf20Sopenharmony_ci		goto err_init_fw;
16968c2ecf20Sopenharmony_ci	}
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_ci	return 0;
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_cierr_init_fw:
17018c2ecf20Sopenharmony_ci	pr_debug("info: %s: unregister device\n", __func__);
17028c2ecf20Sopenharmony_ci	if (adapter->if_ops.unregister_dev)
17038c2ecf20Sopenharmony_ci		adapter->if_ops.unregister_dev(adapter);
17048c2ecf20Sopenharmony_cierr_registerdev:
17058c2ecf20Sopenharmony_ci	set_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags);
17068c2ecf20Sopenharmony_ci	mwifiex_terminate_workqueue(adapter);
17078c2ecf20Sopenharmony_ci	if (adapter->hw_status == MWIFIEX_HW_STATUS_READY) {
17088c2ecf20Sopenharmony_ci		pr_debug("info: %s: shutdown mwifiex\n", __func__);
17098c2ecf20Sopenharmony_ci		mwifiex_shutdown_drv(adapter);
17108c2ecf20Sopenharmony_ci		mwifiex_free_cmd_buffers(adapter);
17118c2ecf20Sopenharmony_ci	}
17128c2ecf20Sopenharmony_cierr_kmalloc:
17138c2ecf20Sopenharmony_ci	if (adapter->irq_wakeup >= 0)
17148c2ecf20Sopenharmony_ci		device_init_wakeup(adapter->dev, false);
17158c2ecf20Sopenharmony_ci	mwifiex_free_adapter(adapter);
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_cierr_init_sw:
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_ci	return -1;
17208c2ecf20Sopenharmony_ci}
17218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_add_card);
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci/*
17248c2ecf20Sopenharmony_ci * This function removes the card.
17258c2ecf20Sopenharmony_ci *
17268c2ecf20Sopenharmony_ci * This function follows the following major steps to remove the device -
17278c2ecf20Sopenharmony_ci *      - Stop data traffic
17288c2ecf20Sopenharmony_ci *      - Shutdown firmware
17298c2ecf20Sopenharmony_ci *      - Remove the logical interfaces
17308c2ecf20Sopenharmony_ci *      - Terminate the work queue
17318c2ecf20Sopenharmony_ci *      - Unregister the device
17328c2ecf20Sopenharmony_ci *      - Free the adapter structure
17338c2ecf20Sopenharmony_ci */
17348c2ecf20Sopenharmony_ciint mwifiex_remove_card(struct mwifiex_adapter *adapter)
17358c2ecf20Sopenharmony_ci{
17368c2ecf20Sopenharmony_ci	if (!adapter)
17378c2ecf20Sopenharmony_ci		return 0;
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ci	if (adapter->is_up)
17408c2ecf20Sopenharmony_ci		mwifiex_uninit_sw(adapter);
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci	if (adapter->irq_wakeup >= 0)
17438c2ecf20Sopenharmony_ci		device_init_wakeup(adapter->dev, false);
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci	/* Unregister device */
17468c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, INFO,
17478c2ecf20Sopenharmony_ci		    "info: unregister device\n");
17488c2ecf20Sopenharmony_ci	if (adapter->if_ops.unregister_dev)
17498c2ecf20Sopenharmony_ci		adapter->if_ops.unregister_dev(adapter);
17508c2ecf20Sopenharmony_ci	/* Free adapter structure */
17518c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, INFO,
17528c2ecf20Sopenharmony_ci		    "info: free adapter\n");
17538c2ecf20Sopenharmony_ci	mwifiex_free_adapter(adapter);
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci	return 0;
17568c2ecf20Sopenharmony_ci}
17578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_remove_card);
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_civoid _mwifiex_dbg(const struct mwifiex_adapter *adapter, int mask,
17608c2ecf20Sopenharmony_ci		  const char *fmt, ...)
17618c2ecf20Sopenharmony_ci{
17628c2ecf20Sopenharmony_ci	struct va_format vaf;
17638c2ecf20Sopenharmony_ci	va_list args;
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ci	if (!(adapter->debug_mask & mask))
17668c2ecf20Sopenharmony_ci		return;
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci	va_start(args, fmt);
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci	vaf.fmt = fmt;
17718c2ecf20Sopenharmony_ci	vaf.va = &args;
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci	if (adapter->dev)
17748c2ecf20Sopenharmony_ci		dev_info(adapter->dev, "%pV", &vaf);
17758c2ecf20Sopenharmony_ci	else
17768c2ecf20Sopenharmony_ci		pr_info("%pV", &vaf);
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_ci	va_end(args);
17798c2ecf20Sopenharmony_ci}
17808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(_mwifiex_dbg);
17818c2ecf20Sopenharmony_ci
17828c2ecf20Sopenharmony_ci/*
17838c2ecf20Sopenharmony_ci * This function initializes the module.
17848c2ecf20Sopenharmony_ci *
17858c2ecf20Sopenharmony_ci * The debug FS is also initialized if configured.
17868c2ecf20Sopenharmony_ci */
17878c2ecf20Sopenharmony_cistatic int
17888c2ecf20Sopenharmony_cimwifiex_init_module(void)
17898c2ecf20Sopenharmony_ci{
17908c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
17918c2ecf20Sopenharmony_ci	mwifiex_debugfs_init();
17928c2ecf20Sopenharmony_ci#endif
17938c2ecf20Sopenharmony_ci	return 0;
17948c2ecf20Sopenharmony_ci}
17958c2ecf20Sopenharmony_ci
17968c2ecf20Sopenharmony_ci/*
17978c2ecf20Sopenharmony_ci * This function cleans up the module.
17988c2ecf20Sopenharmony_ci *
17998c2ecf20Sopenharmony_ci * The debug FS is removed if available.
18008c2ecf20Sopenharmony_ci */
18018c2ecf20Sopenharmony_cistatic void
18028c2ecf20Sopenharmony_cimwifiex_cleanup_module(void)
18038c2ecf20Sopenharmony_ci{
18048c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
18058c2ecf20Sopenharmony_ci	mwifiex_debugfs_remove();
18068c2ecf20Sopenharmony_ci#endif
18078c2ecf20Sopenharmony_ci}
18088c2ecf20Sopenharmony_ci
18098c2ecf20Sopenharmony_cimodule_init(mwifiex_init_module);
18108c2ecf20Sopenharmony_cimodule_exit(mwifiex_cleanup_module);
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_ciMODULE_AUTHOR("Marvell International Ltd.");
18138c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Marvell WiFi-Ex Driver version " VERSION);
18148c2ecf20Sopenharmony_ciMODULE_VERSION(VERSION);
18158c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
1816