blob: d1370d7a0a41b7d8b526aa63e35b687a31bc49c4 [file]
/*******************************************************************************
*
* This file is provided under a dual license. When you use or
* distribute this software, you may choose to be licensed under
* version 2 of the GNU General Public License ("GPLv2 License")
* or BSD License.
*
* GPLv2 License
*
* Copyright(C) 2016 MediaTek Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See http://www.gnu.org/licenses/gpl-2.0.html for more details.
*
* BSD LICENSE
*
* Copyright(C) 2016 MediaTek Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************/
/*
** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux
* /gl_init.c#11
*/
/*! \file gl_init.c
* \brief Main routines of Linux driver
*
* This file contains the main routines of Linux driver for MediaTek Inc.
* 802.11 Wireless LAN Adapters.
*/
/*******************************************************************************
* C O M P I L E R F L A G S
*******************************************************************************
*/
/*******************************************************************************
* E X T E R N A L R E F E R E N C E S
*******************************************************************************
*/
#include "gl_os.h"
#include "debug.h"
#include "wlan_lib.h"
#include "gl_wext.h"
#include "gl_cfg80211.h"
#include "precomp.h"
#if CFG_SUPPORT_AGPS_ASSIST
#include "gl_kal.h"
#endif
#include "gl_vendor.h"
#if CFG_THERMAL_API_SUPPORT
#include "mtk_ts_wmt.h"
#endif
#if CFG_POWER_OFF_CTRL_SUPPORT
#include <linux/reboot.h>
#endif
/*******************************************************************************
* C O N S T A N T S
*******************************************************************************
*/
/* #define MAX_IOREQ_NUM 10 */
struct semaphore g_halt_sem;
int g_u4HaltFlag;
struct wireless_dev *gprWdev;
#if CFG_THERMAL_API_SUPPORT
u_int8_t g_fgIsWifiEnabled = FALSE;
static int mtk_wcn_temp_query_ctrl(void);
#endif
#if IS_ENABLED(CFG_CCN7_SAP_EASYMESH)
#define NETLINK_OSS_KERNEL 25
struct sock *nl_sk;
#endif/* IS_ENABLED(CFG_CCN7_SAP_EASYMESH) */
/*******************************************************************************
* D A T A T Y P E S
*******************************************************************************
*/
/* Tasklet mechanism is like buttom-half in Linux. We just want to
* send a signal to OS for interrupt defer processing. All resources
* are NOT allowed reentry, so txPacket, ISR-DPC and ioctl must avoid preempty.
*/
struct WLANDEV_INFO {
struct net_device *prDev;
};
/*******************************************************************************
* P U B L I C D A T A
*******************************************************************************
*/
MODULE_AUTHOR(NIC_AUTHOR);
MODULE_DESCRIPTION(NIC_DESC);
#if KERNEL_VERSION(5, 12, 0) > LINUX_VERSION_CODE
MODULE_SUPPORTED_DEVICE(NIC_NAME);
#endif
/* MODULE_LICENSE("MTK Propietary"); */
MODULE_LICENSE("Dual BSD/GPL");
#ifdef CFG_DRIVER_INF_NAME_CHANGE
char *gprifnamesta = "";
char *gprifnamep2p = "";
char *gprifnameap = "";
module_param_named(sta, gprifnamesta, charp, 0000);
module_param_named(p2p, gprifnamep2p, charp, 0000);
module_param_named(ap, gprifnameap, charp, 0000);
#endif /* CFG_DRIVER_INF_NAME_CHANGE */
#if CFG_SUPPORT_CUSTOM_EEPROM_FILE
/* Get EEPROM file name from module parameter */
char *gprEepromFile = "";
module_param_named(eeprom_file, gprEepromFile, charp, 0000);
#endif
/* NIC interface name */
#define NIC_INF_NAME "wlan%d"
#ifdef CFG_DRIVER_INF_NAME_CHANGE
/* Kernel IFNAMESIZ is 16, we use 5 in case some protocol might auto gen
* interface name,
*/
/* in that case, the interface name might have risk of over kernel's IFNAMESIZ
*/
#define CUSTOM_IFNAMESIZ 5
#endif /* CFG_DRIVER_INF_NAME_CHANGE */
#if CFG_SUPPORT_SNIFFER
#define NIC_MONITOR_INF_NAME "radiotap%d"
#endif
uint8_t aucDebugModule[DBG_MODULE_NUM];
uint32_t au4LogLevel[ENUM_WIFI_LOG_MODULE_NUM] = {ENUM_WIFI_LOG_LEVEL_DEFAULT};
/* 4 2007/06/26, mikewu, now we don't use this, we just fix the number of wlan
* device to 1
*/
static struct WLANDEV_INFO
arWlanDevInfo[CFG_MAX_WLAN_DEVICES] = { {0} };
static uint32_t
u4WlanDevNum; /* How many NICs coexist now */
#if CFG_SUPPORT_CAL_RESULT_BACKUP_TO_HOST
u_int8_t g_fgIsCalDataBackuped = FALSE;
#endif
/* 20150205 added work queue for sched_scan to avoid cfg80211 stop schedule scan
* dead loack
*/
struct delayed_work sched_workq;
#if CFG_SUPPORT_CFG80211_AUTH
#if CFG_SUPPORT_CFG80211_QUEUE
struct delayed_work cfg80211_workq;
#endif
#endif
#define CFG_EEPRM_FILENAME "EEPROM"
#define FILE_NAME_MAX 64
#if (CFG_EFUSE_BUFFER_MODE_DELAY_CAL == 1)
static uint8_t *apucEepromName[] = {
(uint8_t *) CFG_EEPRM_FILENAME "_MT",
NULL
};
#endif
/* For DTV Ref project -> Default enable */
#if CFG_DC_USB_WOW_CALLBACK || CFG_POWER_OFF_CTRL_SUPPORT
/* Register DC wow callback */
int kalDcSetWow(void)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t count = 0;
uint8_t ret = 0;
if (!gprWdev) {
DBGLOG(INIT, ERROR, "gprWdev == NULL\n");
return -ENODEV;
}
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(gprWdev->wiphy);
if (!prGlueInfo) {
DBGLOG(INIT, ERROR, "prGlueInfo == NULL\n");
return -ENODEV;
}
if (!prGlueInfo->prAdapter) {
DBGLOG(INIT, ERROR, "prGlueInfo->prAdapter == NULL\n");
return -ENODEV;
}
do {
#if !CFG_ENABLE_WAKE_LOCK
/* AIS flow: disassociation if wow_en=0 */
/* cancel scan report done event */
aisPreSuspendFlow(prGlueInfo);
/* It need to add flow to deactive P2P (GC/GO) link during
* suspend flow. Otherwise, MT7668 would fail
* to enter deep sleep.
*/
p2pProcessPreSuspendFlow(prGlueInfo->prAdapter);
#endif
if (kalHaltTryLock())
break;
if (kalIsHalted()) {
kalHaltUnlock();
break;
}
if (prGlueInfo && prGlueInfo->prAdapter) {
set_bit(SUSPEND_FLAG_FOR_WAKEUP_REASON,
&prGlueInfo->prAdapter->ulSuspendFlag);
set_bit(SUSPEND_FLAG_CLEAR_WHEN_RESUME,
&prGlueInfo->prAdapter->ulSuspendFlag);
}
} while (0);
if (kalIsResetting()) {
DBGLOG(HAL, WARN, "Chip resetting, skip\n");
return -1;
}
/* Stop upper layers calling the device hard_start_xmit routine. */
netif_tx_stop_all_queues(prGlueInfo->prDevHandler);
wlanWaitCfg80211SuspendDone(prGlueInfo);
/* change to non-READY state to block cfg80211 ops */
glUsbSetState(&prGlueInfo->rHifInfo, USB_STATE_PRE_SUSPEND_START);
wlanSuspendPmHandle(prGlueInfo);
halPreSuspendCmd(prGlueInfo->prAdapter);
while (prGlueInfo->rHifInfo.state != USB_STATE_PRE_SUSPEND_DONE) {
if (count > 500) {
DBGLOG(HAL, ERROR, "pre_suspend timeout\n");
ret = -EFAULT;
break;
}
mdelay(2);
count++;
}
glUsbSetState(&prGlueInfo->rHifInfo, USB_STATE_SUSPEND);
halDisableInterrupt(prGlueInfo->prAdapter);
halTxCancelAllSending(prGlueInfo->prAdapter);
wlanReleaseAllTxCmdQueue(prGlueInfo->prAdapter);
DBGLOG(INIT, EVENT, "Wow disable suspend Wifi\n");
return ret;
}
#endif
int CFG80211_Suspend(struct wiphy *wiphy,
struct cfg80211_wowlan *wow)
{
DBGLOG(INIT, INFO, "CFG80211 suspend CB\n");
return 0;
}
int CFG80211_Resume(struct wiphy *wiphy)
{
DBGLOG(INIT, INFO, "CFG80211 resume CB\n");
return 0;
}
/*******************************************************************************
* P R I V A T E D A T A
*******************************************************************************
*/
#define CHAN2G(_channel, _freq, _flags) \
{ \
.band = KAL_BAND_2GHZ, \
.center_freq = (_freq), \
.hw_value = (_channel), \
.flags = (_flags), \
.max_antenna_gain = 0, \
.max_power = 30, \
}
static struct ieee80211_channel mtk_2ghz_channels[] = {
CHAN2G(1, 2412, 0),
CHAN2G(2, 2417, 0),
CHAN2G(3, 2422, 0),
CHAN2G(4, 2427, 0),
CHAN2G(5, 2432, 0),
CHAN2G(6, 2437, 0),
CHAN2G(7, 2442, 0),
CHAN2G(8, 2447, 0),
CHAN2G(9, 2452, 0),
CHAN2G(10, 2457, 0),
CHAN2G(11, 2462, 0),
CHAN2G(12, 2467, 0),
CHAN2G(13, 2472, 0),
CHAN2G(14, 2484, 0),
};
#define CHAN5G(_channel, _flags) \
{ \
.band = KAL_BAND_5GHZ, \
.center_freq = \
(((_channel >= 182) && (_channel <= 196)) ? \
(4000 + (5 * (_channel))) : (5000 + (5 * (_channel)))), \
.hw_value = (_channel), \
.flags = (_flags), \
.max_antenna_gain = 0, \
.max_power = 30, \
}
static struct ieee80211_channel mtk_5ghz_channels[] = {
CHAN5G(36, 0), CHAN5G(40, 0),
CHAN5G(44, 0), CHAN5G(48, 0),
CHAN5G(52, 0), CHAN5G(56, 0),
CHAN5G(60, 0), CHAN5G(64, 0),
CHAN5G(100, 0), CHAN5G(104, 0),
CHAN5G(108, 0), CHAN5G(112, 0),
CHAN5G(116, 0), CHAN5G(120, 0),
CHAN5G(124, 0), CHAN5G(128, 0),
CHAN5G(132, 0), CHAN5G(136, 0),
CHAN5G(140, 0), CHAN5G(144, 0),
CHAN5G(149, 0), CHAN5G(153, 0),
CHAN5G(157, 0), CHAN5G(161, 0),
CHAN5G(165, 0),
};
#define RATETAB_ENT(_rate, _rateid, _flags) \
{ \
.bitrate = (_rate), \
.hw_value = (_rateid), \
.flags = (_flags), \
}
/* for cfg80211 - rate table */
static struct ieee80211_rate mtk_rates[] = {
RATETAB_ENT(10, 0x1000, 0),
RATETAB_ENT(20, 0x1001, 0),
RATETAB_ENT(55, 0x1002, 0),
RATETAB_ENT(110, 0x1003, 0), /* 802.11b */
RATETAB_ENT(60, 0x2000, 0),
RATETAB_ENT(90, 0x2001, 0),
RATETAB_ENT(120, 0x2002, 0),
RATETAB_ENT(180, 0x2003, 0),
RATETAB_ENT(240, 0x2004, 0),
RATETAB_ENT(360, 0x2005, 0),
RATETAB_ENT(480, 0x2006, 0),
RATETAB_ENT(540, 0x2007, 0), /* 802.11a/g */
};
#define mtk_a_rates (mtk_rates + 4)
#define mtk_a_rates_size (ARRAY_SIZE(mtk_rates) - 4)
#define mtk_g_rates (mtk_rates + 0)
#define mtk_g_rates_size (ARRAY_SIZE(mtk_rates) - 0)
#define WLAN_MCS_INFO \
{ \
.rx_mask = {0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \
.rx_highest = 0, \
.tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
}
#define WLAN_VHT_MCS_INFO \
{ \
.rx_mcs_map = 0xFFFA, \
.rx_highest = cpu_to_le16(867), \
.tx_mcs_map = 0xFFFA, \
.tx_highest = cpu_to_le16(867), \
}
#define WLAN_HT_CAP \
{ \
.ht_supported = true, \
.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 \
| IEEE80211_HT_CAP_SM_PS \
| IEEE80211_HT_CAP_GRN_FLD \
| IEEE80211_HT_CAP_SGI_20 \
| IEEE80211_HT_CAP_SGI_40, \
.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, \
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, \
.mcs = WLAN_MCS_INFO, \
}
#define WLAN_VHT_CAP \
{ \
.vht_supported = true, \
.cap = IEEE80211_VHT_CAP_RXLDPC \
| IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK \
| IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 \
| IEEE80211_VHT_CAP_RXLDPC \
| IEEE80211_VHT_CAP_SHORT_GI_80 \
| IEEE80211_VHT_CAP_TXSTBC \
| IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE \
| IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE, \
.vht_mcs = WLAN_VHT_MCS_INFO, \
}
/* public for both Legacy Wi-Fi / P2P access */
struct ieee80211_supported_band mtk_band_2ghz = {
.band = KAL_BAND_2GHZ,
.channels = mtk_2ghz_channels,
.n_channels = ARRAY_SIZE(mtk_2ghz_channels),
.bitrates = mtk_g_rates,
.n_bitrates = mtk_g_rates_size,
.ht_cap = WLAN_HT_CAP,
};
/* public for both Legacy Wi-Fi / P2P access */
struct ieee80211_supported_band mtk_band_5ghz = {
.band = KAL_BAND_5GHZ,
.channels = mtk_5ghz_channels,
.n_channels = ARRAY_SIZE(mtk_5ghz_channels),
.bitrates = mtk_a_rates,
.n_bitrates = mtk_a_rates_size,
.ht_cap = WLAN_HT_CAP,
.vht_cap = WLAN_VHT_CAP,
};
const uint32_t mtk_cipher_suites[] = {
/* keep WEP first, it may be removed below */
WLAN_CIPHER_SUITE_WEP40,
WLAN_CIPHER_SUITE_WEP104,
WLAN_CIPHER_SUITE_TKIP,
WLAN_CIPHER_SUITE_CCMP,
/* keep last -- depends on hw flags! */
WLAN_CIPHER_SUITE_AES_CMAC,
WLAN_CIPHER_SUITE_NO_GROUP_ADDR
};
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
const uint32_t mtk_akm_suites[] = {
#if CFG_SUPPORT_802_11R
WLAN_AKM_SUITE_FT_8021X,
WLAN_AKM_SUITE_FT_PSK,
#endif
#if CFG_SUPPORT_802_11W
WLAN_AKM_SUITE_8021X_SHA256,
WLAN_AKM_SUITE_PSK_SHA256,
#endif
#if CFG_SUPPORT_OWE
WLAN_AKM_SUITE_OWE,
#endif
#if CFG_SUPPORT_DPP
WLAN_AKM_SUITE_WFA_DPP,
#endif
#if CFG_SUPPORT_CFG80211_AUTH
WLAN_AKM_SUITE_SAE,
#endif
WLAN_AKM_SUITE_8021X,
WLAN_AKM_SUITE_PSK,
WLAN_AKM_SUITE_8021X_SUITE_B
};
#endif
#if (CFG_ENABLE_UNIFY_WIPHY == 0)
static struct cfg80211_ops mtk_wlan_ops = {
.suspend = mtk_cfg80211_suspend,
.resume = mtk_cfg80211_resume,
.change_virtual_intf = mtk_cfg80211_change_iface,
.add_key = mtk_cfg80211_add_key,
.get_key = mtk_cfg80211_get_key,
.del_key = mtk_cfg80211_del_key,
.set_default_key = mtk_cfg80211_set_default_key,
.get_station = mtk_cfg80211_get_station,
#if CFG_SUPPORT_TDLS
.change_station = mtk_cfg80211_change_station,
.add_station = mtk_cfg80211_add_station,
.del_station = mtk_cfg80211_del_station,
#endif
.scan = mtk_cfg80211_scan,
#if KERNEL_VERSION(4, 5, 0) <= CFG80211_VERSION_CODE
.abort_scan = mtk_cfg80211_abort_scan,
#endif
#if !CFG_SUPPORT_CFG80211_AUTH
.connect = mtk_cfg80211_connect,
.disconnect = mtk_cfg80211_disconnect,
#endif
#if CFG_SUPPORT_CFG80211_AUTH
.deauth = mtk_cfg80211_deauth,
#endif
.join_ibss = mtk_cfg80211_join_ibss,
.leave_ibss = mtk_cfg80211_leave_ibss,
.set_power_mgmt = mtk_cfg80211_set_power_mgmt,
.set_pmksa = mtk_cfg80211_set_pmksa,
.del_pmksa = mtk_cfg80211_del_pmksa,
.flush_pmksa = mtk_cfg80211_flush_pmksa,
#if CONFIG_SUPPORT_GTK_REKEY
.set_rekey_data = mtk_cfg80211_set_rekey_data,
#endif
#if CFG_SUPPORT_CFG80211_AUTH
.auth = mtk_cfg80211_auth,
#endif
.assoc = mtk_cfg80211_assoc,
/* Action Frame TX/RX */
.remain_on_channel = mtk_cfg80211_remain_on_channel,
.cancel_remain_on_channel = mtk_cfg80211_cancel_remain_on_channel,
.mgmt_tx = mtk_cfg80211_mgmt_tx,
/* .mgmt_tx_cancel_wait = mtk_cfg80211_mgmt_tx_cancel_wait, */
#if KERNEL_VERSION(5, 8, 0) <= CFG80211_VERSION_CODE
.update_mgmt_frame_registrations = mtk_cfg_mgmt_frame_update,
#else
.mgmt_frame_register = mtk_cfg80211_mgmt_frame_register,
#endif
#ifdef CONFIG_NL80211_TESTMODE
.testmode_cmd = mtk_cfg80211_testmode_cmd,
#endif
#if CFG_SUPPORT_SCHED_SCAN
.sched_scan_start = mtk_cfg80211_sched_scan_start,
.sched_scan_stop = mtk_cfg80211_sched_scan_stop,
#endif /* CFG_SUPPORT_SCHED_SCAN */
#if CFG_SUPPORT_TDLS
.tdls_oper = mtk_cfg80211_tdls_oper,
.tdls_mgmt = mtk_cfg80211_tdls_mgmt,
#endif
.update_ft_ies = mtk_cfg80211_update_ft_ies,
};
#else /* CFG_ENABLE_UNIFY_WIPHY */
static struct cfg80211_ops mtk_cfg_ops = {
.add_virtual_intf = mtk_cfg_add_iface,
.del_virtual_intf = mtk_cfg_del_iface,
.change_virtual_intf = mtk_cfg_change_iface,
.add_key = mtk_cfg_add_key,
.get_key = mtk_cfg_get_key,
.del_key = mtk_cfg_del_key,
.set_default_mgmt_key = mtk_cfg_set_default_mgmt_key,
.set_default_key = mtk_cfg_set_default_key,
.get_station = mtk_cfg_get_station,
#if CFG_SUPPORT_TDLS
.change_station = mtk_cfg_change_station,
.add_station = mtk_cfg_add_station,
.tdls_oper = mtk_cfg_tdls_oper,
.tdls_mgmt = mtk_cfg_tdls_mgmt,
#endif
.del_station = mtk_cfg_del_station, /* AP/P2P use this function */
.scan = mtk_cfg_scan,
#if KERNEL_VERSION(4, 5, 0) <= CFG80211_VERSION_CODE
.abort_scan = mtk_cfg_abort_scan,
#endif
#if CFG_SUPPORT_SCHED_SCAN
.sched_scan_start = mtk_cfg_sched_scan_start,
.sched_scan_stop = mtk_cfg_sched_scan_stop,
#endif /* CFG_SUPPORT_SCHED_SCAN */
#if !CFG_SUPPORT_CFG80211_AUTH
.connect = mtk_cfg80211_connect,
.disconnect = mtk_cfg80211_disconnect,
#endif
#if CFG_SUPPORT_CFG80211_AUTH
.deauth = mtk_cfg_deauth,
#endif
.join_ibss = mtk_cfg_join_ibss,
.leave_ibss = mtk_cfg_leave_ibss,
.set_power_mgmt = mtk_cfg_set_power_mgmt,
.set_pmksa = mtk_cfg_set_pmksa,
.del_pmksa = mtk_cfg_del_pmksa,
.flush_pmksa = mtk_cfg_flush_pmksa,
#if CONFIG_SUPPORT_GTK_REKEY
.set_rekey_data = mtk_cfg_set_rekey_data,
#endif
.suspend = mtk_cfg_suspend,
.resume = mtk_cfg_resume,
#if CFG_SUPPORT_CFG80211_AUTH
.auth = mtk_cfg_auth,
#endif
.assoc = mtk_cfg_assoc,
/* Action Frame TX/RX */
.remain_on_channel = mtk_cfg_remain_on_channel,
.cancel_remain_on_channel = mtk_cfg_cancel_remain_on_channel,
.mgmt_tx = mtk_cfg_mgmt_tx,
/* .mgmt_tx_cancel_wait = mtk_cfg80211_mgmt_tx_cancel_wait, */
#if KERNEL_VERSION(5, 8, 0) <= CFG80211_VERSION_CODE
.update_mgmt_frame_registrations = mtk_cfg_mgmt_frame_update,
#else
.mgmt_frame_register = mtk_cfg_mgmt_frame_register,
#endif
#ifdef CONFIG_NL80211_TESTMODE
.testmode_cmd = mtk_cfg_testmode_cmd,
#endif
#if (CFG_SUPPORT_DFS_MASTER == 1)
.start_radar_detection = mtk_cfg_start_radar_detection,
#if KERNEL_VERSION(3, 13, 0) <= CFG80211_VERSION_CODE
.channel_switch = mtk_cfg_channel_switch,
#endif
#endif
#if (CFG_ENABLE_WIFI_DIRECT_CFG_80211 != 0)
.change_bss = mtk_cfg_change_bss,
.mgmt_tx_cancel_wait = mtk_cfg_mgmt_tx_cancel_wait,
.deauth = mtk_cfg_deauth,
.disassoc = mtk_cfg_disassoc,
.start_ap = mtk_cfg_start_ap,
.change_beacon = mtk_cfg_change_beacon,
.stop_ap = mtk_cfg_stop_ap,
.set_wiphy_params = mtk_cfg_set_wiphy_params,
.set_bitrate_mask = mtk_cfg_set_bitrate_mask,
#endif
.update_ft_ies = mtk_cfg80211_update_ft_ies,
};
#endif /* CFG_ENABLE_UNIFY_WIPHY */
#if KERNEL_VERSION(3, 18, 0) <= CFG80211_VERSION_CODE
static const struct wiphy_vendor_command
mtk_wlan_vendor_ops[] = {
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = WIFI_SUBCMD_GET_CHANNEL_LIST
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_get_channel_list,
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
.policy = nla_parse_wifi_attribute,
.maxattr = WIFI_ATTRIBUTE_MAX
#else
VENDOR_OPS_SET_POLICY(VENDOR_CMD_RAW_DATA)
#endif
},
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = WIFI_SUBCMD_SET_COUNTRY_CODE
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_set_country_code,
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
.policy = nla_parse_wifi_attribute,
.maxattr = WIFI_ATTRIBUTE_MAX
#else
VENDOR_OPS_SET_POLICY(VENDOR_CMD_RAW_DATA)
#endif
},
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = WIFI_SUBCMD_SET_PNO_RANDOM_MAC_OUI
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_set_scan_mac_oui,
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
.policy = nla_parse_wifi_attribute,
.maxattr = WIFI_ATTRIBUTE_MAX
#else
VENDOR_OPS_SET_POLICY(VENDOR_CMD_RAW_DATA)
#endif
},
{
{
.vendor_id = OUI_QCA,
.subcmd = QCA_NL80211_VENDOR_SUBCMD_SETBAND
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_set_band,
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
.policy = nal_parse_wifi_setband,
.maxattr = QCA_WLAN_VENDOR_ATTR_MAX
#else
VENDOR_OPS_SET_POLICY(VENDOR_CMD_RAW_DATA)
#endif
},
{
{
.vendor_id = OUI_QCA,
.subcmd = WIFI_SUBCMD_SET_ROAMING
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_set_roaming_policy,
VENDOR_OPS_SET_POLICY(VENDOR_CMD_RAW_DATA)
},
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = WIFI_SUBCMD_GET_ROAMING_CAPABILITIES
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_get_roaming_capabilities,
VENDOR_OPS_SET_POLICY(VENDOR_CMD_RAW_DATA)
},
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = WIFI_SUBCMD_CONFIG_ROAMING
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_config_roaming,
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
.policy = nla_parse_wifi_attribute,
.maxattr = WIFI_ATTRIBUTE_MAX
#else
VENDOR_OPS_SET_POLICY(VENDOR_CMD_RAW_DATA)
#endif
},
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = WIFI_SUBCMD_ENABLE_ROAMING
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_enable_roaming,
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
.policy = nla_parse_wifi_attribute,
.maxattr = WIFI_ATTRIBUTE_MAX
#else
VENDOR_OPS_SET_POLICY(VENDOR_CMD_RAW_DATA)
#endif
},
/* RTT */
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = RTT_SUBCMD_GETCAPABILITY
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_get_rtt_capabilities,
VENDOR_OPS_SET_POLICY(VENDOR_CMD_RAW_DATA)
},
/* Link Layer Statistics */
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = LSTATS_SUBCMD_GET_INFO
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_llstats_get_info,
VENDOR_OPS_SET_POLICY(VENDOR_CMD_RAW_DATA)
},
/* RSSI Monitoring */
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = WIFI_SUBCMD_SET_RSSI_MONITOR
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_set_rssi_monitoring,
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
.policy = nla_parse_wifi_rssi_monitor,
.maxattr = WIFI_ATTRIBUTE_RSSI_MONITOR_ATTRIBUTE_MAX
#else
VENDOR_OPS_SET_POLICY(VENDOR_CMD_RAW_DATA)
#endif
},
/* Packet Keep Alive */
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = WIFI_OFFLOAD_START_MKEEP_ALIVE
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_packet_keep_alive_start,
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
.policy = nla_parse_offloading_policy,
.maxattr = MKEEP_ALIVE_ATTRIBUTE_MAX
#else
VENDOR_OPS_SET_POLICY(VENDOR_CMD_RAW_DATA)
#endif
},
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = WIFI_OFFLOAD_STOP_MKEEP_ALIVE
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_packet_keep_alive_stop,
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
.policy = nla_parse_offloading_policy,
.maxattr = MKEEP_ALIVE_ATTRIBUTE_MAX
#else
VENDOR_OPS_SET_POLICY(VENDOR_CMD_RAW_DATA)
#endif
},
/* Get Driver Version or Firmware Version */
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = LOGGER_GET_VER
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_get_version,
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
.policy = nla_get_version_policy,
.maxattr = LOGGER_ATTRIBUTE_MAX
#else
VENDOR_OPS_SET_POLICY(VENDOR_CMD_RAW_DATA)
#endif
},
/* Get Supported Feature Set */
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = WIFI_SUBCMD_GET_FEATURE_SET
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_get_supported_feature_set,
VENDOR_OPS_SET_POLICY(VENDOR_CMD_RAW_DATA)
},
/* Set Tx Power Scenario */
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = WIFI_SUBCMD_SELECT_TX_POWER_SCENARIO
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_set_tx_power_scenario,
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
.policy = nla_parse_wifi_attribute,
.maxattr = WIFI_ATTRIBUTE_MAX
#else
VENDOR_OPS_SET_POLICY(VENDOR_CMD_RAW_DATA)
#endif
},
#if CFG_SUPPORT_P2P_PREFERRED_FREQ_LIST
/* P2P get preferred freq list */
{
{
.vendor_id = OUI_QCA,
.subcmd = NL80211_VENDOR_SUBCMD_GET_PREFER_FREQ_LIST
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
| WIPHY_VENDOR_CMD_NEED_RUNNING,
.doit = mtk_cfg80211_vendor_get_preferred_freq_list,
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
.policy = nla_get_preferred_freq_list_policy,
.maxattr = WIFI_VENDOR_ATTR_PREFERRED_FREQ_LIST_MAX
#else
VENDOR_OPS_SET_POLICY(VENDOR_CMD_RAW_DATA)
#endif
},
#endif /* CFG_SUPPORT_P2P_PREFERRED_FREQ_LIST */
#if CFG_AUTO_CHANNEL_SEL_SUPPORT
{
{
.vendor_id = OUI_QCA,
.subcmd = NL80211_VENDOR_SUBCMD_ACS
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
| WIPHY_VENDOR_CMD_NEED_RUNNING,
.doit = mtk_cfg80211_vendor_acs,
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
.policy = nla_get_acs_policy,
.maxattr = WIFI_VENDOR_ATTR_ACS_MAX
#else
VENDOR_OPS_SET_POLICY(VENDOR_CMD_RAW_DATA)
#endif
},
#endif
{
{
.vendor_id = OUI_QCA,
.subcmd = NL80211_VENDOR_SUBCMD_GET_FEATURES
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_get_features,
VENDOR_OPS_SET_POLICY(VENDOR_CMD_RAW_DATA)
},
{
{
.vendor_id = OUI_MTK,
.subcmd = NL80211_VENDOR_SUBCMD_GET_APF_CAPABILITIES
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_get_apf_capabilities,
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
.policy = nla_get_apf_policy,
.maxattr = APF_ATTRIBUTE_MAX
#else
VENDOR_OPS_SET_POLICY(VENDOR_CMD_RAW_DATA)
#endif
},
#if (CFG_SUPPORT_APF == 1)
{
{
.vendor_id = OUI_MTK,
.subcmd = NL80211_VENDOR_SUBCMD_SET_PACKET_FILTER
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_set_packet_filter
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
,
.policy = nla_get_apf_policy,
.maxattr = APF_ATTRIBUTE_MAX
#endif
},
{
{
.vendor_id = OUI_MTK,
.subcmd = NL80211_VENDOR_SUBCMD_READ_PACKET_FILTER
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_read_packet_filter
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
,
.policy = nla_get_apf_policy,
.maxattr = APF_ATTRIBUTE_MAX
#endif
},
#endif /* CFG_SUPPORT_APF */
};
static const struct nl80211_vendor_cmd_info
mtk_wlan_vendor_events[] = {
{
.vendor_id = GOOGLE_OUI,
.subcmd = GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS
},
{
.vendor_id = GOOGLE_OUI,
.subcmd = GSCAN_EVENT_HOTLIST_RESULTS_FOUND
},
{
.vendor_id = GOOGLE_OUI,
.subcmd = GSCAN_EVENT_SCAN_RESULTS_AVAILABLE
},
{
.vendor_id = GOOGLE_OUI,
.subcmd = GSCAN_EVENT_FULL_SCAN_RESULTS
},
{
.vendor_id = GOOGLE_OUI,
.subcmd = RTT_EVENT_COMPLETE
},
{
.vendor_id = GOOGLE_OUI,
.subcmd = GSCAN_EVENT_COMPLETE_SCAN
},
{
.vendor_id = GOOGLE_OUI,
.subcmd = GSCAN_EVENT_HOTLIST_RESULTS_LOST
},
{
.vendor_id = GOOGLE_OUI,
.subcmd = WIFI_EVENT_RSSI_MONITOR
},
{
.vendor_id = GOOGLE_OUI,
.subcmd = WIFI_EVENT_MAGIC_PACKET_RECEIVED
},
{
.vendor_id = OUI_QCA,
.subcmd = NL80211_VENDOR_SUBCMD_ACS
},
};
#endif
/* There isn't a lot of sense in it, but you can transmit anything you like */
static const struct ieee80211_txrx_stypes
mtk_cfg80211_ais_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
[NL80211_IFTYPE_ADHOC] = {
.tx = 0xffff,
.rx = BIT(IEEE80211_STYPE_ACTION >> 4)
},
[NL80211_IFTYPE_STATION] = {
.tx = 0xffff,
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
BIT(IEEE80211_STYPE_BEACON >> 4)
},
[NL80211_IFTYPE_AP] = {
.tx = 0xffff,
.rx = BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
BIT(IEEE80211_STYPE_ACTION >> 4)
},
[NL80211_IFTYPE_AP_VLAN] = {
/* copy AP */
.tx = 0xffff,
.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
BIT(IEEE80211_STYPE_DISASSOC >> 4) |
BIT(IEEE80211_STYPE_AUTH >> 4) |
BIT(IEEE80211_STYPE_DEAUTH >> 4) |
BIT(IEEE80211_STYPE_ACTION >> 4)
},
[NL80211_IFTYPE_P2P_CLIENT] = {
.tx = 0xffff,
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
},
[NL80211_IFTYPE_P2P_GO] = {
.tx = 0xffff,
.rx = BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
BIT(IEEE80211_STYPE_ACTION >> 4)
}
};
#ifdef CONFIG_PM
static const struct wiphy_wowlan_support mtk_wlan_wowlan_support = {
.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT |
WIPHY_WOWLAN_ANY,
};
#endif
#if CFG_SUPPORT_CFG80211_AUTH
/* NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES & NL80211_FEATURE_QUIET
* support in linux kernet version => 3.18
*/
#if KERNEL_VERSION(3, 18, 0) > CFG80211_VERSION_CODE
#define NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES BIT(19)
#define NL80211_FEATURE_QUIET BIT(21)
#define NL80211_FEATURE_TX_POWER_INSERTION BIT(22)
#endif
#endif
/*******************************************************************************
* M A C R O S
*******************************************************************************
*/
#define EEPROM_VERSION_CUSTOMER 0x03
/*******************************************************************************
* F U N C T I O N D E C L A R A T I O N S
*******************************************************************************
*/
/*******************************************************************************
* F U N C T I O N S
*******************************************************************************
*/
#if 0
/*----------------------------------------------------------------------------*/
/*!
* \brief Override the implementation of select queue
*
* \param[in] dev Pointer to struct net_device
* \param[in] skb Pointer to struct skb_buff
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
unsigned int _cfg80211_classify8021d(struct sk_buff *skb)
{
unsigned int dscp = 0;
/* skb->priority values from 256->263 are magic values
* directly indicate a specific 802.1d priority. This is
* to allow 802.1d priority to be passed directly in from
* tags
*/
if (skb->priority >= 256 && skb->priority <= 263)
return skb->priority - 256;
switch (skb->protocol) {
case htons(ETH_P_IP):
dscp = ip_hdr(skb)->tos & 0xfc;
break;
}
return dscp >> 5;
}
#endif
#if KERNEL_VERSION(5, 2, 0) <= LINUX_VERSION_CODE
u16 wlanSelectQueue(struct net_device *dev,
struct sk_buff *skb,
struct net_device *sb_dev)
{
return mtk_wlan_ndev_select_queue(skb);
}
#elif KERNEL_VERSION(4, 19, 0) <= LINUX_VERSION_CODE
u16 wlanSelectQueue(struct net_device *dev,
struct sk_buff *skb,
struct net_device *sb_dev, select_queue_fallback_t fallback)
{
return mtk_wlan_ndev_select_queue(skb);
}
#elif KERNEL_VERSION(3, 14, 0) <= LINUX_VERSION_CODE
u16 wlanSelectQueue(struct net_device *dev,
struct sk_buff *skb,
void *accel_priv, select_queue_fallback_t fallback)
{
return mtk_wlan_ndev_select_queue(skb);
}
#elif KERNEL_VERSION(3, 13, 0) <= LINUX_VERSION_CODE
u16 wlanSelectQueue(struct net_device *dev,
struct sk_buff *skb,
void *accel_priv)
{
return mtk_wlan_ndev_select_queue(skb);
}
#else
u16 wlanSelectQueue(struct net_device *dev,
struct sk_buff *skb)
{
return mtk_wlan_ndev_select_queue(skb);
}
#endif
/*----------------------------------------------------------------------------*/
/*!
* \brief Load NVRAM data and translate it into REG_INFO_T
*
* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T
* \param[out] prRegInfo Pointer to struct REG_INFO_T
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
static void glLoadNvram(IN struct GLUE_INFO *prGlueInfo,
OUT struct REG_INFO *prRegInfo)
{
ASSERT(prGlueInfo);
ASSERT(prRegInfo);
DBGLOG(INIT, INFO, "glLoadNvram start\n");
if ((!prGlueInfo) || (!prRegInfo))
return;
/* load full NVRAM */
prGlueInfo->fgNvramAvailable = FALSE;
if (kalCfgDataRead(prGlueInfo, 0,
sizeof(prRegInfo->aucNvram),
(uint16_t *)prRegInfo->aucNvram) == TRUE) {
struct WIFI_CFG_PARAM_STRUCT *prNvramSettings;
if (sizeof(struct WIFI_CFG_PARAM_STRUCT) >
sizeof(prRegInfo->aucNvram)) {
DBGLOG(INIT, ERROR,
"Size WIFI_CFG_PARAM_STRUCT %zu > size aucNvram %zu\n"
, sizeof(struct WIFI_CFG_PARAM_STRUCT),
sizeof(prRegInfo->aucNvram));
return;
}
#if CFG_SUPPORT_NVRAM_5G
if (sizeof(struct NEW_EFUSE_MAPPING2NVRAM) >
sizeof(prRegInfo->aucEFUSE)) {
DBGLOG(INIT, ERROR,
"Size NEW_EFUSE_MAPPING2NVRAM %zu >size aucEFUSE %zu\n"
, sizeof(struct NEW_EFUSE_MAPPING2NVRAM),
sizeof(prRegInfo->aucEFUSE));
return;
}
#endif
prRegInfo->prNvramSettings =
(struct WIFI_CFG_PARAM_STRUCT *)&prRegInfo->aucNvram;
prNvramSettings = prRegInfo->prNvramSettings;
#if CFG_SUPPORT_NVRAM_5G
/* load EFUSE overriding part */
kalMemCopy(prRegInfo->aucEFUSE,
prNvramSettings->EfuseMapping.aucEFUSE,
sizeof(prRegInfo->aucEFUSE));
prRegInfo->prOldEfuseMapping =
(struct NEW_EFUSE_MAPPING2NVRAM *)&prRegInfo->aucEFUSE;
#else
/* load EFUSE overriding part */
kalMemCopy(prRegInfo->aucEFUSE, prNvramSettings->aucEFUSE,
sizeof(prRegInfo->aucEFUSE));
#endif
/* load MAC Address */
kalMemCopy(prRegInfo->aucMacAddr,
prNvramSettings->aucMacAddress,
PARAM_MAC_ADDR_LEN * sizeof(uint8_t));
/* load country code */
/* cast to wide characters */
prRegInfo->au2CountryCode[0] =
(uint16_t) prNvramSettings->aucCountryCode[0];
prRegInfo->au2CountryCode[1] =
(uint16_t) prNvramSettings->aucCountryCode[1];
/* load default normal TX power */
kalMemCopy(&prRegInfo->rTxPwr, &prNvramSettings->rTxPwr,
sizeof(struct TX_PWR_PARAM));
/* load feature flags */
prRegInfo->ucTxPwrValid = prNvramSettings->ucTxPwrValid;
prRegInfo->ucSupport5GBand =
prNvramSettings->ucSupport5GBand;
prRegInfo->uc2G4BwFixed20M =
prNvramSettings->uc2G4BwFixed20M;
prRegInfo->uc5GBwFixed20M = prNvramSettings->uc5GBwFixed20M;
prRegInfo->ucEnable5GBand = prNvramSettings->ucEnable5GBand;
prRegInfo->ucRxDiversity = prNvramSettings->ucRxDiversity;
prRegInfo->ucRssiPathCompasationUsed =
prNvramSettings->fgRssiCompensationVaildbit;
prRegInfo->ucGpsDesense = prNvramSettings->ucGpsDesense;
/* load band edge tx power control */
prRegInfo->fg2G4BandEdgePwrUsed =
prNvramSettings->fg2G4BandEdgePwrUsed;
if (prRegInfo->prNvramSettings->fg2G4BandEdgePwrUsed) {
prRegInfo->cBandEdgeMaxPwrCCK =
prNvramSettings->cBandEdgeMaxPwrCCK;
prRegInfo->cBandEdgeMaxPwrOFDM20 =
prNvramSettings->cBandEdgeMaxPwrOFDM20;
prRegInfo->cBandEdgeMaxPwrOFDM40 =
prNvramSettings->cBandEdgeMaxPwrOFDM40;
}
/* load regulation subbands */
prRegInfo->eRegChannelListMap =
(enum ENUM_REG_CH_MAP)
prNvramSettings->ucRegChannelListMap;
prRegInfo->ucRegChannelListIndex =
prNvramSettings->ucRegChannelListIndex;
if (prRegInfo->eRegChannelListMap ==
REG_CH_MAP_CUSTOMIZED) {
kalMemCopy(prRegInfo->rDomainInfo.rSubBand,
prNvramSettings->aucRegSubbandInfo,
MAX_SUBBAND_NUM * sizeof(uint8_t));
}
/* load rssiPathCompensation */
kalMemCopy(&prRegInfo->rRssiPathCompasation,
&prNvramSettings->rRssiPathCompensation,
sizeof(struct RSSI_PATH_COMPASATION));
prGlueInfo->fgNvramAvailable = TRUE;
DBGLOG(INIT, INFO, "glLoadNvram end\n");
} else {
DBGLOG(INIT, INFO, "glLoadNvram fail\n");
}
}
/*----------------------------------------------------------------------------*/
/*!
* \brief Release prDev from wlandev_array and free tasklet object related to
* it.
*
* \param[in] prDev Pointer to struct net_device
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
static void wlanClearDevIdx(struct net_device *prDev)
{
int i;
ASSERT(prDev);
for (i = 0; i < CFG_MAX_WLAN_DEVICES; i++) {
if (arWlanDevInfo[i].prDev == prDev) {
arWlanDevInfo[i].prDev = NULL;
u4WlanDevNum--;
}
}
} /* end of wlanClearDevIdx() */
/*----------------------------------------------------------------------------*/
/*!
* \brief Allocate an unique interface index, net_device::ifindex member for
* this wlan device. Store the net_device in wlandev_array, and
* initialize tasklet object related to it.
*
* \param[in] prDev Pointer to struct net_device
*
* \retval >= 0 The device number.
* \retval -1 Fail to get index.
*/
/*----------------------------------------------------------------------------*/
static int wlanGetDevIdx(struct net_device *prDev)
{
int i;
ASSERT(prDev);
for (i = 0; i < CFG_MAX_WLAN_DEVICES; i++) {
if (arWlanDevInfo[i].prDev == (struct net_device *)NULL) {
/* Reserve 2 bytes space to store one digit of
* device number and NULL terminator.
*/
arWlanDevInfo[i].prDev = prDev;
u4WlanDevNum++;
return i;
}
}
return -1;
} /* end of wlanGetDevIdx() */
/*----------------------------------------------------------------------------*/
/*!
* \brief A method of struct net_device, a primary SOCKET interface to configure
* the interface lively. Handle an ioctl call on one of our devices.
* Everything Linux ioctl specific is done here. Then we pass the
* contents of the ifr->data to the request message handler.
*
* \param[in] prDev Linux kernel netdevice
*
* \param[in] prIFReq Our private ioctl request structure, typed for the
* generic
* struct ifreq so we can use ptr to function
*
* \param[in] cmd Command ID
*
* \retval WLAN_STATUS_SUCCESS The IOCTL command is executed successfully.
* \retval OTHER The execution of IOCTL command is failed.
*/
/*----------------------------------------------------------------------------*/
int wlanDoIOCTL(struct net_device *prDev,
struct ifreq *prIfReq, int i4Cmd)
{
struct GLUE_INFO *prGlueInfo = NULL;
int ret = 0;
/* Verify input parameters for the following functions */
ASSERT(prDev && prIfReq);
if (!prDev || !prIfReq) {
DBGLOG(INIT, ERROR, "Invalid input data\n");
return -EINVAL;
}
prGlueInfo = *((struct GLUE_INFO **) netdev_priv(prDev));
if (!prGlueInfo) {
DBGLOG(INIT, ERROR, "prGlueInfo is NULL\n");
return -EFAULT;
}
if (prGlueInfo->u4ReadyFlag == 0) {
DBGLOG(INIT, ERROR, "Adapter is not ready\n");
return -EINVAL;
}
#if defined(_HIF_USB)
if (prGlueInfo->rHifInfo.state == USB_STATE_SUSPEND) {
DBGLOG(INIT, ERROR, "usb is suspend\n");
return -EINVAL;
}
#endif
if ((i4Cmd >= SIOCIWFIRST) && (i4Cmd < SIOCIWFIRSTPRIV)) {
/* 0x8B00 ~ 0x8BDF, wireless extension region */
ret = wext_support_ioctl(prDev, prIfReq, i4Cmd);
} else if ((i4Cmd >= SIOCIWFIRSTPRIV)
&& (i4Cmd < SIOCIWLASTPRIV)) {
/* 0x8BE0 ~ 0x8BFF, private ioctl region */
ret = priv_support_ioctl(prDev, prIfReq, i4Cmd);
} else if (i4Cmd == SIOCDEVPRIVATE + 1) {
#ifdef CFG_ANDROID_AOSP_PRIV_CMD
ret = android_private_support_driver_cmd(prDev, prIfReq, i4Cmd);
#else
ret = priv_support_driver_cmd(prDev, prIfReq, i4Cmd);
#endif /* CFG_ANDROID_AOSP_PRIV_CMD */
}
#if (CFG_SUPPORT_MDNS_OFFLOAD && CFG_SUPPORT_MDNS_OFFLOAD_TV)
else if (i4Cmd == SIOCDEVPRIVATE + 2) {
/* For mDNS offload template. */
ret = priv_support_mdns_offload(prDev, prIfReq, i4Cmd);
}
#endif
else {
DBGLOG(INIT, WARN, "Unexpected ioctl command: 0x%04x\n",
i4Cmd);
ret = -EOPNOTSUPP;
}
return ret;
} /* end of wlanDoIOCTL() */
#if KERNEL_VERSION(5, 15, 0) <= CFG80211_VERSION_CODE
int wlanDoPrivIOCTL(struct net_device *prDev, struct ifreq *prIfReq,
void __user *prData, int i4Cmd) {
return wlanDoIOCTL(prDev, prIfReq, i4Cmd);
}
#endif
/*----------------------------------------------------------------------------*/
/*!
* \brief Export wlan GLUE_INFO_T pointer to p2p module
*
* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T
*
* \return TRUE: get GlueInfo pointer successfully
* FALSE: wlan is not started yet
*/
/*---------------------------------------------------------------------------*/
struct GLUE_INFO *wlanGetGlueInfo(void)
{
struct net_device *prDev = NULL;
struct GLUE_INFO *prGlueInfo = NULL;
if (u4WlanDevNum == 0)
return NULL;
prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev;
if (prDev == NULL)
return NULL;
prGlueInfo = *((struct GLUE_INFO **) netdev_priv(prDev));
return prGlueInfo;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This function is to set multicast list and set rx mode.
*
* \param[in] prDev Pointer to struct net_device
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
static struct delayed_work workq;
struct net_device *gPrDev;
static void wlanSetMulticastList(struct net_device *prDev)
{
/* Allow to receive all multicast for WOW */
DBGLOG(INIT, TRACE, "wlanSetMulticastList\n");
prDev->flags |= (IFF_MULTICAST | IFF_ALLMULTI);
gPrDev = prDev;
schedule_delayed_work(&workq, 0);
}
/* FIXME: Since we cannot sleep in the wlanSetMulticastList, we arrange
* another workqueue for sleeping. We don't want to block
* main_thread, so we can't let tx_thread to do this
*/
static void wlanSetMulticastListWorkQueue(
struct work_struct *work)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t u4PacketFilter = 0;
uint32_t u4SetInfoLen;
struct net_device *prDev = gPrDev;
down(&g_halt_sem);
if (g_u4HaltFlag) {
up(&g_halt_sem);
return;
}
prGlueInfo = (prDev != NULL) ? *((struct GLUE_INFO **)
netdev_priv(prDev)) : NULL;
ASSERT(prDev);
ASSERT(prGlueInfo);
if (!prDev || !prGlueInfo) {
DBGLOG(INIT, WARN,
"abnormal dev or skb: prDev(0x%p), prGlueInfo(0x%p)\n",
prDev, prGlueInfo);
up(&g_halt_sem);
return;
}
DBGLOG(INIT, TRACE,
"wlanSetMulticastListWorkQueue prDev->flags:0x%x\n",
prDev->flags);
if (prDev->flags & IFF_PROMISC)
u4PacketFilter |= PARAM_PACKET_FILTER_PROMISCUOUS;
if (prDev->flags & IFF_BROADCAST)
u4PacketFilter |= PARAM_PACKET_FILTER_BROADCAST;
if (prDev->flags & IFF_MULTICAST) {
if ((prDev->flags & IFF_ALLMULTI)
|| (netdev_mc_count(prDev) > MAX_NUM_GROUP_ADDR))
u4PacketFilter |= PARAM_PACKET_FILTER_ALL_MULTICAST;
else
u4PacketFilter |= PARAM_PACKET_FILTER_MULTICAST;
}
up(&g_halt_sem);
if (kalIoctl(prGlueInfo,
wlanoidSetCurrentPacketFilter,
&u4PacketFilter,
sizeof(u4PacketFilter), FALSE, FALSE, TRUE,
&u4SetInfoLen) != WLAN_STATUS_SUCCESS) {
return;
}
if (u4PacketFilter & PARAM_PACKET_FILTER_MULTICAST) {
/* Prepare multicast address list */
struct netdev_hw_addr *ha;
uint8_t *prMCAddrList = NULL;
uint32_t i = 0;
down(&g_halt_sem);
if (g_u4HaltFlag) {
up(&g_halt_sem);
return;
}
prMCAddrList = kalMemAlloc(MAX_NUM_GROUP_ADDR * ETH_ALEN,
VIR_MEM_TYPE);
if (!prMCAddrList) {
DBGLOG(INIT, WARN, "prMCAddrList memory alloc fail!\n");
return;
}
netdev_for_each_mc_addr(ha, prDev) {
if (i < MAX_NUM_GROUP_ADDR) {
kalMemCopy((prMCAddrList + i * ETH_ALEN),
GET_ADDR(ha), ETH_ALEN);
i++;
}
}
up(&g_halt_sem);
kalIoctl(prGlueInfo,
wlanoidSetMulticastList, prMCAddrList, (i * ETH_ALEN),
FALSE, FALSE, TRUE, &u4SetInfoLen);
kalMemFree(prMCAddrList, VIR_MEM_TYPE,
MAX_NUM_GROUP_ADDR * ETH_ALEN);
}
} /* end of wlanSetMulticastList() */
/*----------------------------------------------------------------------------*/
/*!
* \brief To indicate scheduled scan has been stopped
*
* \param[in]
* prGlueInfo
*
* \return
* None
*/
/*----------------------------------------------------------------------------*/
void wlanSchedScanStoppedWorkQueue(struct work_struct *work)
{
struct GLUE_INFO *prGlueInfo = NULL;
struct net_device *prDev = gPrDev;
DBGLOG(SCN, INFO, "wlanSchedScanStoppedWorkQueue\n");
prGlueInfo = (prDev != NULL) ? *((struct GLUE_INFO **)
netdev_priv(prDev)) : NULL;
if (!prGlueInfo) {
DBGLOG(SCN, INFO, "prGlueInfo == NULL unexpected\n");
return;
}
/* 2. indication to cfg80211 */
/* 20150205 change cfg80211_sched_scan_stopped to work queue due to
* sched_scan_mtx dead lock issue
*/
#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE
cfg80211_sched_scan_stopped(priv_to_wiphy(prGlueInfo), 0);
#else
cfg80211_sched_scan_stopped(priv_to_wiphy(prGlueInfo));
#endif
DBGLOG(SCN, INFO,
"cfg80211_sched_scan_stopped event send done WorkQueue thread return from wlanSchedScanStoppedWorkQueue\n");
return;
}
/* FIXME: Since we cannot sleep in the wlanSetMulticastList, we arrange
* another workqueue for sleeping. We don't want to block
* main_thread, so we can't let tx_thread to do this
*/
void p2pSetMulticastListWorkQueueWrapper(struct GLUE_INFO
*prGlueInfo)
{
ASSERT(prGlueInfo);
if (!prGlueInfo) {
DBGLOG(INIT, WARN,
"abnormal dev or skb: prGlueInfo(0x%p)\n", prGlueInfo);
return;
}
#if CFG_ENABLE_WIFI_DIRECT
if (prGlueInfo->prAdapter->fgIsP2PRegistered)
mtk_p2p_wext_set_Multicastlist(prGlueInfo);
#endif
} /* end of p2pSetMulticastListWorkQueueWrapper() */
/*----------------------------------------------------------------------------*/
/*
* \brief This function is TX entry point of NET DEVICE.
*
* \param[in] prSkb Pointer of the sk_buff to be sent
* \param[in] prDev Pointer to struct net_device
*
* \retval NETDEV_TX_OK - on success.
* \retval NETDEV_TX_BUSY - on failure, packet will be discarded by upper layer.
*/
/*----------------------------------------------------------------------------*/
netdev_tx_t wlanHardStartXmit(struct sk_buff *prSkb,
struct net_device *prDev)
{
struct NETDEV_PRIVATE_GLUE_INFO *prNetDevPrivate =
(struct NETDEV_PRIVATE_GLUE_INFO *) NULL;
struct GLUE_INFO *prGlueInfo = *((struct GLUE_INFO **)
netdev_priv(prDev));
uint8_t ucBssIndex;
ASSERT(prSkb);
ASSERT(prDev);
ASSERT(prGlueInfo);
prNetDevPrivate = (struct NETDEV_PRIVATE_GLUE_INFO *)
netdev_priv(prDev);
ASSERT(prNetDevPrivate->prGlueInfo == prGlueInfo);
ucBssIndex = prNetDevPrivate->ucBssIdx;
#if CFG_SUPPORT_PASSPOINT
if (prGlueInfo->fgIsDad) {
/* kalPrint("[Passpoint R2] Due to ipv4_dad...TX is forbidden\n"
* );
*/
dev_kfree_skb(prSkb);
return NETDEV_TX_OK;
}
if (prGlueInfo->fgIs6Dad) {
/* kalPrint("[Passpoint R2] Due to ipv6_dad...TX is forbidden\n"
* );
*/
dev_kfree_skb(prSkb);
return NETDEV_TX_OK;
}
#endif /* CFG_SUPPORT_PASSPOINT */
#if CFG_CHIP_RESET_SUPPORT
if (!wlanIsDriverReady(prGlueInfo)) {
DBGLOG(INIT, WARN,
"u4ReadyFlag:%u, kalIsResetting():%d, dropping the packet\n",
prGlueInfo->u4ReadyFlag, kalIsResetting());
dev_kfree_skb(prSkb);
return NETDEV_TX_OK;
}
#endif
kalResetPacket(prGlueInfo, (void *) prSkb);
STATS_TX_TIME_ARRIVE(prSkb);
#if (CFG_SUPPORT_TX_TSO_SW == 1)
if (kalSwTsoXmit(&prSkb, prDev, prGlueInfo, ucBssIndex)
== WLAN_STATUS_SUCCESS)
return NETDEV_TX_OK;
#endif
if (kalHardStartXmit(prSkb, prDev, prGlueInfo,
ucBssIndex) == WLAN_STATUS_SUCCESS) {
/* Successfully enqueue to Tx queue */
/* Successfully enqueue to Tx queue */
if (netif_carrier_ok(prDev))
kalPerMonStart(prGlueInfo);
}
/* For Linux, we'll always return OK FLAG, because we'll free this skb
* by ourself
*/
return NETDEV_TX_OK;
} /* end of wlanHardStartXmit() */
/*----------------------------------------------------------------------------*/
/*!
* \brief A method of struct net_device, to get the network interface
* statistical information.
*
* Whenever an application needs to get statistics for the interface, this
* method is called. This happens, for example, when ifconfig or netstat -i
* is run.
*
* \param[in] prDev Pointer to struct net_device.
*
* \return net_device_stats buffer pointer.
*/
/*----------------------------------------------------------------------------*/
struct net_device_stats *wlanGetStats(IN struct net_device
*prDev)
{
return (struct net_device_stats *)kalGetStats(prDev);
} /* end of wlanGetStats() */
void wlanDebugInit(void)
{
/* Set the initial debug level of each module */
#if DBG
/* enable all */
wlanSetDriverDbgLevel(DBG_ALL_MODULE_IDX, DBG_CLASS_MASK);
#else
#ifdef CFG_DEFAULT_DBG_LEVEL
wlanSetDriverDbgLevel(DBG_ALL_MODULE_IDX,
CFG_DEFAULT_DBG_LEVEL);
#else
wlanSetDriverDbgLevel(DBG_ALL_MODULE_IDX,
DBG_LOG_LEVEL_DEFAULT);
#endif
#endif /* DBG */
LOG_FUNC("Reset ALL DBG module log level to DEFAULT!");
}
/*----------------------------------------------------------------------------*/
/*!
* \brief A function for prDev->init
*
* \param[in] prDev Pointer to struct net_device.
*
* \retval 0 The execution of wlanInit succeeds.
* \retval -ENXIO No such device.
*/
/*----------------------------------------------------------------------------*/
static int wlanInit(struct net_device *prDev)
{
struct GLUE_INFO *prGlueInfo = NULL;
if (!prDev)
return -ENXIO;
prGlueInfo = *((struct GLUE_INFO **) netdev_priv(prDev));
INIT_DELAYED_WORK(&workq, wlanSetMulticastListWorkQueue);
/* 20150205 work queue for sched_scan */
INIT_DELAYED_WORK(&sched_workq,
wlanSchedScanStoppedWorkQueue);
/* 20161024 init wow port setting */
#if CFG_WOW_SUPPORT
kalWowInit(prGlueInfo);
#endif
return 0; /* success */
} /* end of wlanInit() */
/*----------------------------------------------------------------------------*/
/*!
* \brief A function for prDev->uninit
*
* \param[in] prDev Pointer to struct net_device.
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
static void wlanUninit(struct net_device *prDev)
{
} /* end of wlanUninit() */
/*----------------------------------------------------------------------------*/
/*!
* \brief A method of struct net_device, to set the randomized mac address
*
* This method is called before Wifi Framework requests a new conenction with
* enabled feature "Connected Random Mac".
*
* \param[in] ndev Pointer to struct net_device.
* \param[in] addr Randomized Mac address passed from WIFI framework.
*
* \return int.
*/
/*----------------------------------------------------------------------------*/
static int wlanSetMacAddress(struct net_device *ndev, void *addr)
{
struct ADAPTER *prAdapter = NULL;
struct GLUE_INFO *prGlueInfo = NULL;
struct sockaddr *sa = NULL;
/**********************************************************************
* Check if kernel passes valid data to us *
**********************************************************************
*/
if (!ndev || !addr) {
DBGLOG(INIT, ERROR, "Set macaddr with ndev(%d) and addr(%d)\n",
(ndev == NULL) ? 0 : 1, (addr == NULL) ? 0 : 1);
return WLAN_STATUS_INVALID_DATA;
}
/**********************************************************************
* 1. Change OwnMacAddr which will be updated to FW through *
* rlmActivateNetwork later. *
* 2. Change dev_addr stored in kernel to notify framework that the *
* mac addr has been changed and what the new value is. *
**********************************************************************
*/
sa = (struct sockaddr *)addr;
prGlueInfo = *((struct GLUE_INFO **) netdev_priv(ndev));
prAdapter = prGlueInfo->prAdapter;
COPY_MAC_ADDR(prAdapter->prAisBssInfo->aucOwnMacAddr, sa->sa_data);
COPY_MAC_ADDR(prGlueInfo->prDevHandler->dev_addr, sa->sa_data);
DBGLOG(INIT, INFO, "Set connect random macaddr to " MACSTR ".\n",
MAC2STR(prAdapter->prAisBssInfo->aucOwnMacAddr));
return WLAN_STATUS_SUCCESS;
} /* end of wlanSetMacAddr() */
/*----------------------------------------------------------------------------*/
/*!
* \brief A function for prDev->open
*
* \param[in] prDev Pointer to struct net_device.
*
* \retval 0 The execution of wlanOpen succeeds.
* \retval < 0 The execution of wlanOpen failed.
*/
/*----------------------------------------------------------------------------*/
static int wlanOpen(struct net_device *prDev)
{
struct GLUE_INFO *prGlueInfo = NULL;
ASSERT(prDev);
prGlueInfo = *((struct GLUE_INFO **) netdev_priv(prDev));
#if IS_ENABLED(CFG_RX_NAPI_SUPPORT)
napi_enable(&prGlueInfo->rNapi);
#endif /* CFG_RX_NAPI_SUPPORT */
netif_tx_start_all_queues(prDev);
return 0; /* success */
} /* end of wlanOpen() */
/*----------------------------------------------------------------------------*/
/*!
* \brief A function for prDev->stop
*
* \param[in] prDev Pointer to struct net_device.
*
* \retval 0 The execution of wlanStop succeeds.
* \retval < 0 The execution of wlanStop failed.
*/
/*----------------------------------------------------------------------------*/
static int wlanStop(struct net_device *prDev)
{
struct GLUE_INFO *prGlueInfo = NULL;
GLUE_SPIN_LOCK_DECLARATION();
ASSERT(prDev);
prGlueInfo = *((struct GLUE_INFO **) netdev_priv(prDev));
/* CFG80211 down */
GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV);
if (prGlueInfo->prScanRequest) {
kalCfg80211ScanDone(prGlueInfo->prScanRequest, TRUE);
prGlueInfo->prScanRequest = NULL;
}
GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV);
#if CFG_AUTO_CHANNEL_SEL_SUPPORT
/* zero clear old acs information */
kalMemZero(&(prGlueInfo->prAdapter->rWifiVar.rChnLoadInfo),
sizeof(prGlueInfo->prAdapter->rWifiVar.rChnLoadInfo));
wlanInitChnLoadInfoChannelList(prGlueInfo->prAdapter);
#endif
netif_tx_stop_all_queues(prDev);
#if IS_ENABLED(CFG_RX_NAPI_SUPPORT)
DBGLOG(RX, INFO, "RX NAPI disable ongoing %s\n", prDev->name);
napi_synchronize(&prGlueInfo->rNapi);
napi_disable(&prGlueInfo->rNapi);
if (skb_queue_len(&prGlueInfo->rRxNapiSkbQ)) {
struct sk_buff *skb;
DBGLOG(INIT, WARN, "NAPI Remain pkts %d\n",
skb_queue_len(&prGlueInfo->rRxNapiSkbQ));
while ((skb = skb_dequeue(&prGlueInfo->rRxNapiSkbQ)) != NULL)
kfree_skb(skb);
}
DBGLOG(RX, INFO, "RX NAPI disabled %s\n", prDev->name);
#endif /* CFG_RX_NAPI_SUPPORT */
return 0; /* success */
} /* end of wlanStop() */
#if CFG_SUPPORT_SNIFFER
static int wlanMonOpen(struct net_device *prDev)
{
ASSERT(prDev);
netif_tx_start_all_queues(prDev);
return 0; /* success */
}
static int wlanMonStop(struct net_device *prDev)
{
ASSERT(prDev);
netif_tx_stop_all_queues(prDev);
return 0; /* success */
}
static const struct net_device_ops wlan_mon_netdev_ops = {
.ndo_open = wlanMonOpen,
.ndo_stop = wlanMonStop,
};
void wlanMonWorkHandler(struct work_struct *work)
{
struct GLUE_INFO *prGlueInfo;
prGlueInfo = container_of(work, struct GLUE_INFO, monWork);
if (prGlueInfo->fgIsEnableMon) {
if (prGlueInfo->prMonDevHandler)
return;
#if KERNEL_VERSION(3, 18, 0) <= LINUX_VERSION_CODE
prGlueInfo->prMonDevHandler =
alloc_netdev_mq(sizeof(struct NETDEV_PRIVATE_GLUE_INFO),
NIC_MONITOR_INF_NAME,
NET_NAME_PREDICTABLE, ether_setup,
CFG_MAX_TXQ_NUM);
#else
prGlueInfo->prMonDevHandler =
alloc_netdev_mq(sizeof(struct NETDEV_PRIVATE_GLUE_INFO),
NIC_MONITOR_INF_NAME,
ether_setup, CFG_MAX_TXQ_NUM);
#endif
if (prGlueInfo->prMonDevHandler == NULL) {
DBGLOG(INIT, ERROR,
"wlanMonWorkHandler: Allocated prMonDevHandler context FAIL.\n");
return;
}
((struct NETDEV_PRIVATE_GLUE_INFO *) netdev_priv(
prGlueInfo->prMonDevHandler))->prGlueInfo = prGlueInfo;
prGlueInfo->prMonDevHandler->type =
ARPHRD_IEEE80211_RADIOTAP;
prGlueInfo->prMonDevHandler->netdev_ops =
&wlan_mon_netdev_ops;
netif_carrier_off(prGlueInfo->prMonDevHandler);
netif_tx_stop_all_queues(prGlueInfo->prMonDevHandler);
kalResetStats(prGlueInfo->prMonDevHandler);
if (register_netdev(prGlueInfo->prMonDevHandler) < 0) {
DBGLOG(INIT, ERROR,
"wlanMonWorkHandler: Registered prMonDevHandler context FAIL.\n");
free_netdev(prGlueInfo->prMonDevHandler);
prGlueInfo->prMonDevHandler = NULL;
}
DBGLOG(INIT, INFO,
"wlanMonWorkHandler: Registered prMonDevHandler context DONE.\n");
} else {
if (prGlueInfo->prMonDevHandler) {
unregister_netdev(prGlueInfo->prMonDevHandler);
prGlueInfo->prMonDevHandler = NULL;
DBGLOG(INIT, INFO,
"wlanMonWorkHandler: unRegistered prMonDevHandler context DONE.\n");
}
}
}
#endif
/*----------------------------------------------------------------------------*/
/*!
* \brief Update Channel table for cfg80211 for Wi-Fi Direct based on current
* country code
*
* \param[in] prGlueInfo Pointer to glue info
*
* \return none
*/
/*----------------------------------------------------------------------------*/
void wlanUpdateChannelTable(struct GLUE_INFO *prGlueInfo)
{
uint8_t i, j;
uint8_t ucNumOfChannel;
struct RF_CHANNEL_INFO aucChannelList[ARRAY_SIZE(
mtk_2ghz_channels) + ARRAY_SIZE(mtk_5ghz_channels)];
/* 1. Disable all channels */
for (i = 0; i < ARRAY_SIZE(mtk_2ghz_channels); i++) {
mtk_2ghz_channels[i].flags |= IEEE80211_CHAN_DISABLED;
mtk_2ghz_channels[i].orig_flags |= IEEE80211_CHAN_DISABLED;
}
for (i = 0; i < ARRAY_SIZE(mtk_5ghz_channels); i++) {
mtk_5ghz_channels[i].flags |= IEEE80211_CHAN_DISABLED;
mtk_5ghz_channels[i].orig_flags |= IEEE80211_CHAN_DISABLED;
}
/* 2. Get current domain channel list */
rlmDomainGetChnlList(prGlueInfo->prAdapter,
BAND_NULL, FALSE,
ARRAY_SIZE(mtk_2ghz_channels) + ARRAY_SIZE(
mtk_5ghz_channels),
&ucNumOfChannel, aucChannelList);
/* 3. Enable specific channel based on domain channel list */
for (i = 0; i < ucNumOfChannel; i++) {
switch (aucChannelList[i].eBand) {
case BAND_2G4:
for (j = 0; j < ARRAY_SIZE(mtk_2ghz_channels); j++) {
if (mtk_2ghz_channels[j].hw_value ==
aucChannelList[i].ucChannelNum) {
mtk_2ghz_channels[j].flags &=
~IEEE80211_CHAN_DISABLED;
mtk_2ghz_channels[j].orig_flags &=
~IEEE80211_CHAN_DISABLED;
break;
}
}
break;
case BAND_5G:
for (j = 0; j < ARRAY_SIZE(mtk_5ghz_channels); j++) {
if (mtk_5ghz_channels[j].hw_value ==
aucChannelList[i].ucChannelNum) {
mtk_5ghz_channels[j].flags &=
~IEEE80211_CHAN_DISABLED;
mtk_5ghz_channels[j].orig_flags &=
~IEEE80211_CHAN_DISABLED;
break;
}
}
break;
default:
DBGLOG(INIT, WARN, "Unknown band %d\n",
aucChannelList[i].eBand);
break;
}
}
}
/*----------------------------------------------------------------------------*/
/*!
* \brief Register the device to the kernel and return the index.
*
* \param[in] prDev Pointer to struct net_device.
*
* \retval 0 The execution of wlanNetRegister succeeds.
* \retval < 0 The execution of wlanNetRegister failed.
*/
/*----------------------------------------------------------------------------*/
static int32_t wlanNetRegister(struct wireless_dev *prWdev)
{
struct GLUE_INFO *prGlueInfo;
int32_t i4DevIdx = -1;
struct NETDEV_PRIVATE_GLUE_INFO *prNetDevPrivate =
(struct NETDEV_PRIVATE_GLUE_INFO *) NULL;
struct ADAPTER *prAdapter = NULL;
ASSERT(prWdev);
do {
if (!prWdev)
break;
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(prWdev->wiphy);
prAdapter = prGlueInfo->prAdapter;
i4DevIdx = wlanGetDevIdx(prWdev->netdev);
if (i4DevIdx < 0) {
DBGLOG(INIT, ERROR, "net_device number exceeds!\n");
break;
}
if (prAdapter && prAdapter->rWifiVar.ucWow)
kalInitDevWakeup(prGlueInfo->prAdapter,
wiphy_dev(prWdev->wiphy));
#if IS_ENABLED(CFG_RX_NAPI_SUPPORT)
#if IS_ENABLED(CFG_GRO_SUPPORT)
/* Register GRO function to kernel */
prWdev->netdev->features |= NETIF_F_GRO;
prWdev->netdev->hw_features |= NETIF_F_GRO;
#endif /* CFG_GRO_SUPPORT */
netif_napi_add(prWdev->netdev, &prGlueInfo->rNapi,
kalRxNapiPoll, NAPI_POLL_WEIGHT);
skb_queue_head_init(&prGlueInfo->rRxNapiSkbQ);
if (prGlueInfo->prAdapter->rWifiVar.ucRxNapiEnable)
kalRxNapiSetEnable(prGlueInfo, TRUE);
#endif /* CFG_RX_NAPI_SUPPORT */
#if (CFG_SUPPORT_TX_TSO_SW == 1)
prWdev->netdev->features |=
NETIF_F_TSO |
NETIF_F_TSO6 |
NETIF_F_GSO |
NETIF_F_SG;
#endif
if (register_netdev(prWdev->netdev) < 0) {
DBGLOG(INIT, ERROR, "Register net_device failed\n");
wlanClearDevIdx(prWdev->netdev);
i4DevIdx = -1;
}
#if 1
prNetDevPrivate = (struct NETDEV_PRIVATE_GLUE_INFO *)
netdev_priv(prGlueInfo->prDevHandler);
ASSERT(prNetDevPrivate->prGlueInfo == prGlueInfo);
prNetDevPrivate->ucBssIdx =
prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex;
#if CFG_ENABLE_UNIFY_WIPHY
prNetDevPrivate->ucIsP2p = FALSE;
#endif
wlanBindBssIdxToNetInterface(prGlueInfo,
prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex,
(void *) prWdev->netdev);
#else
wlanBindBssIdxToNetInterface(prGlueInfo,
prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex,
(void *) prWdev->netdev);
/* wlanBindNetInterface(prGlueInfo, NET_DEV_WLAN_IDX,
* (PVOID)prWdev->netdev);
*/
#endif
if (i4DevIdx != -1)
prGlueInfo->fgIsRegistered = TRUE;
} while (FALSE);
return i4DevIdx; /* success */
} /* end of wlanNetRegister() */
/*----------------------------------------------------------------------------*/
/*!
* \brief Unregister the device from the kernel
*
* \param[in] prWdev Pointer to struct net_device.
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
static void wlanNetUnregister(struct wireless_dev *prWdev)
{
struct GLUE_INFO *prGlueInfo;
if (!prWdev) {
DBGLOG(INIT, ERROR, "The device context is NULL\n");
return;
}
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(prWdev->wiphy);
#if IS_ENABLED(CFG_RX_NAPI_SUPPORT)
kalRxNapiSetEnable(prGlueInfo, FALSE);
netif_napi_del(&prGlueInfo->rNapi);
#endif /* CFG_RX_NAPI_SUPPORT */
wlanClearDevIdx(prWdev->netdev);
unregister_netdev(prWdev->netdev);
prGlueInfo->fgIsRegistered = FALSE;
#if CFG_SUPPORT_SNIFFER
if (prGlueInfo->prMonDevHandler) {
unregister_netdev(prGlueInfo->prMonDevHandler);
/* FIXME: Why not free_netdev()? */
prGlueInfo->prMonDevHandler = NULL;
}
prGlueInfo->fgIsEnableMon = FALSE;
#endif
} /* end of wlanNetUnregister() */
static const struct net_device_ops wlan_netdev_ops = {
.ndo_open = wlanOpen,
.ndo_stop = wlanStop,
.ndo_set_rx_mode = wlanSetMulticastList,
.ndo_get_stats = wlanGetStats,
.ndo_do_ioctl = wlanDoIOCTL,
#if KERNEL_VERSION(5, 15, 0) <= CFG80211_VERSION_CODE
.ndo_siocdevprivate = wlanDoPrivIOCTL,
#endif
.ndo_start_xmit = wlanHardStartXmit,
.ndo_init = wlanInit,
.ndo_uninit = wlanUninit,
.ndo_select_queue = wlanSelectQueue,
.ndo_set_mac_address = wlanSetMacAddress,
};
#if CFG_ENABLE_UNIFY_WIPHY
const struct net_device_ops *wlanGetNdevOps(void)
{
return &wlan_netdev_ops;
}
#endif
static void wlanCreateWirelessDevice(void)
{
struct wiphy *prWiphy = NULL;
struct wireless_dev *prWdev = NULL;
unsigned int u4SupportSchedScanFlag = 0;
/* 4 <1.1> Create wireless_dev */
prWdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
if (!prWdev) {
DBGLOG(INIT, ERROR,
"Allocating memory to wireless_dev context failed\n");
return;
}
/* 4 <1.2> Create wiphy */
#if CFG_ENABLE_UNIFY_WIPHY
prWiphy = wiphy_new(&mtk_cfg_ops, sizeof(struct GLUE_INFO));
#else
prWiphy = wiphy_new(&mtk_wlan_ops,
sizeof(struct GLUE_INFO));
#endif
if (!prWiphy) {
DBGLOG(INIT, ERROR,
"Allocating memory to wiphy device failed\n");
goto free_wdev;
}
/* 4 <1.3> configure wireless_dev & wiphy */
prWdev->iftype = NL80211_IFTYPE_STATION;
prWiphy->iface_combinations = p_mtk_iface_combinations_sta;
prWiphy->n_iface_combinations =
mtk_iface_combinations_sta_num;
prWiphy->max_scan_ssids = SCN_SSID_MAX_NUM +
1; /* include one wildcard ssid */
prWiphy->max_scan_ie_len = 512;
#if CFG_SUPPORT_SCHED_SCAN
prWiphy->max_sched_scan_ssids =
CFG_SCAN_HIDDEN_SSID_MAX_NUM;
prWiphy->max_match_sets =
CFG_SCAN_SSID_MATCH_MAX_NUM;
prWiphy->max_sched_scan_ie_len = CFG_CFG80211_IE_BUF_LEN;
#if (KERNEL_VERSION(4, 12, 0) < LINUX_VERSION_CODE)
prWiphy->max_sched_scan_reqs = 1;
#else
u4SupportSchedScanFlag =
WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
#endif
#endif /* CFG_SUPPORT_SCHED_SCAN */
prWiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
prWiphy->bands[KAL_BAND_2GHZ] = &mtk_band_2ghz;
/* always assign 5Ghz bands here, if the chip is not support 5Ghz,
* bands[KAL_BAND_5GHZ] will be assign to NULL
*/
prWiphy->bands[KAL_BAND_5GHZ] = &mtk_band_5ghz;
prWiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
prWiphy->cipher_suites = (const u32 *)mtk_cipher_suites;
prWiphy->n_cipher_suites = ARRAY_SIZE(mtk_cipher_suites);
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
prWiphy->akm_suites = (const u32 *)mtk_akm_suites;
prWiphy->n_akm_suites = ARRAY_SIZE(mtk_akm_suites);
#endif
prWiphy->flags = WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL
| u4SupportSchedScanFlag;
#if CFG_SUPPORT_802_11R && CFG_SUPPORT_CFG80211_AUTH
prWiphy->features |= NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES;
prWiphy->features |= NL80211_FEATURE_QUIET;
prWiphy->features |= NL80211_FEATURE_TX_POWER_INSERTION;
#endif /* CFG_SUPPORT_ROAMING */
#if (CFG_SUPPORT_ROAMING == 1)
prWiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
#endif /* CFG_SUPPORT_ROAMING */
#if KERNEL_VERSION(3, 14, 0) > CFG80211_VERSION_CODE
prWiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
#else
prWiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
#if (CFG_SUPPORT_DFS_MASTER == 1)
prWiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
#if KERNEL_VERSION(3, 16, 0) <= CFG80211_VERSION_CODE
prWiphy->max_num_csa_counters = 2;
#endif
#endif /* CFG_SUPPORT_DFS_MASTER */
#endif
#if (CFG_SUPPORT_SAE == 1)
prWiphy->features |= NL80211_FEATURE_SAE;
#endif /* CFG_SUPPORT_DFS_MASTER */
cfg80211_regd_set_wiphy(prWiphy);
#if (CFG_SUPPORT_TDLS == 1)
TDLSEX_WIPHY_FLAGS_INIT(prWiphy->flags);
#endif /* CFG_SUPPORT_TDLS */
prWiphy->max_remain_on_channel_duration = 5000;
prWiphy->mgmt_stypes = mtk_cfg80211_ais_default_mgmt_stypes;
#if (CFG_SUPPORT_SCAN_RANDOM_MAC && \
(KERNEL_VERSION(3, 19, 0) <= CFG80211_VERSION_CODE))
prWiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
prWiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
#endif
#if KERNEL_VERSION(3, 18, 0) <= CFG80211_VERSION_CODE
prWiphy->vendor_commands = mtk_wlan_vendor_ops;
prWiphy->n_vendor_commands = sizeof(mtk_wlan_vendor_ops) /
sizeof(struct wiphy_vendor_command);
prWiphy->vendor_events = mtk_wlan_vendor_events;
prWiphy->n_vendor_events = ARRAY_SIZE(
mtk_wlan_vendor_events);
#endif
/* 4 <1.4> wowlan support */
#ifdef CONFIG_PM
#if KERNEL_VERSION(3, 11, 0) <= CFG80211_VERSION_CODE
prWiphy->wowlan = &mtk_wlan_wowlan_support;
#else
kalMemCopy(&prWiphy->wowlan, &mtk_wlan_wowlan_support,
sizeof(struct wiphy_wowlan_support));
#endif
#endif
#ifdef CONFIG_CFG80211_WEXT
/* 4 <1.5> Use wireless extension to replace IOCTL */
#if CFG_ENABLE_UNIFY_WIPHY
prWiphy->wext = NULL;
#else
prWiphy->wext = &wext_handler_def;
#endif
#endif
/* initialize semaphore for halt control */
sema_init(&g_halt_sem, 1);
#if CFG_ENABLE_UNIFY_WIPHY
prWiphy->iface_combinations = p_mtk_iface_combinations_p2p;
prWiphy->n_iface_combinations =
mtk_iface_combinations_p2p_num;
prWiphy->interface_modes |= BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_STATION);
prWiphy->software_iftypes |= BIT(NL80211_IFTYPE_P2P_DEVICE);
prWiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
WIPHY_FLAG_HAVE_AP_SME;
prWiphy->ap_sme_capa = 1;
#endif
if (wiphy_register(prWiphy) < 0) {
DBGLOG(INIT, ERROR, "wiphy_register error\n");
goto free_wiphy;
}
prWdev->wiphy = prWiphy;
gprWdev = prWdev;
DBGLOG(INIT, INFO, "Create wireless device success\n");
return;
free_wiphy:
wiphy_free(prWiphy);
free_wdev:
kfree(prWdev);
}
/*----------------------------------------------------------------------------*/
/*!
* \brief Destroy all wdev (including the P2P device), and unregister wiphy
*
* \param (none)
*
* \return (none)
*
*/
/*----------------------------------------------------------------------------*/
static void wlanDestroyAllWdev(void)
{
#if CFG_ENABLE_UNIFY_WIPHY
/* There is only one wiphy, avoid that double free the wiphy */
struct wiphy *wiphy = NULL;
#endif
#if CFG_ENABLE_WIFI_DIRECT
int i = 0;
#endif
#if CFG_ENABLE_WIFI_DIRECT
/* free P2P wdev */
for (i = 0; i < KAL_P2P_NUM; i++) {
if (gprP2pRoleWdev[i] == NULL)
continue;
#if CFG_ENABLE_UNIFY_WIPHY
if (gprP2pRoleWdev[i] == gprWdev) {
/* This is AIS/AP Interface */
gprP2pRoleWdev[i] = NULL;
continue;
}
#endif
/* Do wiphy_unregister here. Take care the case that the
* gprP2pRoleWdev[i] is created by the cfg80211 add iface ops,
* And the base P2P dev is in the gprP2pWdev.
* Expect that new created gprP2pRoleWdev[i] is freed in
* unregister_netdev/mtk_vif_destructor. And gprP2pRoleWdev[i]
* is reset as gprP2pWdev in mtk_vif_destructor.
*/
if (gprP2pRoleWdev[i] == gprP2pWdev)
gprP2pWdev = NULL;
#if CFG_ENABLE_UNIFY_WIPHY
wiphy = gprP2pRoleWdev[i]->wiphy;
#else
set_wiphy_dev(gprP2pRoleWdev[i]->wiphy, NULL);
wiphy_unregister(gprP2pRoleWdev[i]->wiphy);
wiphy_free(gprP2pRoleWdev[i]->wiphy);
#endif
kfree(gprP2pRoleWdev[i]);
gprP2pRoleWdev[i] = NULL;
}
if (gprP2pWdev != NULL) {
/* This case is that gprP2pWdev isn't equal to gprP2pRoleWdev[0]
* . The gprP2pRoleWdev[0] is created in the p2p cfg80211 add
* iface ops. The two wdev use the same wiphy. Don't double
* free the same wiphy.
* This part isn't expect occur. Because p2pNetUnregister should
* unregister_netdev the new created wdev, and gprP2pRoleWdev[0]
* is reset as gprP2pWdev.
*/
#if CFG_ENABLE_UNIFY_WIPHY
wiphy = gprP2pWdev->wiphy;
#endif
kfree(gprP2pWdev);
gprP2pWdev = NULL;
}
#endif /* CFG_ENABLE_WIFI_DIRECT */
/* free AIS wdev */
if (gprWdev) {
#if CFG_ENABLE_UNIFY_WIPHY
wiphy = gprWdev->wiphy;
#else
/* trunk doesn't do set_wiphy_dev, but trunk-ce1 does. */
/* set_wiphy_dev(gprWdev->wiphy, NULL); */
wiphy_unregister(gprWdev->wiphy);
wiphy_free(gprWdev->wiphy);
#endif
kfree(gprWdev);
gprWdev = NULL;
}
#if CFG_ENABLE_UNIFY_WIPHY
/* unregister & free wiphy */
if (wiphy) {
/* set_wiphy_dev(wiphy, NULL): set the wiphy->dev->parent = NULL
* The trunk-ce1 does this, but the trunk seems not.
*/
/* set_wiphy_dev(wiphy, NULL); */
wiphy_unregister(wiphy);
wiphy_free(wiphy);
}
#endif
}
void wlanWakeLockInit(struct GLUE_INFO *prGlueInfo)
{
#ifdef CONFIG_ANDROID
KAL_WAKE_LOCK_INIT(NULL, prGlueInfo->prIntrWakeLock,
"WLAN interrupt");
KAL_WAKE_LOCK_INIT(NULL, prGlueInfo->prTimeoutWakeLock,
"WLAN timeout");
#endif
}
void wlanWakeLockUninit(struct GLUE_INFO *prGlueInfo)
{
#if CFG_ENABLE_WAKE_LOCK
if (KAL_WAKE_LOCK_ACTIVE(NULL, prGlueInfo->prIntrWakeLock))
KAL_WAKE_UNLOCK(NULL, prGlueInfo->prIntrWakeLock);
KAL_WAKE_LOCK_DESTROY(NULL, prGlueInfo->prIntrWakeLock);
if (KAL_WAKE_LOCK_ACTIVE(NULL,
prGlueInfo->prTimeoutWakeLock))
KAL_WAKE_UNLOCK(NULL, prGlueInfo->prTimeoutWakeLock);
KAL_WAKE_LOCK_DESTROY(NULL, prGlueInfo->prTimeoutWakeLock);
#endif
}
/*----------------------------------------------------------------------------*/
/*!
* \brief A method for creating Linux NET4 struct net_device object and the
* private data(prGlueInfo and prAdapter). Setup the IO address to the
* HIF.
* Assign the function pointer to the net_device object
*
* \param[in] pvData Memory address for the device
*
* \retval Not null The wireless_dev object.
* \retval NULL Fail to create wireless_dev object
*/
/*----------------------------------------------------------------------------*/
static struct lock_class_key rSpinKey[SPIN_LOCK_NUM];
static struct wireless_dev *wlanNetCreate(void *pvData,
void *pvDriverData)
{
struct wireless_dev *prWdev = gprWdev;
struct GLUE_INFO *prGlueInfo = NULL;
struct ADAPTER *prAdapter = NULL;
uint32_t i;
struct device *prDev;
struct NETDEV_PRIVATE_GLUE_INFO *prNetDevPrivate =
(struct NETDEV_PRIVATE_GLUE_INFO *) NULL;
struct mt66xx_chip_info *prChipInfo;
#if CFG_ENABLE_UNIFY_WIPHY
struct wiphy *prWiphy = NULL;
#endif
uint8_t *prInfName = NULL;
if (prWdev == NULL) {
DBGLOG(INIT, ERROR,
"No wireless dev exist, abort power on\n");
return NULL;
}
#if CFG_ENABLE_UNIFY_WIPHY
/* The gprWdev is created at initWlan() and isn't reset when the
* disconnection occur. That cause some issue.
*/
prWiphy = prWdev->wiphy;
memset(prWdev, 0, sizeof(struct wireless_dev));
prWdev->wiphy = prWiphy;
prWdev->iftype = NL80211_IFTYPE_STATION;
#if (CFG_SUPPORT_SINGLE_SKU == 1)
/* XXX: ref from cfg80211_regd_set_wiphy().
* The error case: Sometimes after unplug/plug usb, the wlan0 STA can't
* scan correctly (FW doesn't do scan). The usb_probe message:
* "mtk_reg_notify:(RLM ERROR) Invalid REG state happened. state = 0x6".
*/
if (rlmDomainGetCtrlState() == REGD_STATE_INVALID)
rlmDomainResetCtrlInfo(TRUE);
#endif
#endif /* CFG_ENABLE_UNIFY_WIPHY */
/* 4 <1.3> co-relate wiphy & prDev */
glGetDev(pvData, &prDev);
if (!prDev) {
DBGLOG(INIT, ERROR, "unable to get struct dev for wlan\n");
return NULL;
}
/* Some kernel API (ex: cfg80211_get_drvinfo) will use wiphy_dev().
* Without set_wiphy_dev(prWdev->wiphy, prDev), those API will crash.
*/
set_wiphy_dev(prWdev->wiphy, prDev);
/* 4 <2> Create Glue structure */
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(prWdev->wiphy);
kalMemZero(prGlueInfo, sizeof(struct GLUE_INFO));
/* 4 <2.1> Create Adapter structure */
prAdapter = (struct ADAPTER *) wlanAdapterCreate(
prGlueInfo);
if (!prAdapter) {
DBGLOG(INIT, ERROR,
"Allocating memory to adapter failed\n");
glClearHifInfo(prGlueInfo);
goto netcreate_err;
}
prChipInfo = ((struct mt66xx_hif_driver_data *)
pvDriverData)->chip_info;
prAdapter->chip_info = prChipInfo;
prGlueInfo->prAdapter = prAdapter;
/* 4 <3> Initialize Glue structure */
/* 4 <3.1> Create net device */
#ifdef CFG_DRIVER_INF_NAME_CHANGE
if (kalStrLen(gprifnamesta) > 0) {
if (kalStrStr(gprifnamesta, "%d"))
prInfName = gprifnamesta;
else
prInfName = kalStrCat(gprifnamesta, "%d");
DBGLOG(INIT, WARN, "Station ifname customized, use %s\n",
prInfName);
} else
#endif /* CFG_DRIVER_INF_NAME_CHANGE */
prInfName = NIC_INF_NAME;
#if KERNEL_VERSION(3, 18, 0) <= LINUX_VERSION_CODE
prGlueInfo->prDevHandler =
alloc_netdev_mq(sizeof(struct NETDEV_PRIVATE_GLUE_INFO),
prInfName, NET_NAME_PREDICTABLE, ether_setup,
CFG_MAX_TXQ_NUM);
#else
prGlueInfo->prDevHandler =
alloc_netdev_mq(sizeof(struct NETDEV_PRIVATE_GLUE_INFO),
prInfName,
ether_setup, CFG_MAX_TXQ_NUM);
#endif
if (!prGlueInfo->prDevHandler) {
DBGLOG(INIT, ERROR,
"Allocating memory to net_device context failed\n");
goto netcreate_err;
}
DBGLOG(INIT, INFO, "net_device prDev(0x%p) allocated\n",
prGlueInfo->prDevHandler);
/* Device can help us to save at most 3000 packets, after we stopped
** queue
*/
prGlueInfo->prDevHandler->tx_queue_len = 3000;
/* 4 <3.1.1> Initialize net device varaiables */
#if 1
prNetDevPrivate = (struct NETDEV_PRIVATE_GLUE_INFO *)
netdev_priv(prGlueInfo->prDevHandler);
prNetDevPrivate->prGlueInfo = prGlueInfo;
#else
*((struct GLUE_INFO **) netdev_priv(
prGlueInfo->prDevHandler)) = prGlueInfo;
#endif
prGlueInfo->prDevHandler->needed_headroom +=
NIC_TX_HEAD_ROOM;
/*
NIC_TX_DESC_AND_PADDING_LENGTH +
prChipInfo->txd_append_size;
*/
prGlueInfo->prDevHandler->netdev_ops = &wlan_netdev_ops;
#ifdef CONFIG_WIRELESS_EXT
prGlueInfo->prDevHandler->wireless_handlers =
&wext_handler_def;
#endif
netif_carrier_off(prGlueInfo->prDevHandler);
netif_tx_stop_all_queues(prGlueInfo->prDevHandler);
kalResetStats(prGlueInfo->prDevHandler);
#if CFG_SUPPORT_SNIFFER
INIT_WORK(&(prGlueInfo->monWork), wlanMonWorkHandler);
#endif
/* 4 <3.1.2> co-relate with wiphy bi-directionally */
prGlueInfo->prDevHandler->ieee80211_ptr = prWdev;
prWdev->netdev = prGlueInfo->prDevHandler;
/* 4 <3.1.3> co-relate net device & prDev */
SET_NETDEV_DEV(prGlueInfo->prDevHandler,
wiphy_dev(prWdev->wiphy));
/* 4 <3.1.4> set device to glue */
prGlueInfo->prDev = prDev;
/* 4 <3.2> Initialize glue variables */
prGlueInfo->eParamMediaStateIndicated =
PARAM_MEDIA_STATE_DISCONNECTED;
prGlueInfo->ePowerState = ParamDeviceStateD0;
prGlueInfo->fgIsRegistered = FALSE;
prGlueInfo->prScanRequest = NULL;
prGlueInfo->prSchedScanRequest = NULL;
#if CFG_SUPPORT_PASSPOINT
/* Init DAD */
prGlueInfo->fgIsDad = FALSE;
prGlueInfo->fgIs6Dad = FALSE;
kalMemZero(prGlueInfo->aucDADipv4, 4);
kalMemZero(prGlueInfo->aucDADipv6, 16);
#endif /* CFG_SUPPORT_PASSPOINT */
init_completion(&prGlueInfo->rScanComp);
init_completion(&prGlueInfo->rHaltComp);
init_completion(&prGlueInfo->rPendComp);
#if CFG_SUPPORT_MULTITHREAD
init_completion(&prGlueInfo->rHifHaltComp);
init_completion(&prGlueInfo->rRxHaltComp);
#if CFG_SDIO_RX_DE_AGG_IN_THREAD
init_completion(&prGlueInfo->rxDeAggHaltComp);
#endif
#endif
#if CFG_SUPPORT_CSI
/* init CSI wait queue */
init_waitqueue_head(&(prGlueInfo->prAdapter->rCSIInfo.waitq));
#endif
#if CFG_SUPPORT_NCHO
init_completion(&prGlueInfo->rAisChGrntComp);
#endif
/* initialize timer for OID timeout checker */
kalOsTimerInitialize(prGlueInfo, kalTimeoutHandler);
for (i = 0; i < SPIN_LOCK_NUM; i++) {
spin_lock_init(&prGlueInfo->rSpinLock[i]);
lockdep_set_class(&prGlueInfo->rSpinLock[i], &rSpinKey[i]);
}
for (i = 0; i < MUTEX_NUM; i++) {
mutex_init(&prGlueInfo->arMutex[i]);
lockdep_set_subclass(&prGlueInfo->arMutex[i], i);
}
/* initialize semaphore for ioctl */
sema_init(&prGlueInfo->ioctl_sem, 1);
#if CFG_SUPPORT_SDIO_READ_WRITE_PATTERN
/* initialize SDIO read-write pattern control */
prGlueInfo->fgEnSdioTestPattern = FALSE;
prGlueInfo->fgIsSdioTestInitialized = FALSE;
#endif
/* 4 <8> Init Queues */
init_waitqueue_head(&prGlueInfo->waitq);
QUEUE_INITIALIZE(&prGlueInfo->rCmdQueue);
prGlueInfo->i4TxPendingCmdNum = 0;
QUEUE_INITIALIZE(&prGlueInfo->rTxQueue);
glSetHifInfo(prGlueInfo, (unsigned long) pvData);
/* Init wakelock */
wlanWakeLockInit(prGlueInfo);
/* main thread is created in this function */
#if CFG_SUPPORT_MULTITHREAD
init_waitqueue_head(&prGlueInfo->waitq_rx);
init_waitqueue_head(&prGlueInfo->waitq_hif);
#if CFG_SDIO_RX_DE_AGG_IN_THREAD
init_waitqueue_head(&prGlueInfo->waitq_rxDeAgg);
#endif
prGlueInfo->u4TxThreadPid = 0xffffffff;
prGlueInfo->u4RxThreadPid = 0xffffffff;
prGlueInfo->u4HifThreadPid = 0xffffffff;
#endif
return prWdev;
netcreate_err:
if (prAdapter != NULL) {
wlanAdapterDestroy(prAdapter);
prAdapter = NULL;
}
if (prGlueInfo->prDevHandler != NULL) {
free_netdev(prGlueInfo->prDevHandler);
prGlueInfo->prDevHandler = NULL;
}
return NULL;
} /* end of wlanNetCreate() */
/*----------------------------------------------------------------------------*/
/*!
* \brief Destroying the struct net_device object and the private data.
*
* \param[in] prWdev Pointer to struct wireless_dev.
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
static void wlanNetDestroy(struct wireless_dev *prWdev)
{
struct GLUE_INFO *prGlueInfo = NULL;
ASSERT(prWdev);
if (!prWdev) {
DBGLOG(INIT, ERROR, "The device context is NULL\n");
return;
}
/* prGlueInfo is allocated with net_device */
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(prWdev->wiphy);
ASSERT(prGlueInfo);
/* prWdev: base AIS dev
* Because the interface dev (ex: usb_device) would be free
* after un-plug event. Should set the wiphy->dev->parent which
* pointer to the interface dev to NULL. Otherwise, the corresponding
* system operation (poweroff, suspend) might reference it.
* set_wiphy_dev(wiphy, NULL): set the wiphy->dev->parent = NULL
* The set_wiphy_dev(prWdev->wiphy, prDev) is done in wlanNetCreate.
* But that is after wiphy_register, and will cause exception in
* wiphy_unregister(), if do not set_wiphy_dev(wiphy, NULL).
*/
set_wiphy_dev(prWdev->wiphy, NULL);
/* destroy kal OS timer */
kalCancelTimer(prGlueInfo);
glClearHifInfo(prGlueInfo);
wlanAdapterDestroy(prGlueInfo->prAdapter);
prGlueInfo->prAdapter = NULL;
/* Free net_device and private data, which are allocated by
* alloc_netdev().
*/
free_netdev(prWdev->netdev);
/* gPrDev is assigned by prGlueInfo->prDevHandler,
* set NULL to this global variable.
*/
gPrDev = NULL;
} /* end of wlanNetDestroy() */
void wlanSetSuspendMode(struct GLUE_INFO *prGlueInfo,
u_int8_t fgEnable)
{
struct net_device *prDev = NULL;
#if CFG_SUPPORT_DROP_MC_PACKET
uint32_t u4PacketFilter = 0;
uint32_t u4SetInfoLen = 0;
#endif
if (!prGlueInfo)
return;
prDev = prGlueInfo->prDevHandler;
if (!prDev)
return;
#if CFG_SUPPORT_DROP_MC_PACKET
/* new filter should not include p2p mask */
#if CFG_ENABLE_WIFI_DIRECT_CFG_80211
u4PacketFilter = prGlueInfo->prAdapter->u4OsPacketFilter &
(~PARAM_PACKET_FILTER_P2P_MASK);
#endif
if (kalIoctl(prGlueInfo,
wlanoidSetCurrentPacketFilter,
&u4PacketFilter,
sizeof(u4PacketFilter), FALSE, FALSE, TRUE,
&u4SetInfoLen) != WLAN_STATUS_SUCCESS)
DBGLOG(INIT, ERROR, "set packet filter failed.\n");
#endif
kalSetNetAddressFromInterface(prGlueInfo, prDev, fgEnable);
wlanNotifyFwSuspend(prGlueInfo, prDev, fgEnable);
}
#if CFG_ENABLE_EARLY_SUSPEND
static struct early_suspend wlan_early_suspend_desc = {
.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN,
};
static void wlan_early_suspend(struct early_suspend *h)
{
struct net_device *prDev = NULL;
struct GLUE_INFO *prGlueInfo = NULL;
/* 4 <1> Sanity Check */
if ((u4WlanDevNum == 0)
&& (u4WlanDevNum > CFG_MAX_WLAN_DEVICES)) {
DBGLOG(INIT, ERROR,
"wlanLateResume u4WlanDevNum==0 invalid!!\n");
return;
}
prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev;
if (!prDev)
return;
prGlueInfo = *((struct GLUE_INFO **) netdev_priv(prDev));
if (!prGlueInfo)
return;
DBGLOG(INIT, INFO, "********<%s>********\n", __func__);
if (prGlueInfo->fgIsInSuspendMode == TRUE) {
DBGLOG(INIT, INFO, "%s: Already in suspend mode, SKIP!\n",
__func__);
return;
}
prGlueInfo->fgIsInSuspendMode = TRUE;
wlanSetSuspendMode(prGlueInfo, TRUE);
p2pSetSuspendMode(prGlueInfo, TRUE);
}
static void wlan_late_resume(struct early_suspend *h)
{
struct net_device *prDev = NULL;
struct GLUE_INFO *prGlueInfo = NULL;
/* 4 <1> Sanity Check */
if ((u4WlanDevNum == 0)
&& (u4WlanDevNum > CFG_MAX_WLAN_DEVICES)) {
DBGLOG(INIT, ERROR,
"wlanLateResume u4WlanDevNum==0 invalid!!\n");
return;
}
prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev;
if (!prDev)
return;
prGlueInfo = *((struct GLUE_INFO **) netdev_priv(prDev));
if (!prGlueInfo)
return;
DBGLOG(INIT, INFO, "********<%s>********\n", __func__);
if (prGlueInfo->fgIsInSuspendMode == FALSE) {
DBGLOG(INIT, INFO, "%s: Not in suspend mode, SKIP!\n",
__func__);
return;
}
prGlueInfo->fgIsInSuspendMode = FALSE;
/* 4 <2> Set suspend mode for each network */
wlanSetSuspendMode(prGlueInfo, FALSE);
p2pSetSuspendMode(prGlueInfo, FALSE);
}
#endif
#if (CFG_MTK_ANDROID_WMT || WLAN_INCLUDE_PROC)
int set_p2p_mode_handler(struct net_device *netdev,
struct PARAM_CUSTOM_P2P_SET_STRUCT p2pmode)
{
struct GLUE_INFO *prGlueInfo = *((struct GLUE_INFO **)
netdev_priv(netdev));
struct PARAM_CUSTOM_P2P_SET_STRUCT rSetP2P;
uint32_t rWlanStatus = WLAN_STATUS_SUCCESS;
uint32_t u4BufLen = 0;
if (!prGlueInfo)
return -1;
#if (CFG_MTK_ANDROID_WMT)
if (prGlueInfo->u4ReadyFlag == 0) {
DBGLOG(INIT, ERROR, "adapter is not ready\n");
return -1;
}
#endif /*CFG_MTK_ANDROID_WMT*/
rSetP2P.u4Enable = p2pmode.u4Enable;
rSetP2P.u4Mode = p2pmode.u4Mode;
if ((!rSetP2P.u4Enable) && (kalIsResetting() == FALSE))
p2pNetUnregister(prGlueInfo, FALSE);
rWlanStatus = kalIoctl(prGlueInfo, wlanoidSetP2pMode,
(void *) &rSetP2P,
sizeof(struct PARAM_CUSTOM_P2P_SET_STRUCT),
FALSE, FALSE, TRUE, &u4BufLen);
DBGLOG(INIT, INFO, "set_p2p_mode_handler ret = 0x%08x\n",
(uint32_t) rWlanStatus);
/* Need to check fgIsP2PRegistered, in case of whole chip reset.
* in this case, kalIOCTL return success always,
* and prGlueInfo->prP2PInfo[0] may be NULL
*/
if ((rSetP2P.u4Enable)
&& (prGlueInfo->prAdapter->fgIsP2PRegistered)
&& (kalIsResetting() == FALSE))
p2pNetRegister(prGlueInfo, FALSE);
return 0;
}
#endif
/*----------------------------------------------------------------------------*/
/*!
* \brief get config from wifi.cfg
*
* \param[in] prAdapter
*
* \retval VOID
*/
/*----------------------------------------------------------------------------*/
void wlanGetConfig(struct ADAPTER *prAdapter)
{
uint8_t *pucConfigBuf;
uint32_t u4ConfigReadLen;
#if CFG_SUPPORT_MULTI_DONGLE
#define WIFI_CFG_FN "wifi_mt7663.cfg"
#else
#define WIFI_CFG_FN "wifi.cfg"
#endif
wlanCfgInit(prAdapter, NULL, 0, 0);
pucConfigBuf = (uint8_t *) kalMemAlloc(
WLAN_CFG_FILE_BUF_SIZE, VIR_MEM_TYPE);
kalMemZero(pucConfigBuf, WLAN_CFG_FILE_BUF_SIZE);
u4ConfigReadLen = 0;
if (pucConfigBuf) {
#ifdef CFG_FILE_NAME
if (kalRequestFirmware(CFG_FILE_NAME, pucConfigBuf,
WLAN_CFG_FILE_BUF_SIZE, &u4ConfigReadLen,
prAdapter->prGlueInfo->prDev) == 0) {
} else
#endif
if (kalRequestFirmware(WIFI_CFG_FN, pucConfigBuf,
WLAN_CFG_FILE_BUF_SIZE, &u4ConfigReadLen,
prAdapter->prGlueInfo->prDev) == 0) {
/* ToDo:: Nothing */
} else if (kalReadToFile("/data/misc/wifi/wifi.cfg",
pucConfigBuf, WLAN_CFG_FILE_BUF_SIZE,
&u4ConfigReadLen) == 0) {
/* ToDo:: Nothing */
} else if (kalReadToFile("/storage/sdcard0/wifi.cfg",
pucConfigBuf, WLAN_CFG_FILE_BUF_SIZE,
&u4ConfigReadLen) == 0) {
/* ToDo:: Nothing */
}
if (pucConfigBuf[0] != '\0' && u4ConfigReadLen > 0)
wlanCfgInit(prAdapter,
pucConfigBuf, u4ConfigReadLen, 0);
kalMemFree(pucConfigBuf, VIR_MEM_TYPE,
WLAN_CFG_FILE_BUF_SIZE);
} /* pucConfigBuf */
}
/*----------------------------------------------------------------------------*/
/*!
* \brief this function send buffer bin EEPROB_MTxxxx.bin to FW.
*
* \param[in] prAdapter
*
* \retval WLAN_STATUS_SUCCESS Success
* \retval WLAN_STATUS_FAILURE Failed
*/
/*----------------------------------------------------------------------------*/
uint32_t wlanDownloadBufferBin(struct ADAPTER *prAdapter)
{
struct GLUE_INFO *prGlueInfo = NULL;
#if (CFG_FW_Report_Efuse_Address)
uint16_t u2InitAddr = prAdapter->u4EfuseStartAddress;
#else
uint16_t u2InitAddr = EFUSE_CONTENT_BUFFER_START;
#endif
uint32_t u4BufLen = 0;
uint32_t rStatus = WLAN_STATUS_SUCCESS;
struct PARAM_CUSTOM_EFUSE_BUFFER_MODE *prSetEfuseBufModeInfo
= NULL;
uint32_t u4ContentLen;
uint8_t *pucConfigBuf = NULL;
struct mt66xx_chip_info *prChipInfo;
uint32_t chip_id;
uint8_t aucEeprom[32];
uint32_t retWlanStat = WLAN_STATUS_FAILURE;
#if CFG_EFUSE_AUTO_MODE_SUPPORT
uint32_t u4Efuse_addr = 0;
struct PARAM_CUSTOM_ACCESS_EFUSE *prAccessEfuseInfo
= NULL;
#endif
if (prAdapter->fgIsSupportPowerOnSendBufferModeCMD ==
TRUE) {
DBGLOG(INIT, INFO, "Start Efuse Buffer Mode ..\n");
DBGLOG(INIT, INFO, "ucEfuseBUfferModeCal is %x\n",
prAdapter->rWifiVar.ucEfuseBufferModeCal);
prChipInfo = prAdapter->chip_info;
chip_id = prChipInfo->chip_id;
prGlueInfo = prAdapter->prGlueInfo;
if (prGlueInfo == NULL || prGlueInfo->prDev == NULL)
goto label_exit;
/* allocate memory for buffer mode info */
prSetEfuseBufModeInfo =
(struct PARAM_CUSTOM_EFUSE_BUFFER_MODE *)
kalMemAlloc(sizeof(
struct PARAM_CUSTOM_EFUSE_BUFFER_MODE),
VIR_MEM_TYPE);
if (prSetEfuseBufModeInfo == NULL)
goto label_exit;
kalMemZero(prSetEfuseBufModeInfo,
sizeof(struct PARAM_CUSTOM_EFUSE_BUFFER_MODE));
#if CFG_EFUSE_AUTO_MODE_SUPPORT
/* allocate memory for Access Efuse Info */
prAccessEfuseInfo =
(struct PARAM_CUSTOM_ACCESS_EFUSE *)
kalMemAlloc(sizeof(
struct PARAM_CUSTOM_ACCESS_EFUSE),
VIR_MEM_TYPE);
if (prAccessEfuseInfo == NULL)
goto label_exit;
kalMemZero(prAccessEfuseInfo,
sizeof(struct PARAM_CUSTOM_ACCESS_EFUSE));
if (prAdapter->rWifiVar.ucEfuseBufferModeCal == LOAD_AUTO) {
prAccessEfuseInfo->u4Address = (u4Efuse_addr /
EFUSE_BLOCK_SIZE) * EFUSE_BLOCK_SIZE;
rStatus = kalIoctl(prGlueInfo,
wlanoidQueryProcessAccessEfuseRead,
prAccessEfuseInfo,
sizeof(struct PARAM_CUSTOM_ACCESS_EFUSE),
TRUE, TRUE, TRUE, &u4BufLen);
if (prGlueInfo->prAdapter->aucEepromVaule[1]
== (chip_id>>8)) {
prAdapter->rWifiVar.ucEfuseBufferModeCal
= LOAD_EFUSE;
DBGLOG(INIT, STATE,
"[EFUSE AUTO] EFUSE Mode\n");
} else {
prAdapter->rWifiVar.ucEfuseBufferModeCal
= LOAD_EEPROM_BIN;
DBGLOG(INIT, STATE,
"[EFUSE AUTO] Buffer Mode\n");
}
}
#endif
if (prAdapter->rWifiVar.ucEfuseBufferModeCal
== LOAD_EEPROM_BIN) {
/* Buffer mode */
/* Only in buffer mode need to access bin file */
/* 1 <1> Load bin file*/
pucConfigBuf = (uint8_t *) kalMemAlloc(
MAX_EEPROM_BUFFER_SIZE, VIR_MEM_TYPE);
if (pucConfigBuf == NULL)
goto label_exit;
kalMemZero(pucConfigBuf, MAX_EEPROM_BUFFER_SIZE);
/* 1 <2> Construct EEPROM binary name */
kalMemZero(aucEeprom, sizeof(aucEeprom));
snprintf(aucEeprom, 32, "%s%x.bin",
apucEepromName[0], chip_id);
/* 1 <3> Request buffer bin */
if (kalRequestFirmware(aucEeprom, pucConfigBuf,
MAX_EEPROM_BUFFER_SIZE, &u4ContentLen,
prGlueInfo->prDev) == 0) {
DBGLOG(INIT, INFO, "request file done\n");
} else {
DBGLOG(INIT, INFO, "can't find file\n");
goto label_exit;
}
/* 1 <4> Send CMD with bin file content */
prGlueInfo = prAdapter->prGlueInfo;
/* Update contents in local table */
kalMemCopy(uacEEPROMImage, pucConfigBuf,
MAX_EEPROM_BUFFER_SIZE);
/* copy to the command buffer */
#if (CFG_FW_Report_Efuse_Address)
u4ContentLen = (prAdapter->u4EfuseEndAddress) -
(prAdapter->u4EfuseStartAddress) + 1;
#else
u4ContentLen = EFUSE_CONTENT_BUFFER_SIZE;
#endif
if (u4ContentLen > MAX_EEPROM_BUFFER_SIZE)
goto label_exit;
kalMemCopy(prSetEfuseBufModeInfo->aBinContent,
&pucConfigBuf[u2InitAddr], u4ContentLen);
prSetEfuseBufModeInfo->ucSourceMode = 1;
} else {
/* eFuse mode */
/* Only need to tell FW the content from, contents are
* directly from efuse
*/
prSetEfuseBufModeInfo->ucSourceMode = 0;
}
prSetEfuseBufModeInfo->ucCmdType = 0x1 |
(prAdapter->rWifiVar.ucCalTimingCtrl << 4);
prSetEfuseBufModeInfo->ucCount =
0xFF; /* ucCmdType 1 don't care the ucCount */
rStatus = kalIoctl(prGlueInfo, wlanoidSetEfusBufferMode,
(void *)prSetEfuseBufModeInfo,
sizeof(struct PARAM_CUSTOM_EFUSE_BUFFER_MODE),
FALSE, TRUE, TRUE, &u4BufLen);
}
retWlanStat = WLAN_STATUS_SUCCESS;
label_exit:
/* free memory */
if (prSetEfuseBufModeInfo != NULL)
kalMemFree(prSetEfuseBufModeInfo, VIR_MEM_TYPE,
sizeof(struct PARAM_CUSTOM_EFUSE_BUFFER_MODE));
if (pucConfigBuf != NULL)
kalMemFree(pucConfigBuf, VIR_MEM_TYPE,
MAX_EEPROM_BUFFER_SIZE);
#if CFG_EFUSE_AUTO_MODE_SUPPORT
if (prAccessEfuseInfo != NULL)
kalMemFree(prAccessEfuseInfo, VIR_MEM_TYPE,
sizeof(struct PARAM_CUSTOM_ACCESS_EFUSE));
#endif
return retWlanStat;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief this function send buffer bin EEPROB_MTxxxx.bin to FW.
*
* \param[in] prAdapter
*
* \retval WLAN_STATUS_SUCCESS Success
* \retval WLAN_STATUS_FAILURE Failed
*/
/*----------------------------------------------------------------------------*/
uint32_t wlanConnacDownloadBufferBin(struct ADAPTER
*prAdapter)
{
struct GLUE_INFO *prGlueInfo = NULL;
uint32_t u4BufLen = 0;
uint32_t rStatus = WLAN_STATUS_SUCCESS;
struct PARAM_CUSTOM_EFUSE_BUFFER_MODE_CONNAC_T
*prSetEfuseBufModeInfo = NULL;
uint32_t u4ContentLen;
uint8_t *pucConfigBuf = NULL;
struct mt66xx_chip_info *prChipInfo;
uint32_t chip_id;
uint8_t aucEeprom[32];
uint32_t retWlanStat = WLAN_STATUS_FAILURE;
struct CAP_BUFFER_MODE_INFO_T *prBufferModeInfo = NULL;
#if CFG_EFUSE_AUTO_MODE_SUPPORT
uint32_t u4Efuse_addr = 0;
struct PARAM_CUSTOM_ACCESS_EFUSE *prAccessEfuseInfo
= NULL;
#endif
if (prAdapter->fgIsSupportPowerOnSendBufferModeCMD == FALSE)
return WLAN_STATUS_SUCCESS;
DBGLOG(INIT, INFO, "Start Efuse Buffer Mode ..\n");
DBGLOG(INIT, INFO, "ucEfuseBUfferModeCal is %x\n",
prAdapter->rWifiVar.ucEfuseBufferModeCal);
prChipInfo = prAdapter->chip_info;
chip_id = prChipInfo->chip_id;
prGlueInfo = prAdapter->prGlueInfo;
prBufferModeInfo = &prAdapter->rBufferModeInfo;
if (prGlueInfo == NULL || prGlueInfo->prDev == NULL)
goto label_exit;
/* allocate memory for buffer mode info */
prSetEfuseBufModeInfo =
(struct PARAM_CUSTOM_EFUSE_BUFFER_MODE_CONNAC_T *)
kalMemAlloc(sizeof(
struct PARAM_CUSTOM_EFUSE_BUFFER_MODE_CONNAC_T),
VIR_MEM_TYPE);
if (prSetEfuseBufModeInfo == NULL)
goto label_exit;
kalMemZero(prSetEfuseBufModeInfo,
sizeof(struct PARAM_CUSTOM_EFUSE_BUFFER_MODE_CONNAC_T));
#if CFG_EFUSE_AUTO_MODE_SUPPORT
/* allocate memory for Access Efuse Info */
prAccessEfuseInfo =
(struct PARAM_CUSTOM_ACCESS_EFUSE *)
kalMemAlloc(sizeof(
struct PARAM_CUSTOM_ACCESS_EFUSE),
VIR_MEM_TYPE);
if (prAccessEfuseInfo == NULL)
goto label_exit;
kalMemZero(prAccessEfuseInfo,
sizeof(struct PARAM_CUSTOM_ACCESS_EFUSE));
if (prAdapter->rWifiVar.ucEfuseBufferModeCal == LOAD_AUTO) {
prAccessEfuseInfo->u4Address = (u4Efuse_addr /
EFUSE_BLOCK_SIZE) * EFUSE_BLOCK_SIZE;
rStatus = kalIoctl(prGlueInfo,
wlanoidQueryProcessAccessEfuseRead,
prAccessEfuseInfo,
sizeof(struct PARAM_CUSTOM_ACCESS_EFUSE),
TRUE, TRUE, TRUE, &u4BufLen);
if (prGlueInfo->prAdapter->aucEepromVaule[1]
== (chip_id>>8)) {
prAdapter->rWifiVar.ucEfuseBufferModeCal
= LOAD_EFUSE;
DBGLOG(INIT, STATE,
"[EFUSE AUTO] EFUSE Mode\n");
} else {
prAdapter->rWifiVar.ucEfuseBufferModeCal
= LOAD_EEPROM_BIN;
DBGLOG(INIT, STATE,
"[EFUSE AUTO] Buffer Mode\n");
}
}
#endif
if (prAdapter->rWifiVar.ucEfuseBufferModeCal == LOAD_EEPROM_BIN) {
/* Buffer mode */
/* Only in buffer mode need to access bin file */
/* 1 <1> Load bin file*/
pucConfigBuf = (uint8_t *) kalMemAlloc(
MAX_EEPROM_BUFFER_SIZE, VIR_MEM_TYPE);
if (pucConfigBuf == NULL)
goto label_exit;
kalMemZero(pucConfigBuf, MAX_EEPROM_BUFFER_SIZE);
/* 1 <2> Construct EEPROM binary name */
kalMemZero(aucEeprom, sizeof(aucEeprom));
snprintf(aucEeprom, 32, "%s%x.bin",
apucEepromName[0], chip_id);
/* 1 <3> Request buffer bin */
#if CFG_SUPPORT_CUSTOM_EEPROM_FILE
if (kalStrLen(gprEepromFile) > 0 &&
kalRequestFirmware(gprEepromFile, pucConfigBuf,
MAX_EEPROM_BUFFER_SIZE, &u4ContentLen, prGlueInfo->prDev)
== 0) {
DBGLOG(INIT, INFO, "request file done\n");
} else
#endif
if (kalRequestFirmware(aucEeprom, pucConfigBuf,
MAX_EEPROM_BUFFER_SIZE, &u4ContentLen, prGlueInfo->prDev)
== 0) {
DBGLOG(INIT, INFO, "request file done\n");
} else {
DBGLOG(INIT, INFO, "can't find file\n");
goto label_exit;
}
DBGLOG(INIT, INFO, "u4ContentLen = %d\n", u4ContentLen);
if (u4ContentLen > MAX_EEPROM_BUFFER_SIZE) {
DBGLOG(INIT, ERROR, "u4ContentLen: %d > %d\n",
u4ContentLen, MAX_EEPROM_BUFFER_SIZE);
goto label_exit;
}
/* Update contents in local table */
kalMemCopy(uacEEPROMImage, pucConfigBuf,
u4ContentLen);
/* Show EEPROM version for customer */
DBGLOG(INIT, INFO, "EEPROM version = %x\n", uacEEPROMImage[EEPROM_VERSION_CUSTOMER]);
/* 1 <4> Send CMD with bin file content */
if (prBufferModeInfo->ucVersion != 0x02) {
DBGLOG(INIT, ERROR, "Not support version\n");
goto label_exit;
}
if (prBufferModeInfo->ucFormatSupportBitmap &
BIT(CONTENT_FORMAT_WHOLE_CONTENT)) {
if (u4ContentLen > prBufferModeInfo->u2EfuseTotalSize) {
DBGLOG(INIT, ERROR, "u4ContentLen: %d > %d\n",
u4ContentLen,
prBufferModeInfo->u2EfuseTotalSize);
goto label_exit;
}
kalMemCopy(prSetEfuseBufModeInfo->aBinContent,
pucConfigBuf, u4ContentLen);
} else if (prBufferModeInfo->ucFormatSupportBitmap &
BIT(CONTENT_FORMAT_MULTIPLE_SECTIONS)) {
/* TODO */
DBGLOG(INIT, ERROR, "Not support yet!\n");
goto label_exit;
} else {
DBGLOG(INIT, ERROR,
"Not support legacy BIN_CONTENT mode\n");
goto label_exit;
}
prSetEfuseBufModeInfo->ucSourceMode = SOURCE_MODE_BUFFER_MODE;
#if CFG_RCPI_COMPENSATION
wlanLoadBufferbinRxFELoss(prAdapter);
#endif
#if CFG_SUPPORT_HW_1T2R
wlanLoadBufferbin1T2R(prAdapter);
#endif
} else {
/* eFuse mode */
/* Only need to tell FW the content from, contents are directly
* from efuse
*/
prSetEfuseBufModeInfo->ucSourceMode = SOURCE_MODE_EFUSE;
u4ContentLen = 0;
#if CFG_RCPI_COMPENSATION
wlanLoadEfuseRxFELoss(prAdapter);
#endif
#if CFG_SUPPORT_HW_1T2R
wlanLoadEfuse1T2R(prAdapter);
#endif
}
prSetEfuseBufModeInfo->ucContentFormat = CONTENT_FORMAT_WHOLE_CONTENT |
(prAdapter->rWifiVar.ucCalTimingCtrl <<
CMD_TYPE_CAL_TIME_REDUCTION_SHFT);
prSetEfuseBufModeInfo->u2Count = u4ContentLen;
rStatus = kalIoctl(prGlueInfo, wlanoidConnacSetEfusBufferMode,
(void *)prSetEfuseBufModeInfo,
OFFSET_OF(struct PARAM_CUSTOM_EFUSE_BUFFER_MODE_CONNAC_T,
aBinContent) + u4ContentLen,
FALSE, TRUE, TRUE, &u4BufLen);
retWlanStat = WLAN_STATUS_SUCCESS;
label_exit:
/* free memory */
if (prSetEfuseBufModeInfo != NULL)
kalMemFree(prSetEfuseBufModeInfo, VIR_MEM_TYPE,
sizeof(struct PARAM_CUSTOM_EFUSE_BUFFER_MODE_CONNAC_T));
if (pucConfigBuf != NULL)
kalMemFree(pucConfigBuf, VIR_MEM_TYPE,
MAX_EEPROM_BUFFER_SIZE);
#if CFG_EFUSE_AUTO_MODE_SUPPORT
if (prAccessEfuseInfo != NULL)
kalMemFree(prAccessEfuseInfo, VIR_MEM_TYPE,
sizeof(struct PARAM_CUSTOM_ACCESS_EFUSE));
#endif
return retWlanStat;
}
#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH
#define FW_LOG_CMD_ON_OFF 0
#define FW_LOG_CMD_SET_LEVEL 1
static uint32_t u4LogOnOffCache = -1;
static void consys_log_event_notification(int cmd, int value)
{
struct GLUE_INFO *prGlueInfo = NULL;
struct ADAPTER *prAdapter = NULL;
struct net_device *prDev = gPrDev;
uint32_t rStatus = WLAN_STATUS_FAILURE;
struct CMD_HEADER rCmdV1Header;
struct CMD_FORMAT_V1 rCmd_v1;
DBGLOG(INIT, INFO, "gPrDev=%p, cmd=%d, value=%d\n",
gPrDev, cmd, value);
if (kalIsHalted()) { /* power-off */
u4LogOnOffCache = value;
DBGLOG(INIT, INFO,
"Power off return, u4LogOnOffCache=%d\n",
u4LogOnOffCache);
return;
}
prGlueInfo = (prDev != NULL) ?
*((struct GLUE_INFO **) netdev_priv(prDev)) : NULL;
DBGLOG(INIT, TRACE, "prGlueInfo=%p\n", prGlueInfo);
if (!prGlueInfo) {
u4LogOnOffCache = value;
DBGLOG(INIT, INFO,
"prGlueInfo == NULL return, u4LogOnOffCache=%d\n",
u4LogOnOffCache);
return;
}
prAdapter = prGlueInfo->prAdapter;
DBGLOG(INIT, TRACE, "prAdapter=%p\n", prAdapter);
if (!prAdapter) {
u4LogOnOffCache = value;
DBGLOG(INIT, INFO,
"prAdapter == NULL return, u4LogOnOffCache=%d\n",
u4LogOnOffCache);
return;
}
if (cmd == FW_LOG_CMD_ON_OFF) {
/*EvtDrvnLogEn 0/1*/
uint8_t onoff[1] = {'0'};
DBGLOG(INIT, TRACE, "FW_LOG_CMD_ON_OFF\n");
rCmdV1Header.cmdType = CMD_TYPE_SET;
rCmdV1Header.cmdVersion = CMD_VER_1;
rCmdV1Header.cmdBufferLen = 0;
rCmdV1Header.itemNum = 0;
kalMemSet(rCmdV1Header.buffer, 0, MAX_CMD_BUFFER_LENGTH);
kalMemSet(&rCmd_v1, 0, sizeof(struct CMD_FORMAT_V1));
rCmd_v1.itemType = ITEM_TYPE_STR;
/*send string format to firmware */
rCmd_v1.itemStringLength = kalStrLen("EnableDbgLog");
kalMemZero(rCmd_v1.itemString, MAX_CMD_NAME_MAX_LENGTH);
kalMemCopy(rCmd_v1.itemString, "EnableDbgLog",
rCmd_v1.itemStringLength);
if (value == 1) /* other cases, send 'OFF=0' */
onoff[0] = '1';
rCmd_v1.itemValueLength = 1;
kalMemZero(rCmd_v1.itemValue, MAX_CMD_VALUE_MAX_LENGTH);
kalMemCopy(rCmd_v1.itemValue, &onoff, 1);
DBGLOG(INIT, INFO, "Send key word (%s) WITH (%s) to firmware\n",
rCmd_v1.itemString, rCmd_v1.itemValue);
kalMemCopy(((struct CMD_FORMAT_V1 *)rCmdV1Header.buffer),
&rCmd_v1, sizeof(struct CMD_FORMAT_V1));
rCmdV1Header.cmdBufferLen += sizeof(struct CMD_FORMAT_V1);
rCmdV1Header.itemNum = 1;
rStatus = wlanSendSetQueryCmd(
prAdapter, /* prAdapter */
CMD_ID_GET_SET_CUSTOMER_CFG, /* 0x70 */
TRUE, /* fgSetQuery */
FALSE, /* fgNeedResp */
FALSE, /* fgIsOid */
NULL, /* pfCmdDoneHandler*/
NULL, /* pfCmdTimeoutHandler */
sizeof(struct CMD_HEADER),
(uint8_t *)&rCmdV1Header, /* pucInfoBuffer */
NULL, /* pvSetQueryBuffer */
0 /* u4SetQueryBufferLen */
);
if (rStatus == WLAN_STATUS_FAILURE)
DBGLOG(INIT, INFO,
"[Fail]kalIoctl wifiSefCFG fail 0x%x\n",
rStatus);
/* keep in cache */
u4LogOnOffCache = value;
} else if (cmd == FW_LOG_CMD_SET_LEVEL) {
/*ENG_LOAD_OFFSET 1*/
/*USERDEBUG_LOAD_OFFSET 2 */
/*USER_LOAD_OFFSET 3 */
DBGLOG(INIT, INFO, "FW_LOG_CMD_SET_LEVEL\n");
} else {
DBGLOG(INIT, INFO, "command can not parse\n");
}
}
#endif
/*----------------------------------------------------------------------------*/
/*!
* \brief Wlan probe function. This function probes and initializes the device.
*
* \param[in] pvData data passed by bus driver init function
* _HIF_EHPI: NULL
* _HIF_SDIO: sdio bus driver handle
*
* \retval 0 Success
* \retval negative value Failed
*/
/*----------------------------------------------------------------------------*/
static int32_t wlanProbe(void *pvData, void *pvDriverData)
{
struct wireless_dev *prWdev = NULL;
enum ENUM_PROBE_FAIL_REASON {
BUS_INIT_FAIL,
NET_CREATE_FAIL,
BUS_SET_IRQ_FAIL,
ADAPTER_START_FAIL,
NET_REGISTER_FAIL,
PROC_INIT_FAIL,
FAIL_MET_INIT_PROCFS,
FAIL_REASON_NUM
} eFailReason;
struct WLANDEV_INFO *prWlandevInfo = NULL;
int32_t i4DevIdx = 0;
struct GLUE_INFO *prGlueInfo = NULL;
struct ADAPTER *prAdapter = NULL;
int32_t i4Status = 0;
u_int8_t bRet = FALSE;
u_int8_t i = 0;
struct REG_INFO *prRegInfo;
struct mt66xx_chip_info *prChipInfo;
#if CFG_SUPPORT_REPLAY_DETECTION
u_int8_t ucRpyDetectOffload;
#endif
#if CFG_THERMAL_API_SUPPORT
struct wcn_platform_bridge pbridge;
#endif
#if (MTK_WCN_HIF_SDIO && CFG_WMT_WIFI_PATH_SUPPORT)
int32_t i4RetVal = 0;
#endif
int32_t u4LogLevel = ENUM_WIFI_LOG_LEVEL_DEFAULT;
#if 0
uint8_t *pucConfigBuf = NULL, pucCfgBuf = NULL;
uint32_t u4ConfigReadLen = 0;
#endif
eFailReason = FAIL_REASON_NUM;
#if CFG_CHIP_RESET_SUPPORT
fgIsResetting = FALSE;
fgIsResetTrigger = FALSE;
fgIsBtTriggered = FALSE;
#if CFG_CHIP_RESET_KO_SUPPORT
send_reset_event(RESET_MODULE_TYPE_WIFI, RFSM_EVENT_PROBE_START);
#endif
#endif
do {
/* 4 <1> Initialize the IO port of the interface */
/* GeorgeKuo: pData has different meaning for _HIF_XXX:
* _HIF_EHPI: pointer to memory base variable, which will be
* initialized by glBusInit().
* _HIF_SDIO: bus driver handle
*/
DBGLOG(INIT, STATE, "enter wlanProbe\n");
bRet = glBusInit(pvData);
#if (CFG_SUPPORT_TRACE_TC4 == 1)
wlanDebugTC4Init();
#endif
/* Cannot get IO address from interface */
if (bRet == FALSE) {
DBGLOG(INIT, ERROR, "wlanProbe: glBusInit() fail\n");
i4Status = -EIO;
eFailReason = BUS_INIT_FAIL;
break;
}
/* 4 <2> Create network device, Adapter, KalInfo,
* prDevHandler(netdev)
*/
prWdev = wlanNetCreate(pvData, pvDriverData);
if (prWdev == NULL) {
DBGLOG(INIT, ERROR,
"wlanProbe: No memory for dev and its private\n");
i4Status = -ENOMEM;
eFailReason = NET_CREATE_FAIL;
break;
}
/* 4 <2.5> Set the ioaddr to HIF Info */
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(prWdev->wiphy);
if (prGlueInfo == NULL) {
DBGLOG(INIT, ERROR,
"wlanProbe: get wiphy_priv() fail\n");
i4Status = -EFAULT;
break;
}
gPrDev = prGlueInfo->prDevHandler;
/* 4 <4> Setup IRQ */
prWlandevInfo = &arWlanDevInfo[i4DevIdx];
i4Status = glBusSetIrq(prWdev->netdev, NULL, prGlueInfo);
if (i4Status != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, ERROR, "wlanProbe: Set IRQ error\n");
eFailReason = BUS_SET_IRQ_FAIL;
break;
}
prGlueInfo->i4DevIdx = i4DevIdx;
prAdapter = prGlueInfo->prAdapter;
prGlueInfo->u4ReadyFlag = 0;
#if CFG_TCP_IP_CHKSUM_OFFLOAD
prAdapter->fgIsSupportCsumOffload = FALSE;
prAdapter->u4CSUMFlags = CSUM_OFFLOAD_EN_ALL;
#endif
#if CFG_SUPPORT_CFG_FILE
wlanGetConfig(prAdapter);
#endif
/* Init Chip Capability */
prChipInfo = prAdapter->chip_info;
if (prChipInfo->asicCapInit)
prChipInfo->asicCapInit(prAdapter);
/* Default support 2.4/5G MIMO */
prAdapter->rWifiFemCfg.u2WifiPath = (
WLAN_FLAG_2G4_WF0 | WLAN_FLAG_5G_WF0 |
WLAN_FLAG_2G4_WF1 | WLAN_FLAG_5G_WF1);
#if (MTK_WCN_HIF_SDIO && CFG_WMT_WIFI_PATH_SUPPORT)
i4RetVal = mtk_wcn_wmt_wifi_fem_cfg_report((
void *)&prAdapter->rWifiFemCfg);
if (i4RetVal)
DBGLOG(INIT, ERROR, "Get WifiPath from WMT drv fail\n");
else
DBGLOG(INIT, INFO,
"Get WifiPath from WMT drv success, WifiPath=0x%x\n",
prAdapter->rWifiFemCfg.u2WifiPath);
#endif
/* 4 <5> Start Device */
prRegInfo = &prGlueInfo->rRegInfo;
/* P_REG_INFO_T prRegInfo = (P_REG_INFO_T) kmalloc(
* sizeof(REG_INFO_T), GFP_KERNEL);
*/
kalMemSet(prRegInfo, 0, sizeof(struct REG_INFO));
/* Trigger the action of switching Pwr state to drv_own */
prAdapter->fgIsFwOwn = TRUE;
/* Load NVRAM content to REG_INFO_T */
glLoadNvram(prGlueInfo, prRegInfo);
/* kalMemCopy(&prGlueInfo->rRegInfo, prRegInfo,
* sizeof(REG_INFO_T));
*/
prRegInfo->u4PowerMode = CFG_INIT_POWER_SAVE_PROF;
#if 0
prRegInfo->fgEnArpFilter = TRUE;
#endif
/* The Init value of u4WpaVersion/u4AuthAlg shall be
* DISABLE/OPEN, not zero!
*/
/* The Init value of u4CipherGroup/u4CipherPairwise shall be
* NONE, not zero!
*/
prGlueInfo->rWpaInfo.u4WpaVersion =
IW_AUTH_WPA_VERSION_DISABLED;
prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM;
prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE;
prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE;
tasklet_init(&prGlueInfo->rRxTask, halRxTasklet,
(unsigned long)prGlueInfo);
tasklet_init(&prGlueInfo->rTxCompleteTask,
halTxCompleteTasklet, (unsigned long)prGlueInfo);
if (wlanAdapterStart(prAdapter,
prRegInfo) != WLAN_STATUS_SUCCESS)
i4Status = -EIO;
if (HAL_IS_TX_DIRECT(prAdapter)) {
if (!prAdapter->fgTxDirectInited) {
skb_queue_head_init(
&prAdapter->rTxDirectSkbQueue);
#if KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE
timer_setup(&prAdapter->rTxDirectSkbTimer,
nicTxDirectTimerCheckSkbQ, 0);
timer_setup(&prAdapter->rTxDirectHifTimer,
nicTxDirectTimerCheckHifQ, 0);
#else
init_timer(&prAdapter->rTxDirectSkbTimer);
prAdapter->rTxDirectSkbTimer.data =
(unsigned long)prGlueInfo;
prAdapter->rTxDirectSkbTimer.function =
nicTxDirectTimerCheckSkbQ;
init_timer(&prAdapter->rTxDirectHifTimer);
prAdapter->rTxDirectHifTimer.data =
(unsigned long)prGlueInfo;
prAdapter->rTxDirectHifTimer.function =
nicTxDirectTimerCheckHifQ;
#endif
prAdapter->fgTxDirectInited = TRUE;
}
}
/* kfree(prRegInfo); */
if (i4Status < 0) {
eFailReason = ADAPTER_START_FAIL;
break;
}
#if (CFG_SUPPORT_TX_TSO_SW == 1)
skb_queue_head_init(&prAdapter->rTsoQueue);
#endif
INIT_WORK(&prGlueInfo->rTxMsduFreeWork, kalFreeTxMsduWorker);
INIT_DELAYED_WORK(&prGlueInfo->rRxPktDeAggWork,
halDeAggRxPktWorker);
#if CFG_SUPPORT_CFG80211_AUTH
#if CFG_SUPPORT_CFG80211_QUEUE
INIT_DELAYED_WORK(&cfg80211_workq,
wlanSchedCfg80211WorkQueue);
#endif
#endif
prGlueInfo->main_thread = kthread_run(main_thread,
prGlueInfo->prDevHandler, "main_thread");
#if CFG_SUPPORT_MULTITHREAD
prGlueInfo->hif_thread = kthread_run(hif_thread,
prGlueInfo->prDevHandler, "hif_thread");
prGlueInfo->rx_thread = kthread_run(rx_thread,
prGlueInfo->prDevHandler, "rx_thread");
HAL_AGG_THREAD(prGlueInfo->prAdapter);
#if CFG_SDIO_RX_DE_AGG_IN_THREAD
prGlueInfo->rx_DeAgg_thread = kthread_run(sdio_rx_DeAgg_thread,
prGlueInfo->prDevHandler,
"sdio_rx_DeAgg_thread");
#endif
#endif
g_u4HaltFlag = 0;
#if CFG_SUPPORT_BUFFER_MODE
#if (CFG_EFUSE_BUFFER_MODE_DELAY_CAL == 1)
if (prChipInfo->downloadBufferBin) {
if (prChipInfo->downloadBufferBin(prAdapter) !=
WLAN_STATUS_SUCCESS){
DBGLOG(INIT, ERROR,
"wlanProbe: downloadBufferBin fail\n");
i4Status = -1;
goto WLAN_PROBE_RETURN;
}
}
#endif
#endif
#if CFG_SUPPORT_DBDC
/* Update DBDC default setting */
cnmInitDbdcSetting(prAdapter);
#endif /*CFG_SUPPORT_DBDC*/
/* send regulatory information to firmware */
rlmDomainSendInfoToFirmware(prAdapter);
/* set MAC address */
{
uint32_t rStatus = WLAN_STATUS_FAILURE;
struct sockaddr MacAddr;
uint32_t u4SetInfoLen = 0;
rStatus = kalIoctl(prGlueInfo, wlanoidQueryCurrentAddr,
&MacAddr.sa_data, PARAM_MAC_ADDR_LEN,
TRUE, TRUE, TRUE, &u4SetInfoLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, WARN, "set MAC addr fail 0x%x\n",
rStatus);
} else {
kalMemCopy(prGlueInfo->prDevHandler->dev_addr,
&MacAddr.sa_data, ETH_ALEN);
kalMemCopy(prGlueInfo->prDevHandler->perm_addr,
prGlueInfo->prDevHandler->dev_addr,
ETH_ALEN);
#if CFG_SHOW_MACADDR_SOURCE
DBGLOG(INIT, INFO, "MAC address: " MACSTR,
MAC2STR(prAdapter->rWifiVar.aucMacAddress));
#endif
}
}
#if CFG_TCP_IP_CHKSUM_OFFLOAD
/* set HW checksum offload */
if (prAdapter->fgIsSupportCsumOffload) {
uint32_t rStatus = WLAN_STATUS_FAILURE;
uint32_t u4CSUMFlags = CSUM_OFFLOAD_EN_ALL;
uint32_t u4SetInfoLen = 0;
rStatus = kalIoctl(prGlueInfo, wlanoidSetCSUMOffload,
(void *) &u4CSUMFlags,
sizeof(uint32_t),
FALSE, FALSE, TRUE, &u4SetInfoLen);
if (rStatus == WLAN_STATUS_SUCCESS) {
prGlueInfo->prDevHandler->features =
NETIF_F_IP_CSUM |
NETIF_F_IPV6_CSUM |
NETIF_F_RXCSUM;
} else {
DBGLOG(INIT, WARN,
"set HW checksum offload fail 0x%x\n",
rStatus);
prAdapter->fgIsSupportCsumOffload = FALSE;
}
}
#endif
#if CFG_SUPPORT_802_11K
{
uint32_t rStatus = WLAN_STATUS_FAILURE;
uint32_t u4SetInfoLen = 0;
rStatus = kalIoctl(prGlueInfo,
wlanoidSync11kCapabilities, NULL, 0,
FALSE, FALSE, TRUE, &u4SetInfoLen);
if (rStatus != WLAN_STATUS_SUCCESS)
DBGLOG(INIT, WARN,
"RRM: Set 11k Capabilities fail 0x%x\n",
rStatus);
}
#endif
/* 4 <3> Register the card */
i4DevIdx = wlanNetRegister(prWdev);
if (i4DevIdx < 0) {
i4Status = -ENXIO;
DBGLOG(INIT, ERROR,
"wlanProbe: Cannot register the net_device context to the kernel\n");
eFailReason = NET_REGISTER_FAIL;
break;
}
/* 4 <4> Register early suspend callback */
#if CFG_ENABLE_EARLY_SUSPEND
glRegisterEarlySuspend(&wlan_early_suspend_desc,
wlan_early_suspend, wlan_late_resume);
#endif
/* 4 <5> Register Notifier callback */
wlanRegisterNotifier();
/* 4 <6> Initialize /proc filesystem */
#if WLAN_INCLUDE_PROC
i4Status = procCreateFsEntry(prGlueInfo);
if (i4Status < 0) {
DBGLOG(INIT, ERROR, "wlanProbe: init procfs failed\n");
eFailReason = PROC_INIT_FAIL;
break;
}
#endif /* WLAN_INCLUDE_PROC */
#if CFG_MET_PACKET_TRACE_SUPPORT
kalMetInit(prGlueInfo);
#endif
#if CFG_ENABLE_BT_OVER_WIFI
prGlueInfo->rBowInfo.fgIsNetRegistered = FALSE;
prGlueInfo->rBowInfo.fgIsRegistered = FALSE;
glRegisterAmpc(prGlueInfo);
#endif
#if (CFG_ENABLE_WIFI_DIRECT && CFG_MTK_ANDROID_WMT)
register_set_p2p_mode_handler(set_p2p_mode_handler);
#elif (CFG_ENABLE_WIFI_DIRECT)
if (prAdapter->rWifiVar.u4RegP2pIfAtProbe) {
struct PARAM_CUSTOM_P2P_SET_STRUCT rSetP2P;
rSetP2P.u4Enable = 1;
#ifdef CFG_DRIVER_INITIAL_RUNNING_MODE
rSetP2P.u4Mode = CFG_DRIVER_INITIAL_RUNNING_MODE;
#else
rSetP2P.u4Mode = RUNNING_P2P_MODE;
#endif /* CFG_DRIVER_RUNNING_MODE */
if (set_p2p_mode_handler(prWdev->netdev, rSetP2P) == 0)
DBGLOG(INIT, INFO,
"%s: p2p device registered\n",
__func__);
else
DBGLOG(INIT, ERROR,
"%s: Failed to register p2p device\n",
__func__);
}
#endif
#if (CFG_MET_PACKET_TRACE_SUPPORT == 1)
DBGLOG(INIT, TRACE, "init MET procfs...\n");
i4Status = kalMetInitProcfs(prGlueInfo);
if (i4Status < 0) {
DBGLOG(INIT, ERROR,
"wlanProbe: init MET procfs failed\n");
eFailReason = FAIL_MET_INIT_PROCFS;
break;
}
#endif
kalMemZero(&prGlueInfo->rFtIeForTx,
sizeof(prGlueInfo->rFtIeForTx));
/* Configure 5G band for registered wiphy */
if (prAdapter->fgEnable5GBand)
prWdev->wiphy->bands[KAL_BAND_5GHZ] = &mtk_band_5ghz;
else
prWdev->wiphy->bands[KAL_BAND_5GHZ] = NULL;
for (i = 0 ; i < KAL_P2P_NUM; i++) {
if (gprP2pRoleWdev[i] == NULL)
continue;
if (prAdapter->fgEnable5GBand)
gprP2pRoleWdev[i]->wiphy->bands[KAL_BAND_5GHZ] =
&mtk_band_5ghz;
else
gprP2pRoleWdev[i]->wiphy->bands[KAL_BAND_5GHZ] =
NULL;
}
} while (FALSE);
if (i4Status == 0) {
#if CFG_SUPPORT_AGPS_ASSIST
kalIndicateAgpsNotify(prAdapter, AGPS_EVENT_WLAN_ON, NULL,
0);
#endif
#if CFG_SUPPORT_EASY_DEBUG
/* move before reading file
* wlanLoadDefaultCustomerSetting(prAdapter);
*/
wlanFeatureToFw(prGlueInfo->prAdapter);
#endif
wlanCfgSetSwCtrl(prGlueInfo->prAdapter);
wlanCfgSetChip(prGlueInfo->prAdapter);
wlanCfgSetCountryCode(prGlueInfo->prAdapter);
kalPerMonInit(prGlueInfo);
#if CFG_MET_TAG_SUPPORT
if (met_tag_init() != 0)
DBGLOG(INIT, ERROR, "MET_TAG_INIT error!\n");
#endif
#if CFG_SUPPORT_CAL_RESULT_BACKUP_TO_HOST
/* Calibration Backup Flow */
if (!g_fgIsCalDataBackuped) {
if (rlmTriggerCalBackup(prGlueInfo->prAdapter,
g_fgIsCalDataBackuped) == WLAN_STATUS_FAILURE) {
DBGLOG(RFTEST, INFO,
"Error : Boot Time Wi-Fi Enable Fail........\n");
i4Status = -1;
goto WLAN_PROBE_RETURN;
}
g_fgIsCalDataBackuped = TRUE;
} else {
if (rlmTriggerCalBackup(prGlueInfo->prAdapter,
g_fgIsCalDataBackuped) == WLAN_STATUS_FAILURE) {
DBGLOG(RFTEST, INFO,
"Error : Normal Wi-Fi Enable Fail........\n");
i4Status = -1;
goto WLAN_PROBE_RETURN;
}
}
#endif
#if CFG_SUPPORT_REPLAY_DETECTION
ucRpyDetectOffload = prAdapter->rWifiVar.ucRpyDetectOffload;
if (ucRpyDetectOffload == FEATURE_ENABLED) {
DBGLOG(INIT, INFO,
"Send CMD to enable Replay Detection offload feature\n");
wlanSuspendRekeyOffload(prAdapter->prGlueInfo,
GTK_REKEY_CMD_MODE_RPY_OFFLOAD_ON);
} else {
DBGLOG(INIT, INFO,
"Send CMD to disable Replay Detection offload feature\n");
wlanSuspendRekeyOffload(prAdapter->prGlueInfo,
GTK_REKEY_CMD_MODE_RPY_OFFLOAD_OFF);
}
#endif
/* card is ready */
prGlueInfo->u4ReadyFlag = 1;
kalSetHalted(FALSE);
wlanDbgGetGlobalLogLevel(ENUM_WIFI_LOG_MODULE_FW,
&u4LogLevel);
if (u4LogLevel > ENUM_WIFI_LOG_LEVEL_DEFAULT)
wlanDbgSetLogLevelImpl(prAdapter,
ENUM_WIFI_LOG_LEVEL_VERSION_V1,
ENUM_WIFI_LOG_MODULE_FW,
u4LogLevel);
#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH
/* sync log status with firmware */
if (u4LogOnOffCache != -1) /* -1: connsysD does not set */
consys_log_event_notification((int)FW_LOG_CMD_ON_OFF,
u4LogOnOffCache);
#endif
#if CFG_SUPPORT_TPENHANCE_MODE
wlanTpeInit(prGlueInfo);
#endif /* CFG_SUPPORT_TPENHANCE_MODE */
DBGLOG(INIT, STATE, "wlanProbe: probe success\n");
#if CFG_CHIP_RESET_HANG
if (fgIsResetHangState == SER_L0_HANG_RST_TRGING) {
DBGLOG(INIT, STATE, "[SER][L0] SET SQC hang!\n");
fgIsResetHangState = SER_L0_HANG_RST_HANG;
fgIsResetting = TRUE;
}
#endif
} else {
DBGLOG(INIT, ERROR, "wlanProbe: probe failed, reason:%d\n",
eFailReason);
switch (eFailReason) {
case FAIL_MET_INIT_PROCFS:
#if WLAN_INCLUDE_PROC
procRemoveProcfs();
#endif
kal_fallthrough;
case PROC_INIT_FAIL:
wlanUnregisterNotifier();
#if CFG_ENABLE_EARLY_SUSPEND
glUnregisterEarlySuspend(&wlan_early_suspend_desc);
#endif
wlanNetUnregister(prWdev);
kal_fallthrough;
case NET_REGISTER_FAIL:
set_bit(GLUE_FLAG_HALT_BIT, &prGlueInfo->ulFlag);
/* wake up main thread */
wake_up_interruptible(&prGlueInfo->waitq);
/* wait main thread stops */
wait_for_completion_interruptible(
&prGlueInfo->rHaltComp);
wlanAdapterStop(prAdapter);
kal_fallthrough;
case ADAPTER_START_FAIL:
glBusFreeIrq(prWdev->netdev,
*((struct GLUE_INFO **)
netdev_priv(prWdev->netdev)));
kal_fallthrough;
case BUS_SET_IRQ_FAIL:
wlanWakeLockUninit(prGlueInfo);
wlanNetDestroy(prWdev);
/* prGlueInfo->prAdapter is released in
* wlanNetDestroy
*/
/* Set NULL value for local prAdapter as well */
prAdapter = NULL;
break;
case NET_CREATE_FAIL:
break;
case BUS_INIT_FAIL:
break;
default:
break;
}
}
#if CFG_THERMAL_API_SUPPORT
if (i4Status == 0)
g_fgIsWifiEnabled = TRUE;
pbridge.thermal_query_cb = mtk_wcn_temp_query_ctrl;
wcn_export_platform_bridge_register(&pbridge);
#endif
/* i4Status is necessary before goto WLAN_PROBE_RETURN */
WLAN_PROBE_RETURN:
#if CFG_CHIP_RESET_SUPPORT
#if CFG_CHIP_RESET_KO_SUPPORT
if (i4Status == 0)
send_reset_event(RESET_MODULE_TYPE_WIFI,
RFSM_EVENT_PROBE_SUCCESS);
else
send_reset_event(RESET_MODULE_TYPE_WIFI,
RFSM_EVENT_PROBE_FAIL);
#endif
#endif
return i4Status;
} /* end of wlanProbe() */
/*----------------------------------------------------------------------------*/
/*!
* \brief A method to stop driver operation and release all resources. Following
* this call, no frame should go up or down through this interface.
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
static void wlanRemove(void)
{
struct net_device *prDev = NULL;
struct WLANDEV_INFO *prWlandevInfo = NULL;
struct GLUE_INFO *prGlueInfo = NULL;
struct ADAPTER *prAdapter = NULL;
u_int8_t fgResult = FALSE;
DBGLOG(INIT, STATE, "Remove wlan!\n");
kalSetHalted(TRUE);
/* 4 <0> Sanity check */
ASSERT(u4WlanDevNum <= CFG_MAX_WLAN_DEVICES);
if (u4WlanDevNum == 0) {
DBGLOG(INIT, ERROR, "u4WlanDevNum = 0\n");
goto WLAN_REMOVE_RETURN;
}
#if (CFG_ENABLE_WIFI_DIRECT && CFG_MTK_ANDROID_WMT)
register_set_p2p_mode_handler(NULL);
#endif
if (u4WlanDevNum > 0
&& u4WlanDevNum <= CFG_MAX_WLAN_DEVICES) {
prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev;
prWlandevInfo = &arWlanDevInfo[u4WlanDevNum - 1];
}
ASSERT(prDev);
if (prDev == NULL) {
DBGLOG(INIT, ERROR, "prDev is NULL\n");
goto WLAN_REMOVE_RETURN;
}
prGlueInfo = *((struct GLUE_INFO **) netdev_priv(prDev));
ASSERT(prGlueInfo);
if (prGlueInfo == NULL) {
DBGLOG(INIT, STATE, "prGlueInfo is NULL\n");
free_netdev(prDev);
goto WLAN_REMOVE_RETURN;
}
/* to avoid that wpa_supplicant/hostapd triogger new cfg80211 command */
prGlueInfo->u4ReadyFlag = 0;
/* Have tried to do scan done here, but the exception occurs for */
/* the P2P scan. Keep the original design that scan done in the */
/* p2pStop/wlanStop. */
#if WLAN_INCLUDE_PROC
procRemoveProcfs();
#endif /* WLAN_INCLUDE_PROC */
prAdapter = prGlueInfo->prAdapter;
kalPerMonDestroy(prGlueInfo);
#if CFG_SUPPORT_TPENHANCE_MODE
wlanTpeUninit(prGlueInfo);
#endif /* CFG_SUPPORT_TPENHANCE_MODE */
#if CFG_SUPPORT_SER
#if defined(_HIF_USB)
cnmTimerStopTimer(prAdapter, &prAdapter->rSerSyncTimer);
#endif /* _HIF_USB */
#endif /* CFG_SUPPORT_SER */
/* complete possible pending oid, which may block wlanRemove some time
* and then whole chip reset may failed
*/
if (kalIsResetting())
wlanReleasePendingOid(prGlueInfo->prAdapter, 1);
#if CFG_ENABLE_BT_OVER_WIFI
if (prGlueInfo->rBowInfo.fgIsNetRegistered) {
bowNotifyAllLinkDisconnected(prGlueInfo->prAdapter);
/* wait 300ms for BoW module to send deauth */
kalMsleep(300);
}
#endif
if (prGlueInfo->eParamMediaStateIndicated ==
PARAM_MEDIA_STATE_CONNECTED) {
#if CFG_WPS_DISCONNECT || (KERNEL_VERSION(4, 2, 0) <= CFG80211_VERSION_CODE)
cfg80211_disconnected(prGlueInfo->prDevHandler, 0, NULL, 0,
TRUE, GFP_KERNEL);
#else
cfg80211_disconnected(prGlueInfo->prDevHandler, 0, NULL, 0,
GFP_KERNEL);
#endif
kalMsleep(500);
}
flush_delayed_work(&workq);
/* 20150205 work queue for sched_scan */
flush_delayed_work(&sched_workq);
#if CFG_SUPPORT_CFG80211_AUTH
#if CFG_SUPPORT_CFG80211_QUEUE
flush_delayed_work(&cfg80211_workq);
#endif
#endif
#if IS_ENABLED(CFG_CCN7_SAP_EASYMESH)
cancel_delayed_work_sync(&prAdapter->prGlueInfo->rChanNoiseControlWork);
cancel_delayed_work_sync(&prAdapter->prGlueInfo->rChanNoiseGetInfoWork);
#endif
down(&g_halt_sem);
g_u4HaltFlag = 1;
up(&g_halt_sem);
/* 4 <2> Mark HALT, notify main thread to stop, and clean up queued
* requests
*/
smp_mb();
set_bit(GLUE_FLAG_HALT_BIT, &prGlueInfo->ulFlag);
/* Stop works */
flush_work(&prGlueInfo->rTxMsduFreeWork);
cancel_delayed_work_sync(&prGlueInfo->rRxPktDeAggWork);
#if CFG_SUPPORT_MULTITHREAD
smp_mb();
wake_up_interruptible(&prGlueInfo->waitq_hif);
wait_for_completion_interruptible(
&prGlueInfo->rHifHaltComp);
HAL_AGG_THREAD_WAKE_UP(prGlueInfo->prAdapter);
#if CFG_SDIO_RX_DE_AGG_IN_THREAD
wake_up_interruptible(&prGlueInfo->waitq_rxDeAgg);
wait_for_completion_interruptible(&prGlueInfo->rxDeAggHaltComp);
#endif
wake_up_interruptible(&prGlueInfo->waitq_rx);
wait_for_completion_interruptible(&prGlueInfo->rRxHaltComp);
#endif
/* wake up main thread */
wake_up_interruptible(&prGlueInfo->waitq);
/* wait main thread stops */
wait_for_completion_interruptible(&prGlueInfo->rHaltComp);
DBGLOG(INIT, INFO, "wlan thread stopped\n");
/* prGlueInfo->rHifInfo.main_thread = NULL; */
prGlueInfo->main_thread = NULL;
#if CFG_SUPPORT_MULTITHREAD
prGlueInfo->hif_thread = NULL;
prGlueInfo->rx_thread = NULL;
#if CFG_SDIO_RX_DE_AGG_IN_THREAD
prGlueInfo->rx_DeAgg_thread = NULL;
#endif
prGlueInfo->u4TxThreadPid = 0xffffffff;
prGlueInfo->u4HifThreadPid = 0xffffffff;
#endif
if (HAL_IS_TX_DIRECT(prAdapter)) {
if (prAdapter->fgTxDirectInited) {
del_timer_sync(&prAdapter->rTxDirectSkbTimer);
del_timer_sync(&prAdapter->rTxDirectHifTimer);
}
}
/* Destroy wakelock */
wlanWakeLockUninit(prGlueInfo);
kalMemSet(&(prGlueInfo->prAdapter->rWlanInfo), 0,
sizeof(struct WLAN_INFO));
#if CFG_ENABLE_WIFI_DIRECT
if (prGlueInfo->prAdapter->fgIsP2PRegistered) {
DBGLOG(INIT, INFO, "p2pNetUnregister...\n");
p2pNetUnregister(prGlueInfo, FALSE);
DBGLOG(INIT, INFO, "p2pRemove...\n");
/*p2pRemove must before wlanAdapterStop */
p2pRemove(prGlueInfo);
}
#endif
#if CFG_ENABLE_BT_OVER_WIFI
if (prGlueInfo->rBowInfo.fgIsRegistered)
glUnregisterAmpc(prGlueInfo);
#endif
#if (CFG_MET_PACKET_TRACE_SUPPORT == 1)
kalMetRemoveProcfs();
#endif
#if CFG_MET_TAG_SUPPORT
if (GL_MET_TAG_UNINIT() != 0)
DBGLOG(INIT, ERROR, "MET_TAG_UNINIT error!\n");
#endif
/* 4 <4> wlanAdapterStop */
#if CFG_SUPPORT_AGPS_ASSIST
kalIndicateAgpsNotify(prAdapter, AGPS_EVENT_WLAN_OFF, NULL,
0);
#endif
wlanAdapterStop(prAdapter);
HAL_LP_OWN_SET(prAdapter, &fgResult);
DBGLOG(INIT, INFO, "HAL_LP_OWN_SET(%d)\n",
(uint32_t) fgResult);
/* 4 <x> Stopping handling interrupt and free IRQ */
glBusFreeIrq(prDev, prGlueInfo);
/* 4 <5> Release the Bus */
glBusRelease(prDev);
#if (CFG_SUPPORT_TRACE_TC4 == 1)
wlanDebugTC4Uninit();
#endif
/* 4 <6> Unregister the card */
wlanNetUnregister(prDev->ieee80211_ptr);
/* 4 <7> Destroy the device */
wlanNetDestroy(prDev->ieee80211_ptr);
prDev = NULL;
tasklet_kill(&prGlueInfo->rTxCompleteTask);
tasklet_kill(&prGlueInfo->rRxTask);
/* 4 <8> Unregister early suspend callback */
#if CFG_ENABLE_EARLY_SUSPEND
glUnregisterEarlySuspend(&wlan_early_suspend_desc);
#endif
gprWdev->netdev = NULL;
/* 4 <9> Unregister notifier callback */
wlanUnregisterNotifier();
#if CFG_CHIP_RESET_SUPPORT & !CFG_WMT_RESET_API_SUPPORT
fgIsResetting = FALSE;
fgIsResetTrigger = FALSE;
fgIsBtTriggered = FALSE;
#endif
#if CFG_THERMAL_API_SUPPORT
g_fgIsWifiEnabled = FALSE;
wcn_export_platform_bridge_unregister();
#endif
WLAN_REMOVE_RETURN:
#if CFG_CHIP_RESET_SUPPORT
#if CFG_CHIP_RESET_KO_SUPPORT
send_reset_event(RESET_MODULE_TYPE_WIFI, RFSM_EVENT_REMOVE);
#endif
#endif
DBGLOG(INIT, STATE, "end\n");
} /* end of wlanRemove() */
/*----------------------------------------------------------------------------*/
/*!
* \brief Driver entry point when the driver is configured as a Linux Module,
* and is called once at module load time, by the user-level modutils
* application: insmod or modprobe.
*
* \retval 0 Success
*/
/*----------------------------------------------------------------------------*/
/* 1 Module Entry Point */
static int initWlan(void)
{
int ret = 0;
struct GLUE_INFO *prGlueInfo = NULL;
DBGLOG(INIT, INFO, "initWlan\n");
#if (CFG_CHIP_RESET_SUPPORT)
#if CFG_CHIP_RESET_KO_SUPPORT
resetko_register_module(RESET_MODULE_TYPE_WIFI,
"wifi",
TRIGGER_RESET_TYPE_GPIO_API,
resetkoReset,
resetkoNotifyFunc);
#endif /* CFG_CHIP_RESET_KO_SUPPORT */
#endif /* CFG_CHIP_RESET_SUPPORT */
#ifdef CFG_DRIVER_INF_NAME_CHANGE
if (kalStrLen(gprifnamesta) > CUSTOM_IFNAMESIZ ||
kalStrLen(gprifnamep2p) > CUSTOM_IFNAMESIZ ||
kalStrLen(gprifnameap) > CUSTOM_IFNAMESIZ) {
DBGLOG(INIT, ERROR, "custom infname len illegal > %d\n",
CUSTOM_IFNAMESIZ);
ret = -EINVAL;
goto INIT_WLAN_RETURN;
}
#endif /* CFG_DRIVER_INF_NAME_CHANGE */
wlanDebugInit();
/* memory pre-allocation */
#if CFG_PRE_ALLOCATION_IO_BUFFER
kalInitIOBuffer(TRUE);
#else
kalInitIOBuffer(FALSE);
#endif
#if WLAN_INCLUDE_PROC
procInitFs();
#endif
wlanCreateWirelessDevice();
if (gprWdev == NULL) {
ret = -ENOMEM;
goto INIT_WLAN_RETURN;
}
prGlueInfo = (struct GLUE_INFO *) wiphy_priv(
gprWdev->wiphy);
if (gprWdev) {
/* P2PDev and P2PRole[0] share the same Wdev */
if (glP2pCreateWirelessDevice(prGlueInfo) == TRUE)
gprP2pWdev = gprP2pRoleWdev[0];
}
gPrDev = NULL;
/* For DTV Ref project -> Default enable */
#if CFG_DC_USB_WOW_CALLBACK
/* register system DC wow enable/disable callback function */
do {
typedef void (*func_ptr) (int (*f) (void));
char *func_name = "WifiRegisterPdwncCallback";
func_ptr pFunc =
(func_ptr)kal_kallsyms_lookup_name(func_name);
char *func_name2 = "RegisterPdwncCallbackWifi";
func_ptr pFunc2 =
(func_ptr)kal_kallsyms_lookup_name(func_name2);
if (pFunc) {
DBGLOG(INIT, ERROR,
"Register Wow callback1 success\n");
pFunc(&kalDcSetWow);
} else if (pFunc2) {
DBGLOG(INIT, ERROR,
"Register Wow callback2 success\n");
pFunc2(&kalDcSetWow);
} else
DBGLOG(INIT, ERROR,
"No Exported Func Found:%s\n",
func_name);
} while (0);
#endif
#if (CFG_CHIP_RESET_SUPPORT)
glResetInit(prGlueInfo);
#endif
ret = ((glRegisterBus(wlanProbe,
wlanRemove) == WLAN_STATUS_SUCCESS) ? 0 : -EIO);
if (ret == -EIO) {
kalUninitIOBuffer();
goto INIT_WLAN_RETURN;
}
kalFbNotifierReg((struct GLUE_INFO *) wiphy_priv(
gprWdev->wiphy));
#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH
wifi_fwlog_event_func_register(consys_log_event_notification);
#endif
#if CFG_MTK_ANDROID_EMI
/* Set WIFI EMI protection to consys permitted on system boot up */
kalSetEmiMpuProtection(gConEmiPhyBase, WIFI_EMI_MEM_OFFSET,
WIFI_EMI_MEM_SIZE, true);
#endif
#if CFG_POWER_OFF_CTRL_SUPPORT
wlanRegisterRebootNotifier();
#endif
#if IS_ENABLED(CFG_CCN7_SAP_EASYMESH)
nl_sk = netlink_kernel_create(&init_net, NETLINK_OSS_KERNEL, NULL);
if (!nl_sk) {
DBGLOG(INIT, ERROR, "netlink create failed!\n");
goto INIT_WLAN_RETURN;
}
#endif /* CFG_CCN7_SAP_EASYMESH */
/* ret is necessary before goto INIT_WLAN_RETURN */
INIT_WLAN_RETURN:
#if CFG_CHIP_RESET_SUPPORT
#if CFG_CHIP_RESET_KO_SUPPORT
if (ret)
resetko_unregister_module(RESET_MODULE_TYPE_WIFI);
#endif /* CFG_CHIP_RESET_KO_SUPPORT */
#endif /* CFG_CHIP_RESET_SUPPORT */
return ret;
} /* end of initWlan() */
/*----------------------------------------------------------------------------*/
/*!
* \brief Driver exit point when the driver as a Linux Module is removed. Called
* at module unload time, by the user level modutils application: rmmod.
* This is our last chance to clean up after ourselves.
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
/* 1 Module Leave Point */
static void exitWlan(void)
{
#if IS_ENABLED(CFG_CCN7_SAP_EASYMESH)
if (nl_sk != NULL)
netlink_kernel_release(nl_sk);
#endif /* CFG_CCN7_SAP_EASYMESH */
kalFbNotifierUnReg();
#if CFG_CHIP_RESET_SUPPORT
glResetUninit();
#endif
glUnregisterBus(wlanRemove);
/* For DTV Ref project -> Default enable */
#if CFG_DC_USB_WOW_CALLBACK
/*Unregister system DC wow enable/disable callback function */
do {
typedef void (*func_ptr) (int (*f) (void));
char *func_name = "WifiRegisterPdwncCallback";
func_ptr pFunc =
(func_ptr)kal_kallsyms_lookup_name(func_name);
char *func_name2 = "RegisterPdwncCallbackWifi";
func_ptr pFunc2 =
(func_ptr)kal_kallsyms_lookup_name(func_name2);
if (pFunc) {
DBGLOG(INIT, STATE,
"Unregister Wow callback1 success\n");
pFunc(NULL);
} else if (pFunc2) {
DBGLOG(INIT, STATE,
"Unregister Wow callback2 success\n");
pFunc2(NULL);
} else
DBGLOG(INIT, ERROR,
"No Exported Func Found:%s\n",
func_name);
} while (0);
#endif
/* free pre-allocated memory */
kalUninitIOBuffer();
wlanDestroyAllWdev();
#if WLAN_INCLUDE_PROC
procUninitProcFs();
#endif
#if CFG_POWER_OFF_CTRL_SUPPORT
wlanUnregisterRebootNotifier();
#endif
#if CFG_CHIP_RESET_SUPPORT
#if CFG_CHIP_RESET_KO_SUPPORT
resetko_unregister_module(RESET_MODULE_TYPE_WIFI);
#endif /* CFG_CHIP_RESET_KO_SUPPORT */
#endif /* CFG_CHIP_RESET_SUPPORT */
DBGLOG(INIT, INFO, "exitWlan\n");
} /* end of exitWlan() */
#if CFG_POWER_OFF_CTRL_SUPPORT
static int wf_pdwnc_notify(struct notifier_block *nb,
unsigned long event, void *unused)
{
if (event == SYS_RESTART) {
DBGLOG(HAL, STATE, "wf_pdwnc_notify()\n");
kalFbNotifierUnReg();
#if CFG_CHIP_RESET_SUPPORT
glResetUninit();
#endif
glUnregisterBus(wlanRemove);
/* free pre-allocated memory */
kalUninitIOBuffer();
wlanDestroyAllWdev();
#if WLAN_INCLUDE_PROC
procUninitProcFs();
#endif
DBGLOG(HAL, STATE, "wf_pdwnc_notify() done\n");
}
if (event == SYS_POWER_OFF || event == SYS_HALT) {
DBGLOG(HAL, STATE, "DC Set WoW\n");
kalDcSetWow();
}
return 0;
}
static struct notifier_block wf_pdwnc_notifier = {
.notifier_call = wf_pdwnc_notify,
.next = NULL,
.priority = 0,
};
void wlanRegisterRebootNotifier(void)
{
DBGLOG(HAL, STATE, "wlanRegisterRebootNotifier()\n");
register_reboot_notifier(&wf_pdwnc_notifier);
DBGLOG(HAL, STATE, "wlanRegisterRebootNotifier() done\n");
}
void wlanUnregisterRebootNotifier(void)
{
DBGLOG(HAL, STATE, "wlanUnregisterRebootNotifier()\n");
unregister_reboot_notifier(&wf_pdwnc_notifier);
DBGLOG(HAL, STATE, "wlanUnregisterRebootNotifier() done\n");
}
#endif
#if CFG_THERMAL_API_SUPPORT
/*----------------------------------------------------------------------------*/
/*!
* \brief export API for thermal
*
* \retval >0 Success
* \retval -1000 invalid
*/
/*----------------------------------------------------------------------------*/
static int mtk_wcn_temp_query_ctrl(void)
{
struct net_device *prDev = NULL;
struct GLUE_INFO *prGlueInfo = NULL;
struct ADAPTER *prAdapter = NULL;
int i4Temperature = 0;
#ifdef CFG_GET_TEMPURATURE
uint32_t u4BufLen;
uint32_t rStatus = WLAN_STATUS_SUCCESS;
#endif
/* 1. check if wifi is enabled */
if (!g_fgIsWifiEnabled)
return -1000;
ASSERT(u4WlanDevNum <= CFG_MAX_WLAN_DEVICES);
if (u4WlanDevNum == 0) {
DBGLOG(INIT, INFO, "0 == u4WlanDevNum\n");
return -1000;
}
if (u4WlanDevNum > 0 && u4WlanDevNum <= CFG_MAX_WLAN_DEVICES)
prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev;
ASSERT(prDev);
if (prDev == NULL) {
DBGLOG(INIT, INFO, "NULL == prDev\n");
return -1000;
}
prGlueInfo = *((struct GLUE_INFO **) netdev_priv(prDev));
ASSERT(prGlueInfo);
if (prGlueInfo == NULL) {
DBGLOG(INIT, INFO, "NULL == prGlueInfo\n");
return -1000;
}
prAdapter = prGlueInfo->prAdapter;
ASSERT(prAdapter);
#ifdef CFG_GET_TEMPURATURE
rStatus = kalIoctl(prGlueInfo,
wlanoidGetTemperature,
&i4Temperature,
sizeof(i4Temperature),
TRUE, TRUE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, ERROR, "Query ucTemperature failed!\n");
return -1000;
}
#else
return -1000;
#endif
return i4Temperature;
}
#endif
#if ((MTK_WCN_HIF_SDIO == 1) && (CFG_BUILT_IN_DRIVER == 1)) || \
((MTK_WCN_HIF_AXI == 1) && (CFG_BUILT_IN_DRIVER == 1))
int mtk_wcn_wlan_gen4_init(void)
{
return initWlan();
}
EXPORT_SYMBOL(mtk_wcn_wlan_gen4_init);
void mtk_wcn_wlan_gen4_exit(void)
{
return exitWlan();
}
EXPORT_SYMBOL(mtk_wcn_wlan_gen4_exit);
#elif ((MTK_WCN_HIF_SDIO == 0) && (CFG_BUILT_IN_DRIVER == 1))
device_initcall(initWlan);
#else
module_init(initWlan);
module_exit(exitWlan);
#endif