1/*
2 * hdfinit_bdh.c
3 *
4 * hdf driver
5 *
6 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 */
22
23#include <uapi/linux/nl80211.h>
24#include <securec.h>
25#include <asm/byteorder.h>
26#include <linux/kernel.h>
27
28#include "hdf_wifi_product.h"
29#include "wifi_mac80211_ops.h"
30#include "hdf_wlan_utils.h"
31#include "hdf_wl_interface.h"
32#include "net_bdh_adpater.h"
33#include "hdf_public_ap6275s.h"
34#include "eapol.h"
35
36#define HDF_LOG_TAG BDH6Driver
37int hdf_cfgp2p_register_ndev(struct net_device *p2p_netdev, struct net_device *primary_netdev, struct wiphy *wiphy);
38int dhd_module_init(void);
39void dhd_module_exit(void);
40struct bcm_cfg80211;
41s32 wl_get_vif_macaddr(struct bcm_cfg80211 *cfg, u16 wl_iftype, u8 *mac_addr);
42
43struct NetDeviceInterFace *wal_get_net_p2p_ops(void);
44struct hdf_inf_map g_hdf_infmap[HDF_INF_MAX];
45
46int g_hdf_ifidx = HDF_INF_WLAN0;
47int g_event_ifidx = HDF_INF_WLAN0;
48int g_scan_event_ifidx = HDF_INF_WLAN0;
49int g_conn_event_ifidx = HDF_INF_WLAN0;
50int g_mgmt_tx_event_ifidx = HDF_INF_P2P0;
51int bdh6_reset_driver_flag = 0;
52
53// BDH Wifi6 chip driver init
54int32_t InitBDH6Chip(struct HdfWlanDevice *device)
55{
56    (void)device;
57    HDF_LOGW("bdh6: call InitBDH6Chip");
58    return HDF_SUCCESS;
59}
60
61int32_t DeinitBDH6Chip(struct HdfWlanDevice *device)
62{
63    int32_t ret = HDF_SUCCESS;
64    (void)device;
65    if (ret != 0) {
66        HDF_LOGE("%s:Deinit failed!ret=%d", __func__, ret);
67    }
68    return ret;
69}
70
71static void HdfInfMapInit(void)
72{
73    int32_t i = 0;
74
75    memset_s(g_hdf_infmap, sizeof(g_hdf_infmap), 0, sizeof(g_hdf_infmap));
76    for (i = 0; i < HDF_INF_MAX; i ++) {
77        INIT_WORK(&g_hdf_infmap[i].eapolEvent.eapol_report, eapol_report_handler);
78        NetBufQueueInit(&g_hdf_infmap[i].eapolEvent.eapolQueue);
79        g_hdf_infmap[i].eapolEvent.idx = i;
80    }
81    g_hdf_ifidx = HDF_INF_WLAN0; // master interface
82}
83
84#define WIFI_IMAGE_FILE_NAME "/vendor/etc/firmware/fw_bcm43752a2_ag.bin"
85#define CK_WF_IMG_MAX_CNT 2
86#define  CK_WF_IMG_DELAY_MS 500
87int32_t CheckWiFiImageFile(const char *filename)
88{
89    struct file *fp = NULL;
90    int32_t icnt = 0;
91
92    while (icnt ++ <= CK_WF_IMG_MAX_CNT) {
93        fp = filp_open(filename, O_RDONLY, 0);
94        if (IS_ERR(fp)) {
95            HDF_LOGE("%s:open %s failed, cnt=%d, error=%d", __func__, filename, icnt, PTR_ERR(fp));
96            fp = NULL;
97            OsalMSleep(CK_WF_IMG_DELAY_MS);
98        } else {
99            filp_close(fp, NULL);
100            fp = NULL;
101            HDF_LOGE("%s:open %s success, cnt=%d", __func__, filename, icnt);
102            return 0;
103        }
104    }
105
106    HDF_LOGE("%s:open %s failed, cnt=%d reach to max times", __func__, filename, icnt);
107    return -1;
108}
109
110static int32_t InitPrimaryInterface(struct NetDevice *netDevice, struct net_device *netdev)
111{
112    int32_t ret = 0;
113    int32_t private_data_size = 0;
114    struct HdfWifiNetDeviceData *data = NULL;
115    // Init primary interface wlan0
116
117    data = GetPlatformData(netDevice);
118    if (data == NULL) {
119        HDF_LOGE("%s:netdevice data null!", __func__);
120        return HDF_FAILURE;
121    }
122
123    hdf_bdh6_netdev_init(netDevice);
124    netDevice->classDriverPriv = data;
125    private_data_size = get_dhd_priv_data_size(); // create bdh6 private object
126    netDevice->mlPriv = kzalloc(private_data_size, GFP_KERNEL);
127    if (netDevice->mlPriv == NULL) {
128        HDF_LOGE("%s:kzalloc mlPriv failed", __func__);
129        return HDF_FAILURE;
130    }
131
132    set_krn_netdev(netDevice, netdev, g_hdf_ifidx);
133    dhd_module_init();
134    return HDF_SUCCESS;
135}
136
137static int32_t InitP2pInterface(struct NetDevice *netDevice, struct net_device *netdev)
138{
139    int32_t ret = 0;
140    struct wiphy *wiphy = NULL;
141    struct net_device *p2p_netdev = NULL;
142    struct NetDevice *p2p_hnetdev = NULL;
143    struct bcm_cfg80211 *cfg = NULL;
144    WifiIfAdd ifAdd;
145
146    memset_s(&ifAdd, sizeof(ifAdd), 0, sizeof(ifAdd));
147    if (snprintf_s(ifAdd.ifName, IFNAMSIZ, IFNAMSIZ - 1, "p2p%d", 0) < 0) {
148        HDF_LOGE("%s:format ifName failed!", __func__);
149        return HDF_FAILURE;
150    }
151
152    ifAdd.type = NL80211_IFTYPE_P2P_DEVICE;
153    // Init interface p2p0
154    ret = P2pInitNetdev(netDevice, &ifAdd, sizeof(void *), HDF_INF_P2P0);
155    if (ret != 0) {
156        HDF_LOGE("%s:P2pInitNetdev %s failed", __func__, ifAdd.ifName);
157        return HDF_FAILURE;
158    }
159    wiphy = get_linux_wiphy_ndev(netdev);
160    if (wiphy == NULL) {
161        HDF_LOGE("%s:get wlan0 wiphy failed", __func__);
162        return HDF_FAILURE;
163    }
164    p2p_hnetdev = get_hdf_netdev(g_hdf_ifidx);
165    p2p_netdev = get_krn_netdev(g_hdf_ifidx);
166    p2p_netdev->ieee80211_ptr = NULL;
167    p2p_hnetdev->ieee80211Ptr = p2p_netdev->ieee80211_ptr;
168    cfg = wiphy_priv(wiphy);  // update mac from wdev address
169    wl_get_vif_macaddr(cfg, 7, p2p_hnetdev->macAddr);  // WL_IF_TYPE_P2P_DISC = 7
170    memcpy_s(p2p_netdev->dev_addr, p2p_netdev->addr_len, p2p_hnetdev->macAddr, MAC_ADDR_SIZE);
171    p2p_hnetdev->netDeviceIf = wal_get_net_p2p_ops();  // reset netdev_ops
172    hdf_cfgp2p_register_ndev(p2p_netdev, netdev, wiphy);
173    ret = NetDeviceAdd(p2p_hnetdev);  // Call linux register_netdev()
174    HDF_LOGI("NetDeviceAdd %s ret = %d", p2p_hnetdev->name, ret);
175    return ret;
176}
177
178int32_t BDH6Init(struct HdfChipDriver *chipDriver, struct NetDevice *netDevice)
179{
180    int32_t ret = 0;
181    struct net_device *netdev = NULL;
182    struct net_device *p2p_netdev = NULL;
183    struct NetDevice *p2p_hnetdev = NULL;
184
185    (void)chipDriver;
186    HDF_LOGI("bdh6: call BDH6Init");
187    HdfInfMapInit();
188
189    // Init primary interface wlan0
190    if (netDevice == NULL) {
191        HDF_LOGE("%s netdevice is null!", __func__);
192        return HDF_FAILURE;
193    }
194
195    netdev = GetLinuxInfByNetDevice(netDevice);
196    if (netdev == NULL) {
197        HDF_LOGE("%s net_device is null!", __func__);
198        return HDF_FAILURE;
199    }
200
201    ret = InitPrimaryInterface(netDevice, netdev);
202    if (ret != HDF_SUCCESS) {
203        return HDF_FAILURE;
204    }
205
206    ret = InitP2pInterface(netDevice, netdev);
207    if (ret != HDF_SUCCESS) {
208        return HDF_FAILURE;
209    }
210    p2p_hnetdev = get_hdf_netdev(g_hdf_ifidx);
211    p2p_netdev = get_krn_netdev(g_hdf_ifidx);
212
213    if (bdh6_reset_driver_flag) {
214        p2p_hnetdev->netDeviceIf->open(p2p_hnetdev);
215        rtnl_lock();
216        dev_open(netdev, NULL);
217        rtnl_unlock();
218        rtnl_lock();
219        dev_open(p2p_netdev, NULL);
220        rtnl_unlock();
221        rtnl_lock();
222        if (start_p2p_completed) {
223            start_p2p_completed = 0;
224            hdf_start_p2p_device();
225        }
226        rtnl_unlock();
227        bdh6_reset_driver_flag = 0;
228        HDF_LOGI("%s: reset driver ok", __func__);
229    }
230    return HDF_SUCCESS;
231}
232
233int32_t BDH6Deinit(struct HdfChipDriver *chipDriver, struct NetDevice *netDevice)
234{
235    // free p2p0
236    int32_t i = 0;
237    struct NetDevice *p2p_hnetdev = get_hdf_netdev(HDF_INF_P2P0);
238    (void)chipDriver;
239    kfree(p2p_hnetdev->mlPriv);
240    p2p_hnetdev->mlPriv = NULL;
241    DestroyEapolData(p2p_hnetdev);
242    if (NetDeviceDelete(p2p_hnetdev) != 0) {
243        return HDF_FAILURE;
244    }
245    if (NetDeviceDeInit(p2p_hnetdev) != 0) {
246        return HDF_FAILURE;
247    }
248
249    hdf_bdh6_netdev_stop(netDevice);
250    dhd_module_exit();
251
252    // free primary wlan0
253    kfree(netDevice->mlPriv);
254    netDevice->mlPriv = NULL;
255    DestroyEapolData(netDevice);
256
257    for (i = 0; i < HDF_INF_MAX; i ++) {
258        cancel_work_sync(&g_hdf_infmap[i].eapolEvent.eapol_report);
259        NetBufQueueClear(&g_hdf_infmap[i].eapolEvent.eapolQueue);
260    }
261    bdh6_reset_driver_flag = 1;
262    HDF_LOGI("%s: ok", __func__);
263
264    return HDF_SUCCESS;
265}
266
267