18d6344f9Sopenharmony_ci/*
28d6344f9Sopenharmony_ci * hdfinit_bdh.c
38d6344f9Sopenharmony_ci *
48d6344f9Sopenharmony_ci * hdf driver
58d6344f9Sopenharmony_ci *
68d6344f9Sopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
78d6344f9Sopenharmony_ci *
88d6344f9Sopenharmony_ci * This program is free software; you can redistribute it and/or
98d6344f9Sopenharmony_ci * modify it under the terms of the GNU General Public License
108d6344f9Sopenharmony_ci * as published by the Free Software Foundation; either version 2
118d6344f9Sopenharmony_ci * of the License, or (at your option) any later version.
128d6344f9Sopenharmony_ci *
138d6344f9Sopenharmony_ci * This program is distributed in the hope that it will be useful,
148d6344f9Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
158d6344f9Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
168d6344f9Sopenharmony_ci * GNU General Public License for more details.
178d6344f9Sopenharmony_ci *
188d6344f9Sopenharmony_ci * You should have received a copy of the GNU General Public License
198d6344f9Sopenharmony_ci * along with this program; if not, write to the Free Software
208d6344f9Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
218d6344f9Sopenharmony_ci */
228d6344f9Sopenharmony_ci
238d6344f9Sopenharmony_ci#include <uapi/linux/nl80211.h>
248d6344f9Sopenharmony_ci#include <securec.h>
258d6344f9Sopenharmony_ci#include <asm/byteorder.h>
268d6344f9Sopenharmony_ci#include <linux/kernel.h>
278d6344f9Sopenharmony_ci
288d6344f9Sopenharmony_ci#include "hdf_wifi_product.h"
298d6344f9Sopenharmony_ci#include "wifi_mac80211_ops.h"
308d6344f9Sopenharmony_ci#include "hdf_wlan_utils.h"
318d6344f9Sopenharmony_ci#include "hdf_wl_interface.h"
328d6344f9Sopenharmony_ci#include "net_bdh_adpater.h"
338d6344f9Sopenharmony_ci#include "hdf_public_ap6275s.h"
348d6344f9Sopenharmony_ci#include "eapol.h"
358d6344f9Sopenharmony_ci
368d6344f9Sopenharmony_ci#define HDF_LOG_TAG BDH6Driver
378d6344f9Sopenharmony_ciint hdf_cfgp2p_register_ndev(struct net_device *p2p_netdev, struct net_device *primary_netdev, struct wiphy *wiphy);
388d6344f9Sopenharmony_ciint dhd_module_init(void);
398d6344f9Sopenharmony_civoid dhd_module_exit(void);
408d6344f9Sopenharmony_cistruct bcm_cfg80211;
418d6344f9Sopenharmony_cis32 wl_get_vif_macaddr(struct bcm_cfg80211 *cfg, u16 wl_iftype, u8 *mac_addr);
428d6344f9Sopenharmony_ci
438d6344f9Sopenharmony_cistruct NetDeviceInterFace *wal_get_net_p2p_ops(void);
448d6344f9Sopenharmony_cistruct hdf_inf_map g_hdf_infmap[HDF_INF_MAX];
458d6344f9Sopenharmony_ci
468d6344f9Sopenharmony_ciint g_hdf_ifidx = HDF_INF_WLAN0;
478d6344f9Sopenharmony_ciint g_event_ifidx = HDF_INF_WLAN0;
488d6344f9Sopenharmony_ciint g_scan_event_ifidx = HDF_INF_WLAN0;
498d6344f9Sopenharmony_ciint g_conn_event_ifidx = HDF_INF_WLAN0;
508d6344f9Sopenharmony_ciint g_mgmt_tx_event_ifidx = HDF_INF_P2P0;
518d6344f9Sopenharmony_ciint bdh6_reset_driver_flag = 0;
528d6344f9Sopenharmony_ci
538d6344f9Sopenharmony_ci// BDH Wifi6 chip driver init
548d6344f9Sopenharmony_ciint32_t InitBDH6Chip(struct HdfWlanDevice *device)
558d6344f9Sopenharmony_ci{
568d6344f9Sopenharmony_ci    (void)device;
578d6344f9Sopenharmony_ci    HDF_LOGW("bdh6: call InitBDH6Chip");
588d6344f9Sopenharmony_ci    return HDF_SUCCESS;
598d6344f9Sopenharmony_ci}
608d6344f9Sopenharmony_ci
618d6344f9Sopenharmony_ciint32_t DeinitBDH6Chip(struct HdfWlanDevice *device)
628d6344f9Sopenharmony_ci{
638d6344f9Sopenharmony_ci    int32_t ret = HDF_SUCCESS;
648d6344f9Sopenharmony_ci    (void)device;
658d6344f9Sopenharmony_ci    if (ret != 0) {
668d6344f9Sopenharmony_ci        HDF_LOGE("%s:Deinit failed!ret=%d", __func__, ret);
678d6344f9Sopenharmony_ci    }
688d6344f9Sopenharmony_ci    return ret;
698d6344f9Sopenharmony_ci}
708d6344f9Sopenharmony_ci
718d6344f9Sopenharmony_cistatic void HdfInfMapInit(void)
728d6344f9Sopenharmony_ci{
738d6344f9Sopenharmony_ci    int32_t i = 0;
748d6344f9Sopenharmony_ci
758d6344f9Sopenharmony_ci    memset_s(g_hdf_infmap, sizeof(g_hdf_infmap), 0, sizeof(g_hdf_infmap));
768d6344f9Sopenharmony_ci    for (i = 0; i < HDF_INF_MAX; i ++) {
778d6344f9Sopenharmony_ci        INIT_WORK(&g_hdf_infmap[i].eapolEvent.eapol_report, eapol_report_handler);
788d6344f9Sopenharmony_ci        NetBufQueueInit(&g_hdf_infmap[i].eapolEvent.eapolQueue);
798d6344f9Sopenharmony_ci        g_hdf_infmap[i].eapolEvent.idx = i;
808d6344f9Sopenharmony_ci    }
818d6344f9Sopenharmony_ci    g_hdf_ifidx = HDF_INF_WLAN0; // master interface
828d6344f9Sopenharmony_ci}
838d6344f9Sopenharmony_ci
848d6344f9Sopenharmony_ci#define WIFI_IMAGE_FILE_NAME "/vendor/etc/firmware/fw_bcm43752a2_ag.bin"
858d6344f9Sopenharmony_ci#define CK_WF_IMG_MAX_CNT 2
868d6344f9Sopenharmony_ci#define  CK_WF_IMG_DELAY_MS 500
878d6344f9Sopenharmony_ciint32_t CheckWiFiImageFile(const char *filename)
888d6344f9Sopenharmony_ci{
898d6344f9Sopenharmony_ci    struct file *fp = NULL;
908d6344f9Sopenharmony_ci    int32_t icnt = 0;
918d6344f9Sopenharmony_ci
928d6344f9Sopenharmony_ci    while (icnt ++ <= CK_WF_IMG_MAX_CNT) {
938d6344f9Sopenharmony_ci        fp = filp_open(filename, O_RDONLY, 0);
948d6344f9Sopenharmony_ci        if (IS_ERR(fp)) {
958d6344f9Sopenharmony_ci            HDF_LOGE("%s:open %s failed, cnt=%d, error=%d", __func__, filename, icnt, PTR_ERR(fp));
968d6344f9Sopenharmony_ci            fp = NULL;
978d6344f9Sopenharmony_ci            OsalMSleep(CK_WF_IMG_DELAY_MS);
988d6344f9Sopenharmony_ci        } else {
998d6344f9Sopenharmony_ci            filp_close(fp, NULL);
1008d6344f9Sopenharmony_ci            fp = NULL;
1018d6344f9Sopenharmony_ci            HDF_LOGE("%s:open %s success, cnt=%d", __func__, filename, icnt);
1028d6344f9Sopenharmony_ci            return 0;
1038d6344f9Sopenharmony_ci        }
1048d6344f9Sopenharmony_ci    }
1058d6344f9Sopenharmony_ci
1068d6344f9Sopenharmony_ci    HDF_LOGE("%s:open %s failed, cnt=%d reach to max times", __func__, filename, icnt);
1078d6344f9Sopenharmony_ci    return -1;
1088d6344f9Sopenharmony_ci}
1098d6344f9Sopenharmony_ci
1108d6344f9Sopenharmony_cistatic int32_t InitPrimaryInterface(struct NetDevice *netDevice, struct net_device *netdev)
1118d6344f9Sopenharmony_ci{
1128d6344f9Sopenharmony_ci    int32_t ret = 0;
1138d6344f9Sopenharmony_ci    int32_t private_data_size = 0;
1148d6344f9Sopenharmony_ci    struct HdfWifiNetDeviceData *data = NULL;
1158d6344f9Sopenharmony_ci    // Init primary interface wlan0
1168d6344f9Sopenharmony_ci
1178d6344f9Sopenharmony_ci    data = GetPlatformData(netDevice);
1188d6344f9Sopenharmony_ci    if (data == NULL) {
1198d6344f9Sopenharmony_ci        HDF_LOGE("%s:netdevice data null!", __func__);
1208d6344f9Sopenharmony_ci        return HDF_FAILURE;
1218d6344f9Sopenharmony_ci    }
1228d6344f9Sopenharmony_ci
1238d6344f9Sopenharmony_ci    hdf_bdh6_netdev_init(netDevice);
1248d6344f9Sopenharmony_ci    netDevice->classDriverPriv = data;
1258d6344f9Sopenharmony_ci    private_data_size = get_dhd_priv_data_size(); // create bdh6 private object
1268d6344f9Sopenharmony_ci    netDevice->mlPriv = kzalloc(private_data_size, GFP_KERNEL);
1278d6344f9Sopenharmony_ci    if (netDevice->mlPriv == NULL) {
1288d6344f9Sopenharmony_ci        HDF_LOGE("%s:kzalloc mlPriv failed", __func__);
1298d6344f9Sopenharmony_ci        return HDF_FAILURE;
1308d6344f9Sopenharmony_ci    }
1318d6344f9Sopenharmony_ci
1328d6344f9Sopenharmony_ci    set_krn_netdev(netDevice, netdev, g_hdf_ifidx);
1338d6344f9Sopenharmony_ci    dhd_module_init();
1348d6344f9Sopenharmony_ci    return HDF_SUCCESS;
1358d6344f9Sopenharmony_ci}
1368d6344f9Sopenharmony_ci
1378d6344f9Sopenharmony_cistatic int32_t InitP2pInterface(struct NetDevice *netDevice, struct net_device *netdev)
1388d6344f9Sopenharmony_ci{
1398d6344f9Sopenharmony_ci    int32_t ret = 0;
1408d6344f9Sopenharmony_ci    struct wiphy *wiphy = NULL;
1418d6344f9Sopenharmony_ci    struct net_device *p2p_netdev = NULL;
1428d6344f9Sopenharmony_ci    struct NetDevice *p2p_hnetdev = NULL;
1438d6344f9Sopenharmony_ci    struct bcm_cfg80211 *cfg = NULL;
1448d6344f9Sopenharmony_ci    WifiIfAdd ifAdd;
1458d6344f9Sopenharmony_ci
1468d6344f9Sopenharmony_ci    memset_s(&ifAdd, sizeof(ifAdd), 0, sizeof(ifAdd));
1478d6344f9Sopenharmony_ci    if (snprintf_s(ifAdd.ifName, IFNAMSIZ, IFNAMSIZ - 1, "p2p%d", 0) < 0) {
1488d6344f9Sopenharmony_ci        HDF_LOGE("%s:format ifName failed!", __func__);
1498d6344f9Sopenharmony_ci        return HDF_FAILURE;
1508d6344f9Sopenharmony_ci    }
1518d6344f9Sopenharmony_ci
1528d6344f9Sopenharmony_ci    ifAdd.type = NL80211_IFTYPE_P2P_DEVICE;
1538d6344f9Sopenharmony_ci    // Init interface p2p0
1548d6344f9Sopenharmony_ci    ret = P2pInitNetdev(netDevice, &ifAdd, sizeof(void *), HDF_INF_P2P0);
1558d6344f9Sopenharmony_ci    if (ret != 0) {
1568d6344f9Sopenharmony_ci        HDF_LOGE("%s:P2pInitNetdev %s failed", __func__, ifAdd.ifName);
1578d6344f9Sopenharmony_ci        return HDF_FAILURE;
1588d6344f9Sopenharmony_ci    }
1598d6344f9Sopenharmony_ci    wiphy = get_linux_wiphy_ndev(netdev);
1608d6344f9Sopenharmony_ci    if (wiphy == NULL) {
1618d6344f9Sopenharmony_ci        HDF_LOGE("%s:get wlan0 wiphy failed", __func__);
1628d6344f9Sopenharmony_ci        return HDF_FAILURE;
1638d6344f9Sopenharmony_ci    }
1648d6344f9Sopenharmony_ci    p2p_hnetdev = get_hdf_netdev(g_hdf_ifidx);
1658d6344f9Sopenharmony_ci    p2p_netdev = get_krn_netdev(g_hdf_ifidx);
1668d6344f9Sopenharmony_ci    p2p_netdev->ieee80211_ptr = NULL;
1678d6344f9Sopenharmony_ci    p2p_hnetdev->ieee80211Ptr = p2p_netdev->ieee80211_ptr;
1688d6344f9Sopenharmony_ci    cfg = wiphy_priv(wiphy);  // update mac from wdev address
1698d6344f9Sopenharmony_ci    wl_get_vif_macaddr(cfg, 7, p2p_hnetdev->macAddr);  // WL_IF_TYPE_P2P_DISC = 7
1708d6344f9Sopenharmony_ci    memcpy_s(p2p_netdev->dev_addr, p2p_netdev->addr_len, p2p_hnetdev->macAddr, MAC_ADDR_SIZE);
1718d6344f9Sopenharmony_ci    p2p_hnetdev->netDeviceIf = wal_get_net_p2p_ops();  // reset netdev_ops
1728d6344f9Sopenharmony_ci    hdf_cfgp2p_register_ndev(p2p_netdev, netdev, wiphy);
1738d6344f9Sopenharmony_ci    ret = NetDeviceAdd(p2p_hnetdev);  // Call linux register_netdev()
1748d6344f9Sopenharmony_ci    HDF_LOGI("NetDeviceAdd %s ret = %d", p2p_hnetdev->name, ret);
1758d6344f9Sopenharmony_ci    return ret;
1768d6344f9Sopenharmony_ci}
1778d6344f9Sopenharmony_ci
1788d6344f9Sopenharmony_ciint32_t BDH6Init(struct HdfChipDriver *chipDriver, struct NetDevice *netDevice)
1798d6344f9Sopenharmony_ci{
1808d6344f9Sopenharmony_ci    int32_t ret = 0;
1818d6344f9Sopenharmony_ci    struct net_device *netdev = NULL;
1828d6344f9Sopenharmony_ci    struct net_device *p2p_netdev = NULL;
1838d6344f9Sopenharmony_ci    struct NetDevice *p2p_hnetdev = NULL;
1848d6344f9Sopenharmony_ci
1858d6344f9Sopenharmony_ci    (void)chipDriver;
1868d6344f9Sopenharmony_ci    HDF_LOGI("bdh6: call BDH6Init");
1878d6344f9Sopenharmony_ci    HdfInfMapInit();
1888d6344f9Sopenharmony_ci
1898d6344f9Sopenharmony_ci    // Init primary interface wlan0
1908d6344f9Sopenharmony_ci    if (netDevice == NULL) {
1918d6344f9Sopenharmony_ci        HDF_LOGE("%s netdevice is null!", __func__);
1928d6344f9Sopenharmony_ci        return HDF_FAILURE;
1938d6344f9Sopenharmony_ci    }
1948d6344f9Sopenharmony_ci
1958d6344f9Sopenharmony_ci    netdev = GetLinuxInfByNetDevice(netDevice);
1968d6344f9Sopenharmony_ci    if (netdev == NULL) {
1978d6344f9Sopenharmony_ci        HDF_LOGE("%s net_device is null!", __func__);
1988d6344f9Sopenharmony_ci        return HDF_FAILURE;
1998d6344f9Sopenharmony_ci    }
2008d6344f9Sopenharmony_ci
2018d6344f9Sopenharmony_ci    ret = InitPrimaryInterface(netDevice, netdev);
2028d6344f9Sopenharmony_ci    if (ret != HDF_SUCCESS) {
2038d6344f9Sopenharmony_ci        return HDF_FAILURE;
2048d6344f9Sopenharmony_ci    }
2058d6344f9Sopenharmony_ci
2068d6344f9Sopenharmony_ci    ret = InitP2pInterface(netDevice, netdev);
2078d6344f9Sopenharmony_ci    if (ret != HDF_SUCCESS) {
2088d6344f9Sopenharmony_ci        return HDF_FAILURE;
2098d6344f9Sopenharmony_ci    }
2108d6344f9Sopenharmony_ci    p2p_hnetdev = get_hdf_netdev(g_hdf_ifidx);
2118d6344f9Sopenharmony_ci    p2p_netdev = get_krn_netdev(g_hdf_ifidx);
2128d6344f9Sopenharmony_ci
2138d6344f9Sopenharmony_ci    if (bdh6_reset_driver_flag) {
2148d6344f9Sopenharmony_ci        p2p_hnetdev->netDeviceIf->open(p2p_hnetdev);
2158d6344f9Sopenharmony_ci        rtnl_lock();
2168d6344f9Sopenharmony_ci        dev_open(netdev, NULL);
2178d6344f9Sopenharmony_ci        rtnl_unlock();
2188d6344f9Sopenharmony_ci        rtnl_lock();
2198d6344f9Sopenharmony_ci        dev_open(p2p_netdev, NULL);
2208d6344f9Sopenharmony_ci        rtnl_unlock();
2218d6344f9Sopenharmony_ci        rtnl_lock();
2228d6344f9Sopenharmony_ci        if (start_p2p_completed) {
2238d6344f9Sopenharmony_ci            start_p2p_completed = 0;
2248d6344f9Sopenharmony_ci            hdf_start_p2p_device();
2258d6344f9Sopenharmony_ci        }
2268d6344f9Sopenharmony_ci        rtnl_unlock();
2278d6344f9Sopenharmony_ci        bdh6_reset_driver_flag = 0;
2288d6344f9Sopenharmony_ci        HDF_LOGI("%s: reset driver ok", __func__);
2298d6344f9Sopenharmony_ci    }
2308d6344f9Sopenharmony_ci    return HDF_SUCCESS;
2318d6344f9Sopenharmony_ci}
2328d6344f9Sopenharmony_ci
2338d6344f9Sopenharmony_ciint32_t BDH6Deinit(struct HdfChipDriver *chipDriver, struct NetDevice *netDevice)
2348d6344f9Sopenharmony_ci{
2358d6344f9Sopenharmony_ci    // free p2p0
2368d6344f9Sopenharmony_ci    int32_t i = 0;
2378d6344f9Sopenharmony_ci    struct NetDevice *p2p_hnetdev = get_hdf_netdev(HDF_INF_P2P0);
2388d6344f9Sopenharmony_ci    (void)chipDriver;
2398d6344f9Sopenharmony_ci    kfree(p2p_hnetdev->mlPriv);
2408d6344f9Sopenharmony_ci    p2p_hnetdev->mlPriv = NULL;
2418d6344f9Sopenharmony_ci    DestroyEapolData(p2p_hnetdev);
2428d6344f9Sopenharmony_ci    if (NetDeviceDelete(p2p_hnetdev) != 0) {
2438d6344f9Sopenharmony_ci        return HDF_FAILURE;
2448d6344f9Sopenharmony_ci    }
2458d6344f9Sopenharmony_ci    if (NetDeviceDeInit(p2p_hnetdev) != 0) {
2468d6344f9Sopenharmony_ci        return HDF_FAILURE;
2478d6344f9Sopenharmony_ci    }
2488d6344f9Sopenharmony_ci
2498d6344f9Sopenharmony_ci    hdf_bdh6_netdev_stop(netDevice);
2508d6344f9Sopenharmony_ci    dhd_module_exit();
2518d6344f9Sopenharmony_ci
2528d6344f9Sopenharmony_ci    // free primary wlan0
2538d6344f9Sopenharmony_ci    kfree(netDevice->mlPriv);
2548d6344f9Sopenharmony_ci    netDevice->mlPriv = NULL;
2558d6344f9Sopenharmony_ci    DestroyEapolData(netDevice);
2568d6344f9Sopenharmony_ci
2578d6344f9Sopenharmony_ci    for (i = 0; i < HDF_INF_MAX; i ++) {
2588d6344f9Sopenharmony_ci        cancel_work_sync(&g_hdf_infmap[i].eapolEvent.eapol_report);
2598d6344f9Sopenharmony_ci        NetBufQueueClear(&g_hdf_infmap[i].eapolEvent.eapolQueue);
2608d6344f9Sopenharmony_ci    }
2618d6344f9Sopenharmony_ci    bdh6_reset_driver_flag = 1;
2628d6344f9Sopenharmony_ci    HDF_LOGI("%s: ok", __func__);
2638d6344f9Sopenharmony_ci
2648d6344f9Sopenharmony_ci    return HDF_SUCCESS;
2658d6344f9Sopenharmony_ci}
2668d6344f9Sopenharmony_ci
267