18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. 48c2ecf20Sopenharmony_ci * All rights reserved. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/irq.h> 88c2ecf20Sopenharmony_ci#include <linux/kthread.h> 98c2ecf20Sopenharmony_ci#include <linux/firmware.h> 108c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 118c2ecf20Sopenharmony_ci#include <linux/inetdevice.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "cfg80211.h" 148c2ecf20Sopenharmony_ci#include "wlan_cfg.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define WILC_MULTICAST_TABLE_SIZE 8 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* latest API version supported */ 198c2ecf20Sopenharmony_ci#define WILC1000_API_VER 1 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define WILC1000_FW_PREFIX "atmel/wilc1000_wifi_firmware-" 228c2ecf20Sopenharmony_ci#define __WILC1000_FW(api) WILC1000_FW_PREFIX #api ".bin" 238c2ecf20Sopenharmony_ci#define WILC1000_FW(api) __WILC1000_FW(api) 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic irqreturn_t isr_uh_routine(int irq, void *user_data) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci struct net_device *dev = user_data; 288c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(dev); 298c2ecf20Sopenharmony_ci struct wilc *wilc = vif->wilc; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci if (wilc->close) { 328c2ecf20Sopenharmony_ci netdev_err(dev, "Can't handle UH interrupt\n"); 338c2ecf20Sopenharmony_ci return IRQ_HANDLED; 348c2ecf20Sopenharmony_ci } 358c2ecf20Sopenharmony_ci return IRQ_WAKE_THREAD; 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic irqreturn_t isr_bh_routine(int irq, void *userdata) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci struct net_device *dev = userdata; 418c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(userdata); 428c2ecf20Sopenharmony_ci struct wilc *wilc = vif->wilc; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci if (wilc->close) { 458c2ecf20Sopenharmony_ci netdev_err(dev, "Can't handle BH interrupt\n"); 468c2ecf20Sopenharmony_ci return IRQ_HANDLED; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci wilc_handle_isr(wilc); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci return IRQ_HANDLED; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic int init_irq(struct net_device *dev) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(dev); 578c2ecf20Sopenharmony_ci struct wilc *wl = vif->wilc; 588c2ecf20Sopenharmony_ci int ret; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci ret = request_threaded_irq(wl->dev_irq_num, isr_uh_routine, 618c2ecf20Sopenharmony_ci isr_bh_routine, 628c2ecf20Sopenharmony_ci IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 638c2ecf20Sopenharmony_ci "WILC_IRQ", dev); 648c2ecf20Sopenharmony_ci if (ret) { 658c2ecf20Sopenharmony_ci netdev_err(dev, "Failed to request IRQ [%d]\n", ret); 668c2ecf20Sopenharmony_ci return ret; 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci netdev_dbg(dev, "IRQ request succeeded IRQ-NUM= %d\n", wl->dev_irq_num); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci return 0; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic void deinit_irq(struct net_device *dev) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(dev); 768c2ecf20Sopenharmony_ci struct wilc *wilc = vif->wilc; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci /* Deinitialize IRQ */ 798c2ecf20Sopenharmony_ci if (wilc->dev_irq_num) 808c2ecf20Sopenharmony_ci free_irq(wilc->dev_irq_num, wilc); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_civoid wilc_mac_indicate(struct wilc *wilc) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci s8 status; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci wilc_wlan_cfg_get_val(wilc, WID_STATUS, &status, 1); 888c2ecf20Sopenharmony_ci if (wilc->mac_status == WILC_MAC_STATUS_INIT) { 898c2ecf20Sopenharmony_ci wilc->mac_status = status; 908c2ecf20Sopenharmony_ci complete(&wilc->sync_event); 918c2ecf20Sopenharmony_ci } else { 928c2ecf20Sopenharmony_ci wilc->mac_status = status; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic struct net_device *get_if_handler(struct wilc *wilc, u8 *mac_header) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct net_device *ndev = NULL; 998c2ecf20Sopenharmony_ci struct wilc_vif *vif; 1008c2ecf20Sopenharmony_ci struct ieee80211_hdr *h = (struct ieee80211_hdr *)mac_header; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci list_for_each_entry_rcu(vif, &wilc->vif_list, list) { 1038c2ecf20Sopenharmony_ci if (vif->mode == WILC_STATION_MODE) 1048c2ecf20Sopenharmony_ci if (ether_addr_equal_unaligned(h->addr2, vif->bssid)) { 1058c2ecf20Sopenharmony_ci ndev = vif->ndev; 1068c2ecf20Sopenharmony_ci goto out; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci if (vif->mode == WILC_AP_MODE) 1098c2ecf20Sopenharmony_ci if (ether_addr_equal_unaligned(h->addr1, vif->bssid)) { 1108c2ecf20Sopenharmony_ci ndev = vif->ndev; 1118c2ecf20Sopenharmony_ci goto out; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ciout: 1158c2ecf20Sopenharmony_ci return ndev; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_civoid wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(wilc_netdev); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (bssid) 1238c2ecf20Sopenharmony_ci ether_addr_copy(vif->bssid, bssid); 1248c2ecf20Sopenharmony_ci else 1258c2ecf20Sopenharmony_ci eth_zero_addr(vif->bssid); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci vif->mode = mode; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ciint wilc_wlan_get_num_conn_ifcs(struct wilc *wilc) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci int srcu_idx; 1338c2ecf20Sopenharmony_ci u8 ret_val = 0; 1348c2ecf20Sopenharmony_ci struct wilc_vif *vif; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci srcu_idx = srcu_read_lock(&wilc->srcu); 1378c2ecf20Sopenharmony_ci list_for_each_entry_rcu(vif, &wilc->vif_list, list) { 1388c2ecf20Sopenharmony_ci if (!is_zero_ether_addr(vif->bssid)) 1398c2ecf20Sopenharmony_ci ret_val++; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci srcu_read_unlock(&wilc->srcu, srcu_idx); 1428c2ecf20Sopenharmony_ci return ret_val; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic int wilc_txq_task(void *vp) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci int ret; 1488c2ecf20Sopenharmony_ci u32 txq_count; 1498c2ecf20Sopenharmony_ci struct wilc *wl = vp; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci complete(&wl->txq_thread_started); 1528c2ecf20Sopenharmony_ci while (1) { 1538c2ecf20Sopenharmony_ci wait_for_completion(&wl->txq_event); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (wl->close) { 1568c2ecf20Sopenharmony_ci complete(&wl->txq_thread_started); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci while (!kthread_should_stop()) 1598c2ecf20Sopenharmony_ci schedule(); 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci do { 1638c2ecf20Sopenharmony_ci ret = wilc_wlan_handle_txq(wl, &txq_count); 1648c2ecf20Sopenharmony_ci if (txq_count < FLOW_CONTROL_LOWER_THRESHOLD) { 1658c2ecf20Sopenharmony_ci int srcu_idx; 1668c2ecf20Sopenharmony_ci struct wilc_vif *ifc; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci srcu_idx = srcu_read_lock(&wl->srcu); 1698c2ecf20Sopenharmony_ci list_for_each_entry_rcu(ifc, &wl->vif_list, 1708c2ecf20Sopenharmony_ci list) { 1718c2ecf20Sopenharmony_ci if (ifc->mac_opened && ifc->ndev) 1728c2ecf20Sopenharmony_ci netif_wake_queue(ifc->ndev); 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci srcu_read_unlock(&wl->srcu, srcu_idx); 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci } while (ret == WILC_VMM_ENTRY_FULL_RETRY && !wl->close); 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci return 0; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic int wilc_wlan_get_firmware(struct net_device *dev) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(dev); 1848c2ecf20Sopenharmony_ci struct wilc *wilc = vif->wilc; 1858c2ecf20Sopenharmony_ci int chip_id; 1868c2ecf20Sopenharmony_ci const struct firmware *wilc_fw; 1878c2ecf20Sopenharmony_ci int ret; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci chip_id = wilc_get_chipid(wilc, false); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci netdev_info(dev, "ChipID [%x] loading firmware [%s]\n", chip_id, 1928c2ecf20Sopenharmony_ci WILC1000_FW(WILC1000_API_VER)); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci ret = request_firmware(&wilc_fw, WILC1000_FW(WILC1000_API_VER), 1958c2ecf20Sopenharmony_ci wilc->dev); 1968c2ecf20Sopenharmony_ci if (ret != 0) { 1978c2ecf20Sopenharmony_ci netdev_err(dev, "%s - firmware not available\n", 1988c2ecf20Sopenharmony_ci WILC1000_FW(WILC1000_API_VER)); 1998c2ecf20Sopenharmony_ci return -EINVAL; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci wilc->firmware = wilc_fw; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return 0; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic int wilc_start_firmware(struct net_device *dev) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(dev); 2098c2ecf20Sopenharmony_ci struct wilc *wilc = vif->wilc; 2108c2ecf20Sopenharmony_ci int ret = 0; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci ret = wilc_wlan_start(wilc); 2138c2ecf20Sopenharmony_ci if (ret) 2148c2ecf20Sopenharmony_ci return ret; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (!wait_for_completion_timeout(&wilc->sync_event, 2178c2ecf20Sopenharmony_ci msecs_to_jiffies(5000))) 2188c2ecf20Sopenharmony_ci return -ETIME; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci return 0; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic int wilc1000_firmware_download(struct net_device *dev) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(dev); 2268c2ecf20Sopenharmony_ci struct wilc *wilc = vif->wilc; 2278c2ecf20Sopenharmony_ci int ret = 0; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (!wilc->firmware) { 2308c2ecf20Sopenharmony_ci netdev_err(dev, "Firmware buffer is NULL\n"); 2318c2ecf20Sopenharmony_ci return -ENOBUFS; 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci ret = wilc_wlan_firmware_download(wilc, wilc->firmware->data, 2358c2ecf20Sopenharmony_ci wilc->firmware->size); 2368c2ecf20Sopenharmony_ci if (ret) 2378c2ecf20Sopenharmony_ci return ret; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci release_firmware(wilc->firmware); 2408c2ecf20Sopenharmony_ci wilc->firmware = NULL; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci netdev_dbg(dev, "Download Succeeded\n"); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return 0; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic int wilc_init_fw_config(struct net_device *dev, struct wilc_vif *vif) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct wilc_priv *priv = &vif->priv; 2508c2ecf20Sopenharmony_ci struct host_if_drv *hif_drv; 2518c2ecf20Sopenharmony_ci u8 b; 2528c2ecf20Sopenharmony_ci u16 hw; 2538c2ecf20Sopenharmony_ci u32 w; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci netdev_dbg(dev, "Start configuring Firmware\n"); 2568c2ecf20Sopenharmony_ci hif_drv = (struct host_if_drv *)priv->hif_drv; 2578c2ecf20Sopenharmony_ci netdev_dbg(dev, "Host = %p\n", hif_drv); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci w = vif->iftype; 2608c2ecf20Sopenharmony_ci cpu_to_le32s(&w); 2618c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 1, WID_SET_OPERATION_MODE, (u8 *)&w, 4, 2628c2ecf20Sopenharmony_ci 0, 0)) 2638c2ecf20Sopenharmony_ci goto fail; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci b = WILC_FW_BSS_TYPE_INFRA; 2668c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_BSS_TYPE, &b, 1, 0, 0)) 2678c2ecf20Sopenharmony_ci goto fail; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci b = WILC_FW_TX_RATE_AUTO; 2708c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_CURRENT_TX_RATE, &b, 1, 0, 0)) 2718c2ecf20Sopenharmony_ci goto fail; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci b = WILC_FW_OPER_MODE_G_MIXED_11B_2; 2748c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_11G_OPERATING_MODE, &b, 1, 0, 0)) 2758c2ecf20Sopenharmony_ci goto fail; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci b = WILC_FW_PREAMBLE_SHORT; 2788c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_PREAMBLE, &b, 1, 0, 0)) 2798c2ecf20Sopenharmony_ci goto fail; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci b = WILC_FW_11N_PROT_AUTO; 2828c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_11N_PROT_MECH, &b, 1, 0, 0)) 2838c2ecf20Sopenharmony_ci goto fail; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci b = WILC_FW_ACTIVE_SCAN; 2868c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_SCAN_TYPE, &b, 1, 0, 0)) 2878c2ecf20Sopenharmony_ci goto fail; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci b = WILC_FW_SITE_SURVEY_OFF; 2908c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_SITE_SURVEY, &b, 1, 0, 0)) 2918c2ecf20Sopenharmony_ci goto fail; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci hw = 0xffff; 2948c2ecf20Sopenharmony_ci cpu_to_le16s(&hw); 2958c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_RTS_THRESHOLD, (u8 *)&hw, 2, 0, 0)) 2968c2ecf20Sopenharmony_ci goto fail; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci hw = 2346; 2998c2ecf20Sopenharmony_ci cpu_to_le16s(&hw); 3008c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_FRAG_THRESHOLD, (u8 *)&hw, 2, 0, 0)) 3018c2ecf20Sopenharmony_ci goto fail; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci b = 0; 3048c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_BCAST_SSID, &b, 1, 0, 0)) 3058c2ecf20Sopenharmony_ci goto fail; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci b = 1; 3088c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_QOS_ENABLE, &b, 1, 0, 0)) 3098c2ecf20Sopenharmony_ci goto fail; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci b = WILC_FW_NO_POWERSAVE; 3128c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_POWER_MANAGEMENT, &b, 1, 0, 0)) 3138c2ecf20Sopenharmony_ci goto fail; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci b = WILC_FW_SEC_NO; 3168c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_11I_MODE, &b, 1, 0, 0)) 3178c2ecf20Sopenharmony_ci goto fail; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci b = WILC_FW_AUTH_OPEN_SYSTEM; 3208c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_AUTH_TYPE, &b, 1, 0, 0)) 3218c2ecf20Sopenharmony_ci goto fail; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci b = 3; 3248c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_LISTEN_INTERVAL, &b, 1, 0, 0)) 3258c2ecf20Sopenharmony_ci goto fail; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci b = 3; 3288c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_DTIM_PERIOD, &b, 1, 0, 0)) 3298c2ecf20Sopenharmony_ci goto fail; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci b = WILC_FW_ACK_POLICY_NORMAL; 3328c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_ACK_POLICY, &b, 1, 0, 0)) 3338c2ecf20Sopenharmony_ci goto fail; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci b = 0; 3368c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_USER_CONTROL_ON_TX_POWER, &b, 1, 3378c2ecf20Sopenharmony_ci 0, 0)) 3388c2ecf20Sopenharmony_ci goto fail; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci b = 48; 3418c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_TX_POWER_LEVEL_11A, &b, 1, 0, 0)) 3428c2ecf20Sopenharmony_ci goto fail; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci b = 28; 3458c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_TX_POWER_LEVEL_11B, &b, 1, 0, 0)) 3468c2ecf20Sopenharmony_ci goto fail; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci hw = 100; 3498c2ecf20Sopenharmony_ci cpu_to_le16s(&hw); 3508c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_BEACON_INTERVAL, (u8 *)&hw, 2, 0, 0)) 3518c2ecf20Sopenharmony_ci goto fail; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci b = WILC_FW_REKEY_POLICY_DISABLE; 3548c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_POLICY, &b, 1, 0, 0)) 3558c2ecf20Sopenharmony_ci goto fail; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci w = 84600; 3588c2ecf20Sopenharmony_ci cpu_to_le32s(&w); 3598c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_PERIOD, (u8 *)&w, 4, 0, 0)) 3608c2ecf20Sopenharmony_ci goto fail; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci w = 500; 3638c2ecf20Sopenharmony_ci cpu_to_le32s(&w); 3648c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_PACKET_COUNT, (u8 *)&w, 4, 0, 3658c2ecf20Sopenharmony_ci 0)) 3668c2ecf20Sopenharmony_ci goto fail; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci b = 1; 3698c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_SHORT_SLOT_ALLOWED, &b, 1, 0, 3708c2ecf20Sopenharmony_ci 0)) 3718c2ecf20Sopenharmony_ci goto fail; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci b = WILC_FW_ERP_PROT_SELF_CTS; 3748c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_11N_ERP_PROT_TYPE, &b, 1, 0, 0)) 3758c2ecf20Sopenharmony_ci goto fail; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci b = 1; 3788c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_11N_ENABLE, &b, 1, 0, 0)) 3798c2ecf20Sopenharmony_ci goto fail; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci b = WILC_FW_11N_OP_MODE_HT_MIXED; 3828c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_11N_OPERATING_MODE, &b, 1, 0, 0)) 3838c2ecf20Sopenharmony_ci goto fail; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci b = 1; 3868c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_11N_TXOP_PROT_DISABLE, &b, 1, 0, 0)) 3878c2ecf20Sopenharmony_ci goto fail; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci b = WILC_FW_OBBS_NONHT_DETECT_PROTECT_REPORT; 3908c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_11N_OBSS_NONHT_DETECTION, &b, 1, 3918c2ecf20Sopenharmony_ci 0, 0)) 3928c2ecf20Sopenharmony_ci goto fail; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci b = WILC_FW_HT_PROT_RTS_CTS_NONHT; 3958c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_11N_HT_PROT_TYPE, &b, 1, 0, 0)) 3968c2ecf20Sopenharmony_ci goto fail; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci b = 0; 3998c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_11N_RIFS_PROT_ENABLE, &b, 1, 0, 4008c2ecf20Sopenharmony_ci 0)) 4018c2ecf20Sopenharmony_ci goto fail; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci b = 7; 4048c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_11N_CURRENT_TX_MCS, &b, 1, 0, 0)) 4058c2ecf20Sopenharmony_ci goto fail; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci b = 1; 4088c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, 0, WID_11N_IMMEDIATE_BA_ENABLED, &b, 1, 4098c2ecf20Sopenharmony_ci 1, 1)) 4108c2ecf20Sopenharmony_ci goto fail; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci return 0; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cifail: 4158c2ecf20Sopenharmony_ci return -EINVAL; 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic void wlan_deinitialize_threads(struct net_device *dev) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(dev); 4218c2ecf20Sopenharmony_ci struct wilc *wl = vif->wilc; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci wl->close = 1; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci complete(&wl->txq_event); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci if (wl->txq_thread) { 4288c2ecf20Sopenharmony_ci kthread_stop(wl->txq_thread); 4298c2ecf20Sopenharmony_ci wl->txq_thread = NULL; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic void wilc_wlan_deinitialize(struct net_device *dev) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(dev); 4368c2ecf20Sopenharmony_ci struct wilc *wl = vif->wilc; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (!wl) { 4398c2ecf20Sopenharmony_ci netdev_err(dev, "wl is NULL\n"); 4408c2ecf20Sopenharmony_ci return; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (wl->initialized) { 4448c2ecf20Sopenharmony_ci netdev_info(dev, "Deinitializing wilc1000...\n"); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (!wl->dev_irq_num && 4478c2ecf20Sopenharmony_ci wl->hif_func->disable_interrupt) { 4488c2ecf20Sopenharmony_ci mutex_lock(&wl->hif_cs); 4498c2ecf20Sopenharmony_ci wl->hif_func->disable_interrupt(wl); 4508c2ecf20Sopenharmony_ci mutex_unlock(&wl->hif_cs); 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci complete(&wl->txq_event); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci wlan_deinitialize_threads(dev); 4558c2ecf20Sopenharmony_ci deinit_irq(dev); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci wilc_wlan_stop(wl, vif); 4588c2ecf20Sopenharmony_ci wilc_wlan_cleanup(dev); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci wl->initialized = false; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci netdev_dbg(dev, "wilc1000 deinitialization Done\n"); 4638c2ecf20Sopenharmony_ci } else { 4648c2ecf20Sopenharmony_ci netdev_dbg(dev, "wilc1000 is not initialized\n"); 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic int wlan_initialize_threads(struct net_device *dev) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(dev); 4718c2ecf20Sopenharmony_ci struct wilc *wilc = vif->wilc; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci wilc->txq_thread = kthread_run(wilc_txq_task, (void *)wilc, 4748c2ecf20Sopenharmony_ci "K_TXQ_TASK"); 4758c2ecf20Sopenharmony_ci if (IS_ERR(wilc->txq_thread)) { 4768c2ecf20Sopenharmony_ci netdev_err(dev, "couldn't create TXQ thread\n"); 4778c2ecf20Sopenharmony_ci wilc->close = 0; 4788c2ecf20Sopenharmony_ci return PTR_ERR(wilc->txq_thread); 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci wait_for_completion(&wilc->txq_thread_started); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci return 0; 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_cistatic int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci int ret = 0; 4888c2ecf20Sopenharmony_ci struct wilc *wl = vif->wilc; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (!wl->initialized) { 4918c2ecf20Sopenharmony_ci wl->mac_status = WILC_MAC_STATUS_INIT; 4928c2ecf20Sopenharmony_ci wl->close = 0; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci ret = wilc_wlan_init(dev); 4958c2ecf20Sopenharmony_ci if (ret) 4968c2ecf20Sopenharmony_ci return ret; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci ret = wlan_initialize_threads(dev); 4998c2ecf20Sopenharmony_ci if (ret) 5008c2ecf20Sopenharmony_ci goto fail_wilc_wlan; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (wl->dev_irq_num && init_irq(dev)) { 5038c2ecf20Sopenharmony_ci ret = -EIO; 5048c2ecf20Sopenharmony_ci goto fail_threads; 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (!wl->dev_irq_num && 5088c2ecf20Sopenharmony_ci wl->hif_func->enable_interrupt && 5098c2ecf20Sopenharmony_ci wl->hif_func->enable_interrupt(wl)) { 5108c2ecf20Sopenharmony_ci ret = -EIO; 5118c2ecf20Sopenharmony_ci goto fail_irq_init; 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci ret = wilc_wlan_get_firmware(dev); 5158c2ecf20Sopenharmony_ci if (ret) 5168c2ecf20Sopenharmony_ci goto fail_irq_enable; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci ret = wilc1000_firmware_download(dev); 5198c2ecf20Sopenharmony_ci if (ret) 5208c2ecf20Sopenharmony_ci goto fail_irq_enable; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci ret = wilc_start_firmware(dev); 5238c2ecf20Sopenharmony_ci if (ret) 5248c2ecf20Sopenharmony_ci goto fail_irq_enable; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci if (wilc_wlan_cfg_get(vif, 1, WID_FIRMWARE_VERSION, 1, 0)) { 5278c2ecf20Sopenharmony_ci int size; 5288c2ecf20Sopenharmony_ci char firmware_ver[20]; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci size = wilc_wlan_cfg_get_val(wl, WID_FIRMWARE_VERSION, 5318c2ecf20Sopenharmony_ci firmware_ver, 5328c2ecf20Sopenharmony_ci sizeof(firmware_ver)); 5338c2ecf20Sopenharmony_ci firmware_ver[size] = '\0'; 5348c2ecf20Sopenharmony_ci netdev_dbg(dev, "Firmware Ver = %s\n", firmware_ver); 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci ret = wilc_init_fw_config(dev, vif); 5388c2ecf20Sopenharmony_ci if (ret) { 5398c2ecf20Sopenharmony_ci netdev_err(dev, "Failed to configure firmware\n"); 5408c2ecf20Sopenharmony_ci goto fail_fw_start; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci wl->initialized = true; 5438c2ecf20Sopenharmony_ci return 0; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cifail_fw_start: 5468c2ecf20Sopenharmony_ci wilc_wlan_stop(wl, vif); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cifail_irq_enable: 5498c2ecf20Sopenharmony_ci if (!wl->dev_irq_num && 5508c2ecf20Sopenharmony_ci wl->hif_func->disable_interrupt) 5518c2ecf20Sopenharmony_ci wl->hif_func->disable_interrupt(wl); 5528c2ecf20Sopenharmony_cifail_irq_init: 5538c2ecf20Sopenharmony_ci if (wl->dev_irq_num) 5548c2ecf20Sopenharmony_ci deinit_irq(dev); 5558c2ecf20Sopenharmony_cifail_threads: 5568c2ecf20Sopenharmony_ci wlan_deinitialize_threads(dev); 5578c2ecf20Sopenharmony_cifail_wilc_wlan: 5588c2ecf20Sopenharmony_ci wilc_wlan_cleanup(dev); 5598c2ecf20Sopenharmony_ci netdev_err(dev, "WLAN initialization FAILED\n"); 5608c2ecf20Sopenharmony_ci } else { 5618c2ecf20Sopenharmony_ci netdev_dbg(dev, "wilc1000 already initialized\n"); 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci return ret; 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistatic int mac_init_fn(struct net_device *ndev) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci netif_start_queue(ndev); 5698c2ecf20Sopenharmony_ci netif_stop_queue(ndev); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci return 0; 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cistatic int wilc_mac_open(struct net_device *ndev) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(ndev); 5778c2ecf20Sopenharmony_ci struct wilc *wl = vif->wilc; 5788c2ecf20Sopenharmony_ci unsigned char mac_add[ETH_ALEN] = {0}; 5798c2ecf20Sopenharmony_ci int ret = 0; 5808c2ecf20Sopenharmony_ci struct mgmt_frame_regs mgmt_regs = {}; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci if (!wl || !wl->dev) { 5838c2ecf20Sopenharmony_ci netdev_err(ndev, "device not ready\n"); 5848c2ecf20Sopenharmony_ci return -ENODEV; 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci netdev_dbg(ndev, "MAC OPEN[%p]\n", ndev); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci ret = wilc_init_host_int(ndev); 5908c2ecf20Sopenharmony_ci if (ret) 5918c2ecf20Sopenharmony_ci return ret; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci ret = wilc_wlan_initialize(ndev, vif); 5948c2ecf20Sopenharmony_ci if (ret) { 5958c2ecf20Sopenharmony_ci wilc_deinit_host_int(ndev); 5968c2ecf20Sopenharmony_ci return ret; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), vif->iftype, 6008c2ecf20Sopenharmony_ci vif->idx); 6018c2ecf20Sopenharmony_ci wilc_get_mac_address(vif, mac_add); 6028c2ecf20Sopenharmony_ci netdev_dbg(ndev, "Mac address: %pM\n", mac_add); 6038c2ecf20Sopenharmony_ci ether_addr_copy(ndev->dev_addr, mac_add); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(ndev->dev_addr)) { 6068c2ecf20Sopenharmony_ci netdev_err(ndev, "Wrong MAC address\n"); 6078c2ecf20Sopenharmony_ci wilc_deinit_host_int(ndev); 6088c2ecf20Sopenharmony_ci wilc_wlan_deinitialize(ndev); 6098c2ecf20Sopenharmony_ci return -EINVAL; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci mgmt_regs.interface_stypes = vif->mgmt_reg_stypes; 6138c2ecf20Sopenharmony_ci /* so we detect a change */ 6148c2ecf20Sopenharmony_ci vif->mgmt_reg_stypes = 0; 6158c2ecf20Sopenharmony_ci wilc_update_mgmt_frame_registrations(vif->ndev->ieee80211_ptr->wiphy, 6168c2ecf20Sopenharmony_ci vif->ndev->ieee80211_ptr, 6178c2ecf20Sopenharmony_ci &mgmt_regs); 6188c2ecf20Sopenharmony_ci netif_wake_queue(ndev); 6198c2ecf20Sopenharmony_ci wl->open_ifcs++; 6208c2ecf20Sopenharmony_ci vif->mac_opened = 1; 6218c2ecf20Sopenharmony_ci return 0; 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_cistatic struct net_device_stats *mac_stats(struct net_device *dev) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(dev); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci return &vif->netstats; 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_cistatic void wilc_set_multicast_list(struct net_device *dev) 6328c2ecf20Sopenharmony_ci{ 6338c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 6348c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(dev); 6358c2ecf20Sopenharmony_ci int i; 6368c2ecf20Sopenharmony_ci u8 *mc_list; 6378c2ecf20Sopenharmony_ci u8 *cur_mc; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci if (dev->flags & IFF_PROMISC) 6408c2ecf20Sopenharmony_ci return; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (dev->flags & IFF_ALLMULTI || 6438c2ecf20Sopenharmony_ci dev->mc.count > WILC_MULTICAST_TABLE_SIZE) { 6448c2ecf20Sopenharmony_ci wilc_setup_multicast_filter(vif, 0, 0, NULL); 6458c2ecf20Sopenharmony_ci return; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci if (dev->mc.count == 0) { 6498c2ecf20Sopenharmony_ci wilc_setup_multicast_filter(vif, 1, 0, NULL); 6508c2ecf20Sopenharmony_ci return; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci mc_list = kmalloc_array(dev->mc.count, ETH_ALEN, GFP_ATOMIC); 6548c2ecf20Sopenharmony_ci if (!mc_list) 6558c2ecf20Sopenharmony_ci return; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci cur_mc = mc_list; 6588c2ecf20Sopenharmony_ci i = 0; 6598c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 6608c2ecf20Sopenharmony_ci memcpy(cur_mc, ha->addr, ETH_ALEN); 6618c2ecf20Sopenharmony_ci netdev_dbg(dev, "Entry[%d]: %pM\n", i, cur_mc); 6628c2ecf20Sopenharmony_ci i++; 6638c2ecf20Sopenharmony_ci cur_mc += ETH_ALEN; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (wilc_setup_multicast_filter(vif, 1, dev->mc.count, mc_list)) 6678c2ecf20Sopenharmony_ci kfree(mc_list); 6688c2ecf20Sopenharmony_ci} 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_cistatic void wilc_tx_complete(void *priv, int status) 6718c2ecf20Sopenharmony_ci{ 6728c2ecf20Sopenharmony_ci struct tx_complete_data *pv_data = priv; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci dev_kfree_skb(pv_data->skb); 6758c2ecf20Sopenharmony_ci kfree(pv_data); 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_cinetdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *ndev) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(ndev); 6818c2ecf20Sopenharmony_ci struct wilc *wilc = vif->wilc; 6828c2ecf20Sopenharmony_ci struct tx_complete_data *tx_data = NULL; 6838c2ecf20Sopenharmony_ci int queue_count; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci if (skb->dev != ndev) { 6868c2ecf20Sopenharmony_ci netdev_err(ndev, "Packet not destined to this device\n"); 6878c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 6888c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci tx_data = kmalloc(sizeof(*tx_data), GFP_ATOMIC); 6928c2ecf20Sopenharmony_ci if (!tx_data) { 6938c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 6948c2ecf20Sopenharmony_ci netif_wake_queue(ndev); 6958c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci tx_data->buff = skb->data; 6998c2ecf20Sopenharmony_ci tx_data->size = skb->len; 7008c2ecf20Sopenharmony_ci tx_data->skb = skb; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci vif->netstats.tx_packets++; 7038c2ecf20Sopenharmony_ci vif->netstats.tx_bytes += tx_data->size; 7048c2ecf20Sopenharmony_ci queue_count = wilc_wlan_txq_add_net_pkt(ndev, (void *)tx_data, 7058c2ecf20Sopenharmony_ci tx_data->buff, tx_data->size, 7068c2ecf20Sopenharmony_ci wilc_tx_complete); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci if (queue_count > FLOW_CONTROL_UPPER_THRESHOLD) { 7098c2ecf20Sopenharmony_ci int srcu_idx; 7108c2ecf20Sopenharmony_ci struct wilc_vif *vif; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci srcu_idx = srcu_read_lock(&wilc->srcu); 7138c2ecf20Sopenharmony_ci list_for_each_entry_rcu(vif, &wilc->vif_list, list) { 7148c2ecf20Sopenharmony_ci if (vif->mac_opened) 7158c2ecf20Sopenharmony_ci netif_stop_queue(vif->ndev); 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci srcu_read_unlock(&wilc->srcu, srcu_idx); 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 7218c2ecf20Sopenharmony_ci} 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_cistatic int wilc_mac_close(struct net_device *ndev) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(ndev); 7268c2ecf20Sopenharmony_ci struct wilc *wl = vif->wilc; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci netdev_dbg(ndev, "Mac close\n"); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (wl->open_ifcs > 0) 7318c2ecf20Sopenharmony_ci wl->open_ifcs--; 7328c2ecf20Sopenharmony_ci else 7338c2ecf20Sopenharmony_ci return 0; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci if (vif->ndev) { 7368c2ecf20Sopenharmony_ci netif_stop_queue(vif->ndev); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci wilc_deinit_host_int(vif->ndev); 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci if (wl->open_ifcs == 0) { 7428c2ecf20Sopenharmony_ci netdev_dbg(ndev, "Deinitializing wilc1000\n"); 7438c2ecf20Sopenharmony_ci wl->close = 1; 7448c2ecf20Sopenharmony_ci wilc_wlan_deinitialize(ndev); 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci vif->mac_opened = 0; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci return 0; 7508c2ecf20Sopenharmony_ci} 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_civoid wilc_frmw_to_host(struct wilc *wilc, u8 *buff, u32 size, 7538c2ecf20Sopenharmony_ci u32 pkt_offset) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci unsigned int frame_len = 0; 7568c2ecf20Sopenharmony_ci int stats; 7578c2ecf20Sopenharmony_ci unsigned char *buff_to_send = NULL; 7588c2ecf20Sopenharmony_ci struct sk_buff *skb; 7598c2ecf20Sopenharmony_ci struct net_device *wilc_netdev; 7608c2ecf20Sopenharmony_ci struct wilc_vif *vif; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci if (!wilc) 7638c2ecf20Sopenharmony_ci return; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci wilc_netdev = get_if_handler(wilc, buff); 7668c2ecf20Sopenharmony_ci if (!wilc_netdev) 7678c2ecf20Sopenharmony_ci return; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci buff += pkt_offset; 7708c2ecf20Sopenharmony_ci vif = netdev_priv(wilc_netdev); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci if (size > 0) { 7738c2ecf20Sopenharmony_ci frame_len = size; 7748c2ecf20Sopenharmony_ci buff_to_send = buff; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci skb = dev_alloc_skb(frame_len); 7778c2ecf20Sopenharmony_ci if (!skb) 7788c2ecf20Sopenharmony_ci return; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci skb->dev = wilc_netdev; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci skb_put_data(skb, buff_to_send, frame_len); 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, wilc_netdev); 7858c2ecf20Sopenharmony_ci vif->netstats.rx_packets++; 7868c2ecf20Sopenharmony_ci vif->netstats.rx_bytes += frame_len; 7878c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 7888c2ecf20Sopenharmony_ci stats = netif_rx(skb); 7898c2ecf20Sopenharmony_ci netdev_dbg(wilc_netdev, "netif_rx ret value is: %d\n", stats); 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_civoid wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size) 7948c2ecf20Sopenharmony_ci{ 7958c2ecf20Sopenharmony_ci int srcu_idx; 7968c2ecf20Sopenharmony_ci struct wilc_vif *vif; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci srcu_idx = srcu_read_lock(&wilc->srcu); 7998c2ecf20Sopenharmony_ci list_for_each_entry_rcu(vif, &wilc->vif_list, list) { 8008c2ecf20Sopenharmony_ci u16 type = le16_to_cpup((__le16 *)buff); 8018c2ecf20Sopenharmony_ci u32 type_bit = BIT(type >> 4); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci if (vif->priv.p2p_listen_state && 8048c2ecf20Sopenharmony_ci vif->mgmt_reg_stypes & type_bit) 8058c2ecf20Sopenharmony_ci wilc_wfi_p2p_rx(vif, buff, size); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci if (vif->monitor_flag) 8088c2ecf20Sopenharmony_ci wilc_wfi_monitor_rx(wilc->monitor_dev, buff, size); 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci srcu_read_unlock(&wilc->srcu, srcu_idx); 8118c2ecf20Sopenharmony_ci} 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_cistatic const struct net_device_ops wilc_netdev_ops = { 8148c2ecf20Sopenharmony_ci .ndo_init = mac_init_fn, 8158c2ecf20Sopenharmony_ci .ndo_open = wilc_mac_open, 8168c2ecf20Sopenharmony_ci .ndo_stop = wilc_mac_close, 8178c2ecf20Sopenharmony_ci .ndo_start_xmit = wilc_mac_xmit, 8188c2ecf20Sopenharmony_ci .ndo_get_stats = mac_stats, 8198c2ecf20Sopenharmony_ci .ndo_set_rx_mode = wilc_set_multicast_list, 8208c2ecf20Sopenharmony_ci}; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_civoid wilc_netdev_cleanup(struct wilc *wilc) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci struct wilc_vif *vif; 8258c2ecf20Sopenharmony_ci int srcu_idx, ifc_cnt = 0; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci if (!wilc) 8288c2ecf20Sopenharmony_ci return; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci if (wilc->firmware) { 8318c2ecf20Sopenharmony_ci release_firmware(wilc->firmware); 8328c2ecf20Sopenharmony_ci wilc->firmware = NULL; 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci srcu_idx = srcu_read_lock(&wilc->srcu); 8368c2ecf20Sopenharmony_ci list_for_each_entry_rcu(vif, &wilc->vif_list, list) { 8378c2ecf20Sopenharmony_ci if (vif->ndev) 8388c2ecf20Sopenharmony_ci unregister_netdev(vif->ndev); 8398c2ecf20Sopenharmony_ci } 8408c2ecf20Sopenharmony_ci srcu_read_unlock(&wilc->srcu, srcu_idx); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci wilc_wfi_deinit_mon_interface(wilc, false); 8438c2ecf20Sopenharmony_ci flush_workqueue(wilc->hif_workqueue); 8448c2ecf20Sopenharmony_ci destroy_workqueue(wilc->hif_workqueue); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci while (ifc_cnt < WILC_NUM_CONCURRENT_IFC) { 8478c2ecf20Sopenharmony_ci mutex_lock(&wilc->vif_mutex); 8488c2ecf20Sopenharmony_ci if (wilc->vif_num <= 0) { 8498c2ecf20Sopenharmony_ci mutex_unlock(&wilc->vif_mutex); 8508c2ecf20Sopenharmony_ci break; 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci vif = wilc_get_wl_to_vif(wilc); 8538c2ecf20Sopenharmony_ci if (!IS_ERR(vif)) 8548c2ecf20Sopenharmony_ci list_del_rcu(&vif->list); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci wilc->vif_num--; 8578c2ecf20Sopenharmony_ci mutex_unlock(&wilc->vif_mutex); 8588c2ecf20Sopenharmony_ci synchronize_srcu(&wilc->srcu); 8598c2ecf20Sopenharmony_ci ifc_cnt++; 8608c2ecf20Sopenharmony_ci } 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci wilc_wlan_cfg_deinit(wilc); 8638c2ecf20Sopenharmony_ci wlan_deinit_locks(wilc); 8648c2ecf20Sopenharmony_ci kfree(wilc->bus_data); 8658c2ecf20Sopenharmony_ci wiphy_unregister(wilc->wiphy); 8668c2ecf20Sopenharmony_ci wiphy_free(wilc->wiphy); 8678c2ecf20Sopenharmony_ci} 8688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wilc_netdev_cleanup); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_cistatic u8 wilc_get_available_idx(struct wilc *wl) 8718c2ecf20Sopenharmony_ci{ 8728c2ecf20Sopenharmony_ci int idx = 0; 8738c2ecf20Sopenharmony_ci struct wilc_vif *vif; 8748c2ecf20Sopenharmony_ci int srcu_idx; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci srcu_idx = srcu_read_lock(&wl->srcu); 8778c2ecf20Sopenharmony_ci list_for_each_entry_rcu(vif, &wl->vif_list, list) { 8788c2ecf20Sopenharmony_ci if (vif->idx == 0) 8798c2ecf20Sopenharmony_ci idx = 1; 8808c2ecf20Sopenharmony_ci else 8818c2ecf20Sopenharmony_ci idx = 0; 8828c2ecf20Sopenharmony_ci } 8838c2ecf20Sopenharmony_ci srcu_read_unlock(&wl->srcu, srcu_idx); 8848c2ecf20Sopenharmony_ci return idx; 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_cistruct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name, 8888c2ecf20Sopenharmony_ci int vif_type, enum nl80211_iftype type, 8898c2ecf20Sopenharmony_ci bool rtnl_locked) 8908c2ecf20Sopenharmony_ci{ 8918c2ecf20Sopenharmony_ci struct net_device *ndev; 8928c2ecf20Sopenharmony_ci struct wilc_vif *vif; 8938c2ecf20Sopenharmony_ci int ret; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci ndev = alloc_etherdev(sizeof(*vif)); 8968c2ecf20Sopenharmony_ci if (!ndev) 8978c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci vif = netdev_priv(ndev); 9008c2ecf20Sopenharmony_ci ndev->ieee80211_ptr = &vif->priv.wdev; 9018c2ecf20Sopenharmony_ci strcpy(ndev->name, name); 9028c2ecf20Sopenharmony_ci vif->wilc = wl; 9038c2ecf20Sopenharmony_ci vif->ndev = ndev; 9048c2ecf20Sopenharmony_ci ndev->ml_priv = vif; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci ndev->netdev_ops = &wilc_netdev_ops; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci SET_NETDEV_DEV(ndev, wiphy_dev(wl->wiphy)); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci vif->priv.wdev.wiphy = wl->wiphy; 9118c2ecf20Sopenharmony_ci vif->priv.wdev.netdev = ndev; 9128c2ecf20Sopenharmony_ci vif->priv.wdev.iftype = type; 9138c2ecf20Sopenharmony_ci vif->priv.dev = ndev; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci if (rtnl_locked) 9168c2ecf20Sopenharmony_ci ret = register_netdevice(ndev); 9178c2ecf20Sopenharmony_ci else 9188c2ecf20Sopenharmony_ci ret = register_netdev(ndev); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci if (ret) { 9218c2ecf20Sopenharmony_ci free_netdev(ndev); 9228c2ecf20Sopenharmony_ci return ERR_PTR(-EFAULT); 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci ndev->needs_free_netdev = true; 9268c2ecf20Sopenharmony_ci vif->iftype = vif_type; 9278c2ecf20Sopenharmony_ci vif->idx = wilc_get_available_idx(wl); 9288c2ecf20Sopenharmony_ci vif->mac_opened = 0; 9298c2ecf20Sopenharmony_ci mutex_lock(&wl->vif_mutex); 9308c2ecf20Sopenharmony_ci list_add_tail_rcu(&vif->list, &wl->vif_list); 9318c2ecf20Sopenharmony_ci wl->vif_num += 1; 9328c2ecf20Sopenharmony_ci mutex_unlock(&wl->vif_mutex); 9338c2ecf20Sopenharmony_ci synchronize_srcu(&wl->srcu); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci return vif; 9368c2ecf20Sopenharmony_ci} 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 9398c2ecf20Sopenharmony_ciMODULE_FIRMWARE(WILC1000_FW(WILC1000_API_VER)); 940