/* * Copyright (c) 2022, Fuzhou Rockchip Electronics Co., Ltd * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ /*Linux version 3.4.0 compilation*/ //#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)) #include //#endif #include #include #include #include #include #include #include #include <../net/mac80211/ieee80211_i.h> #include "rk960.h" #include "txrx.h" #include "hwbus.h" #include "fwio.h" #include "hwio.h" #include "bh.h" #include "sta.h" #include "ap.h" #include "scan.h" #include "debug.h" #include "pm.h" MODULE_AUTHOR("Rockchips"); MODULE_DESCRIPTION("Rockchips RK960 Wireless Lan Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("rk960_core"); static int jtag_debug = 0; module_param(jtag_debug, int, 0644); MODULE_PARM_DESC(jtag_debug, "jtag debug"); static int sdio_width = 4; module_param(sdio_width, int, 0644); MODULE_PARM_DESC(sdio_width, "sdio width"); static int sgi = 0; module_param(sgi, int, 0644); MODULE_PARM_DESC(sgi, "short gi"); static int stbc = 0; module_param(stbc, int, 0644); MODULE_PARM_DESC(stbc, "stbc"); static int ht_support = 1; module_param(ht_support, int, 0644); MODULE_PARM_DESC(ht_support, "ht support"); static int mcs_mask = 0xFF; module_param(mcs_mask, int, 0644); MODULE_PARM_DESC(mcs_mask, "mcs mask"); #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) int rk960_vendor_init(struct wiphy *wiphy); #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) #define vfs_write(fp, buf, len, pos) kernel_write(fp, buf, len, pos) #define vfs_read(fp, buf, len, pos) kernel_read(fp, buf, len, pos) #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) */ /* Accept MAC address of the form macaddr=0x00,0x80,0xE1,0x30,0x40,0x50 */ static u8 rk960_mac_templates[RK960_MAX_VIFS][ETH_ALEN] = { #ifndef CUSTOM_FEATURE /* To use macaddr of customers */ {0x00, 0x80, 0xe1, 0x01, 0x02, 0x03}, {0x00, 0x80, 0xe1, 0x01, 0x02, 0x01}, #else {0x00, 0x12, 0x34, 0x01, 0x02, 0x03}, {0x00, 0x12, 0x34, 0x01, 0x02, 0x01}, #endif }; module_param_array_named(macaddr, rk960_mac_templates[0], byte, NULL, S_IRUGO); module_param_array_named(macaddr2, rk960_mac_templates[1], byte, NULL, S_IRUGO); MODULE_PARM_DESC(macaddr, "First MAC address"); MODULE_PARM_DESC(macaddr2, "Second MAC address"); #ifdef CUSTOM_FEATURE /* To use macaddr and PS Mode of customers */ #define PATH_WIFI_MACADDR "/efs/wifi/.mac.info" #define PATH_WIFI_MACADDR_TMP "/data/.mac.info" #define PATH_WIFI_PSM_INFO "/data/.psm.info" static int savedpsm = 0; #endif static u8 rk960_tx_max_agg_num_tbl[8] = { 2, 4, 8, 12, 16, 16, 16, 16 }; /* TODO: use rates and channels from the device */ #define RATETAB_ENT(_rate, _rateid, _flags) \ { \ .bitrate = (_rate), \ .hw_value = (_rateid), \ .flags = (_flags), \ } static struct ieee80211_rate rk960_rates[] = { RATETAB_ENT(10, 0, 0), RATETAB_ENT(20, 1, 0), RATETAB_ENT(55, 2, 0), RATETAB_ENT(110, 3, 0), RATETAB_ENT(60, 6, 0), RATETAB_ENT(90, 7, 0), RATETAB_ENT(120, 8, 0), RATETAB_ENT(180, 9, 0), RATETAB_ENT(240, 10, 0), RATETAB_ENT(360, 11, 0), RATETAB_ENT(480, 12, 0), RATETAB_ENT(540, 13, 0), }; static struct ieee80211_rate rk960_mcs_rates[] = { RATETAB_ENT(65, 14, IEEE80211_TX_RC_MCS), RATETAB_ENT(130, 15, IEEE80211_TX_RC_MCS), RATETAB_ENT(195, 16, IEEE80211_TX_RC_MCS), RATETAB_ENT(260, 17, IEEE80211_TX_RC_MCS), RATETAB_ENT(390, 18, IEEE80211_TX_RC_MCS), RATETAB_ENT(520, 19, IEEE80211_TX_RC_MCS), RATETAB_ENT(585, 20, IEEE80211_TX_RC_MCS), RATETAB_ENT(650, 21, IEEE80211_TX_RC_MCS), }; #define rk960_a_rates (rk960_rates + 4) #define rk960_a_rates_size (ARRAY_SIZE(rk960_rates) - 4) #define rk960_g_rates (rk960_rates + 0) #define rk960_g_rates_size (ARRAY_SIZE(rk960_rates)) #define rk960_n_rates (rk960_mcs_rates) #define rk960_n_rates_size (ARRAY_SIZE(rk960_mcs_rates)) #define CHAN2G(_channel, _freq, _flags) { \ .band = IEEE80211_BAND_2GHZ, \ .center_freq = (_freq), \ .hw_value = (_channel), \ .flags = (_flags), \ .max_antenna_gain = 0, \ .max_power = 30, \ } #define CHAN5G(_channel, _flags) { \ .band = IEEE80211_BAND_5GHZ, \ .center_freq = 5000 + (5 * (_channel)), \ .hw_value = (_channel), \ .flags = (_flags), \ .max_antenna_gain = 0, \ .max_power = 30, \ } static struct ieee80211_channel rk960_2ghz_chantable[] = { 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), }; #ifdef CONFIG_RK960_5GHZ_SUPPORT static struct ieee80211_channel rk960_5ghz_chantable[] = { CHAN5G(34, 0), CHAN5G(36, 0), CHAN5G(38, 0), CHAN5G(40, 0), CHAN5G(42, 0), CHAN5G(44, 0), CHAN5G(46, 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(149, 0), CHAN5G(153, 0), CHAN5G(157, 0), CHAN5G(161, 0), CHAN5G(165, 0), CHAN5G(184, 0), CHAN5G(188, 0), CHAN5G(192, 0), CHAN5G(196, 0), CHAN5G(200, 0), CHAN5G(204, 0), CHAN5G(208, 0), CHAN5G(212, 0), CHAN5G(216, 0), }; #endif /* CONFIG_RK960_5GHZ_SUPPORT */ static struct ieee80211_supported_band rk960_band_2ghz = { .channels = rk960_2ghz_chantable, .n_channels = ARRAY_SIZE(rk960_2ghz_chantable), .bitrates = rk960_g_rates, .n_bitrates = rk960_g_rates_size, #if 1 .ht_cap = { .cap = IEEE80211_HT_CAP_GRN_FLD /*| IEEE80211_HT_CAP_SGI_20 */ /*| (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) */ , .ht_supported = 1, .ampdu_factor = IEEE80211_HT_MAX_AMPDU_32K, .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, .mcs = { .rx_mask[0] = 0xFF, .rx_highest = __cpu_to_le16(0x41), .tx_params = IEEE80211_HT_MCS_TX_DEFINED, }, }, #endif }; #ifdef CONFIG_RK960_5GHZ_SUPPORT static struct ieee80211_supported_band rk960_band_5ghz = { .channels = rk960_5ghz_chantable, .n_channels = ARRAY_SIZE(rk960_5ghz_chantable), .bitrates = rk960_a_rates, .n_bitrates = rk960_a_rates_size, .ht_cap = { .cap = IEEE80211_HT_CAP_GRN_FLD | (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), .ht_supported = 1, .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, .mcs = { .rx_mask[0] = 0xFF, .rx_highest = __cpu_to_le16(0x41), .tx_params = IEEE80211_HT_MCS_TX_DEFINED, }, }, }; #endif /* CONFIG_RK960_5GHZ_SUPPORT */ static const unsigned long rk960_ttl[] = { 1 * HZ, /* VO */ 2 * HZ, /* VI */ 5 * HZ, /* BE */ 10 * HZ /* BK */ }; static const struct ieee80211_ops rk960_ops = { .start = rk960_start, .stop = rk960_stop, .add_interface = rk960_add_interface, .remove_interface = rk960_remove_interface, .change_interface = rk960_change_interface, .tx = rk960_tx, .hw_scan = rk960_hw_scan, #ifdef ROAM_OFFLOAD .sched_scan_start = rk960_hw_sched_scan_start, .sched_scan_stop = rk960_hw_sched_scan_stop, #endif /*ROAM_OFFLOAD */ .set_tim = rk960_set_tim, .sta_notify = rk960_sta_notify, .sta_add = rk960_sta_add, .sta_remove = rk960_sta_remove, .set_key = rk960_set_key, .set_rts_threshold = rk960_set_rts_threshold, .config = rk960_config, .bss_info_changed = rk960_bss_info_changed, .prepare_multicast = rk960_prepare_multicast, .configure_filter = rk960_configure_filter, .conf_tx = rk960_conf_tx, .get_stats = rk960_get_stats, .ampdu_action = rk960_ampdu_action, .flush = rk960_flush, #ifdef CONFIG_PM .suspend = rk960_wow_suspend, .resume = rk960_wow_resume, #endif /* CONFIG_PM */ /* Intentionally not offloaded: */ /*.channel_switch = rk960_channel_switch, */ .remain_on_channel = rk960_remain_on_channel, .cancel_remain_on_channel = rk960_cancel_remain_on_channel, #ifdef IPV6_FILTERING // .set_data_filter = rk960_set_data_filter, #endif /*IPV6_FILTERING */ #ifdef CONFIG_RK960_TESTMODE .testmode_cmd = rk960_testmode_cmd, #endif /* CONFIG_RK960_TESTMODE */ }; static const struct wiphy_wowlan_support uccp_wowlan_support = { .flags = WIPHY_WOWLAN_ANY, }; int rk960_jtag_debug_enable(void) { return jtag_debug; } int rk960_get_sdio_width_param(void) { return sdio_width; } void rk960_sdio_width_switch(struct rk960_common *hw_priv) { int src_width = rk960_sdio_get_bus_width(hw_priv); int dst_width = sdio_width; if (jtag_debug) return; if (src_width != dst_width) { RK960_INFO_MAIN("%s: %dbit -> %dbit\n", __func__, src_width, dst_width); wsm_set_sdio_data_width(hw_priv, dst_width, 0); rk960_sdio_set_bus_width(hw_priv, dst_width, 1); } } /*void rk960_delba_process(struct rk960_common *hw_priv) { struct ieee80211_vif *vif; struct rk960_vif *priv; struct ieee80211_sub_if_data *sdata = NULL; int if_id = 0; int i; rk960_hw_vif_read_lock(&hw_priv->vif_list_lock); vif = hw_priv->vif_list[if_id]; if (vif) sdata = vif_to_sdata(vif); priv = rk960_get_vif_from_ieee80211_hw_priv(hw_priv, if_id); rk960_hw_vif_read_unlock(&hw_priv->vif_list_lock); if (sdata && priv && priv->join_status == RK960_JOIN_STATUS_STA) { for (i = 0; i <= 7; i++) ieee80211_send_delba(sdata, priv->join_bssid, i, WLAN_BACK_RECIPIENT, WLAN_REASON_QSTA_REQUIRE_SETUP); } }*/ void rk960_fw_error_work(struct work_struct *work) { struct rk960_common *hw_priv = container_of(work, struct rk960_common, fw_err_work); int wanted = hw_priv->wsm_caps.firmwareReady + 1; if (!hw_priv->fw_error_enable) BUG_ON(1); // 1. reset rk960 rockchip_wifi_power(0); mdelay(10); rockchip_wifi_power(1); mdelay(50); rk960_sdio_recovery_init(hw_priv); // 2. download fw rk960_sdio_device_init(hw_priv->hwbus_priv); hw_priv->wsm_rx_seq = 0; atomic_set(&hw_priv->evt_idx, 0); rk960_download_fw(hw_priv, 1); hw_priv->wsm_tx_seq = 0; hw_priv->hw_bufs_used = 0; atomic_set(&hw_priv->msg_idx, 0); if (wait_event_interruptible_timeout(hw_priv->wsm_startup_done, hw_priv->wsm_caps.firmwareReady == wanted, 2 * HZ) <= 0) { RK960_ERROR_FWREC("Timeout waiting on device startup\n"); return; } //rk960_sdio_width_switch(hw_priv); wsm_set_fw_recovery(hw_priv, &hw_priv->wsm_rec_info); memset(&hw_priv->wsm_rec_info, 0, sizeof(struct wsm_rec_info)); // 3. recovery cmds wsm_send_fw_recovery_cmd(hw_priv); // 4. delba process //rk960_delba_process(hw_priv); // 5. complete unfinished event (scan, pending tx) //rk960_pending_scan_complete_indication(hw_priv); wsm_set_pm_indication(hw_priv, NULL); mutex_unlock(&hw_priv->wsm_cmd_save_mux); rk960_tx_queues_unlock(hw_priv); wsm_unlock_tx_rec(hw_priv); hw_priv->fw_error_processing = 0; RK960_INFO_FWREC("-------- fw error recovery end --------\n"); } #ifdef RK960_FW_ERROR_RECOVERY void rk960_pending_wsm_cmd(struct rk960_common *hw_priv) { if (hw_priv->wsm_cmd.ptr) { spin_lock(&hw_priv->wsm_cmd.lock); hw_priv->wsm_cmd.ret = 0; hw_priv->wsm_cmd.done = 1; hw_priv->wsm_cmd.ptr = NULL; spin_unlock(&hw_priv->wsm_cmd.lock); wake_up(&hw_priv->wsm_cmd_wq); } } void rk960_signal_fw_error(struct rk960_common *hw_priv, int reason) { int idx; if (!hw_priv->fw_error_processing) { RK960_INFO_FWREC("%s\n", __func__); hw_priv->fw_error_processing = 1; wsm_lock_tx_rec(hw_priv); rk960_tx_queues_lock(hw_priv); rk960_pm_stay_awake(&hw_priv->pm_state, 3 * HZ); hw_priv->device_can_sleep = false; hw_priv->device_wakeing = false; mutex_lock(&hw_priv->wsm_cmd_save_mux); wake_up(&hw_priv->tx_queue_stats.wait_link_id_empty); rk960_pending_wsm_cmd(hw_priv); rk960_queue_flush_pending_tx(hw_priv, -1); BUG_ON(hw_priv->fw_error_counter >= RK960_FWERR_SIZE); idx = hw_priv->fw_error_counter; hw_priv->fw_error_reason[idx] = reason; hw_priv->fw_error_counter++; RK960_INFO_FWREC("-------- fw error" " recovery %d(%d) start --------\n", idx, reason); // trigger recovery work schedule_work(&hw_priv->fw_err_work); } else { if (reason == RK960_FWERR_REASON_SDIO) { rk960_pending_wsm_cmd(hw_priv); } } } #endif #define Rk960_WIFI_MAC_ADDR_FROM_VENDOR_STORAGE void rk960_init_mac_addr(struct rk960_common *hw_priv, int init) { int i; if (init) { // 1. check mac addr from wifi efuse if (is_valid_ether_addr(hw_priv->wifi_efuse_mac_addr)) { RK960_INFO_MAIN("wifi mac addr from efuse\n"); memcpy(hw_priv->vif_macs[0], hw_priv->wifi_efuse_mac_addr, ETH_ALEN); } else { // 2. check mac addr from host vendor storage if (rockchip_wifi_mac_addr(hw_priv->vif_macs[0]) != 0) { RK960_INFO_MAIN("rockchip_wifi_mac_addr" " failed!\n"); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) eth_random_addr(hw_priv->vif_macs[0]); #else random_ether_addr(hw_priv->vif_macs[0]); #endif } } } memcpy(hw_priv->vif_macs[1], hw_priv->vif_macs[0], ETH_ALEN); #if 0 /* Set the Locally Administered bit */ vif_macs[1][0] |= 0x02; /* Increment the MSB by 1 (excluding 2 special bits) */ vif_macs[1][0] += (1 << 2); #else for (i = 5; i >= 0; i--) { hw_priv->vif_macs[1][i]++; if (hw_priv->vif_macs[1][i] != 0) { break; } } #endif // 3. register mac addr to ieee80211_hw #ifdef Rk960_WIFI_MAC_ADDR_FROM_VENDOR_STORAGE for (i = 0; i < RK960_MAX_VIFS; i++) { memcpy(hw_priv->addresses[i].addr, hw_priv->vif_macs[i % 2], ETH_ALEN); } #else for (i = 0; i < RK960_MAX_VIFS; i++) { memcpy(hw_priv->addresses[i].addr, rk960_mac_templates[i], ETH_ALEN); } #endif if (hw_priv->addresses[0].addr[3] == 0 && hw_priv->addresses[0].addr[4] == 0 && hw_priv->addresses[0].addr[5] == 0) { get_random_bytes(&hw_priv->addresses[0].addr[3], 3); hw_priv->addresses[1].addr[3] = hw_priv->addresses[0].addr[3]; hw_priv->addresses[1].addr[4] = hw_priv->addresses[0].addr[4]; hw_priv->addresses[1].addr[5] = hw_priv->addresses[0].addr[5] + 1; } #ifdef P2P_MULTIVIF memcpy(hw_priv->addresses[2].addr, hw_priv->addresses[1].addr, ETH_ALEN); hw_priv->addresses[2].addr[4] ^= 0x80; #endif RK960_INFO_MAIN("addresses[0]: %pM\n", hw_priv->addresses[0].addr); RK960_INFO_MAIN("addresses[1]: %pM\n", hw_priv->addresses[1].addr); #ifdef P2P_MULTIVIF RK960_INFO_MAIN("addresses[2]: %pM\n", hw_priv->addresses[2].addr); #endif SET_IEEE80211_PERM_ADDR(hw_priv->hw, hw_priv->addresses[0].addr); } struct ieee80211_hw *rk960_init_common(size_t hw_priv_data_len) { int i; struct ieee80211_hw *hw; struct rk960_common *hw_priv; struct ieee80211_supported_band *sband; int band; #ifdef CUSTOM_FEATURE /* To use macaddr of customers */ char readmac[17 + 1] = { 0, }; #endif hw = ieee80211_alloc_hw(hw_priv_data_len, &rk960_ops); if (!hw) return NULL; hw_priv = hw->priv; /* TODO:COMBO this debug message can be removed */ RK960_DEBUG_MAIN("Allocated hw_priv @ %p\n", hw_priv); hw_priv->if_id_slot = 0; hw_priv->roc_if_id = -1; hw_priv->roc_if_id_last = -1; atomic_set(&hw_priv->num_vifs, 0); hw_priv->def_vif_id = -1; hw_priv->delayed_unjoin_if_id = -1; hw_priv->hwbus_rcvbuf = kmalloc(EFFECTIVE_RX_BUF_SIZE, GFP_KERNEL); if (!hw_priv->hwbus_rcvbuf) { return NULL; } hw_priv->hwbus_sndbuf = kmalloc(EFFECTIVE_TX_BUF_SIZE, GFP_KERNEL); if (!hw_priv->hwbus_sndbuf) { return NULL; } hw_priv->hw = hw; hw_priv->rates = rk960_rates; /* TODO: fetch from FW */ hw_priv->mcs_rates = rk960_n_rates; #ifdef ROAM_OFFLOAD hw_priv->auto_scanning = 0; hw_priv->frame_rcvd = 0; hw_priv->num_scanchannels = 0; hw_priv->num_2g_channels = 0; hw_priv->num_5g_channels = 0; #endif /*ROAM_OFFLOAD */ #ifdef AP_AGGREGATE_FW_FIX /* Enable block ACK for 4 TID (BE,VI,VI,VO). */ /*due to HW limitations */ hw_priv->ba_tid_mask = RK960_TX_BLOCK_ACK_ENABLED_FOR_ALL_TID; //0xB1; #else /* Enable block ACK for every TID but voice. */ hw_priv->ba_tid_mask = 0x3F; #endif #if 0 /* Enable block ACK for every TID but voice. */ hw_priv->ba_tid_mask = 0x3F; #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) ieee80211_hw_set(hw, NEED_DTIM_BEFORE_ASSOC); ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW); ieee80211_hw_set(hw, AMPDU_AGGREGATION); ieee80211_hw_set(hw, CONNECTION_MONITOR); ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); ieee80211_hw_set(hw, SIGNAL_DBM); ieee80211_hw_set(hw, SUPPORTS_PS); ieee80211_hw_set(hw, MFP_CAPABLE); // ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); #else hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_UAPSD | // IEEE80211_HW_MFP_CAPABLE | IEEE80211_HW_CONNECTION_MONITOR; // | /*IEEE80211_HW_SUPPORTS_CQM_RSSI | */ /* Aggregation is fully controlled by firmware. * Do not need any support from the mac80211 stack */ /* IEEE80211_HW_AMPDU_AGGREGATION | */ #if defined(CONFIG_RK960_USE_STE_EXTENSIONS) /*IEEE80211_HW_SUPPORTS_P2P_PS | */ /*IEEE80211_HW_SUPPORTS_CQM_BEACON_MISS | */ /*IEEE80211_HW_SUPPORTS_CQM_TX_FAIL | */ #endif /* CONFIG_RK960_USE_STE_EXTENSIONS */ /*IEEE80211_HW_BEACON_FILTER; */ #endif hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MESH_POINT) | BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) hw->wiphy->wowlan = &uccp_wowlan_support; #else /* Support only for limited wowlan functionalities */ hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_DISCONNECT; hw->wiphy->wowlan.n_patterns = 0; #endif #if defined(CONFIG_RK960_USE_STE_EXTENSIONS) hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; #endif /* CONFIG_RK960_USE_STE_EXTENSIONS */ #if defined(CONFIG_RK960_DISABLE_BEACON_HINTS) hw->wiphy->flags |= WIPHY_FLAG_DISABLE_BEACON_HINTS; #endif hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; hw->wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; hw->wiphy->n_addresses = RK960_MAX_VIFS; hw->wiphy->addresses = hw_priv->addresses; hw->wiphy->max_remain_on_channel_duration = 500; #if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 10, 0)) hw->channel_change_time = 500; /* TODO: find actual value */ #endif /* hw_priv->beacon_req_id = cpu_to_le32(0); */ hw->queues = 4; hw_priv->noise = -94; hw->max_rates = 8; hw->max_rate_tries = 15; hw->extra_tx_headroom = WSM_TX_EXTRA_HEADROOM + 8 /* TKIP IV */ + 12 /* TKIP ICV and MIC */ ; hw->sta_data_size = sizeof(struct rk960_sta_priv); hw->vif_data_size = sizeof(struct rk960_vif); if (sgi) { RK960_INFO_MAIN("enable sgi\n"); rk960_band_2ghz.ht_cap.cap |= IEEE80211_HT_CAP_SGI_20; } if (stbc) { RK960_INFO_MAIN("enable stbc\n"); rk960_band_2ghz.ht_cap.cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); } if (!ht_support) { RK960_INFO_MAIN("disable ht\n"); rk960_band_2ghz.ht_cap.ht_supported = 0; } if (mcs_mask != 0xFF) { RK960_INFO_MAIN("mcs_mask = %x\n", mcs_mask); rk960_band_2ghz.ht_cap.mcs.rx_mask[0] = mcs_mask; } hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &rk960_band_2ghz; #ifdef CONFIG_RK960_5GHZ_SUPPORT hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &rk960_band_5ghz; #endif /* CONFIG_RK960_5GHZ_SUPPORT */ /* Channel params have to be cleared before registering wiphy again */ for (band = 0; band < IEEE80211_NUM_BANDS; band++) { sband = hw->wiphy->bands[band]; if (!sband) continue; for (i = 0; i < sband->n_channels; i++) { sband->channels[i].flags = 0; sband->channels[i].max_antenna_gain = 0; sband->channels[i].max_power = 30; } } hw->wiphy->max_scan_ssids = WSM_SCAN_MAX_NUM_OF_SSIDS; hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; #ifdef ROAM_OFFLOAD #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) hw->wiphy->max_sched_scan_reqs = 1; #endif hw->wiphy->max_match_sets = WSM_SCAN_MAX_MATCH_SETS_NUM_OF_SSIDS; hw->wiphy->max_sched_scan_ssids = WSM_SCAN_MAX_MATCH_SETS_NUM_OF_SSIDS; hw->wiphy->max_sched_scan_ie_len = IEEE80211_MAX_DATA_LEN; #endif spin_lock_init(&hw_priv->hw_bufs_used_lock); spin_lock_init(&hw_priv->vif_list_lock); mutex_init(&hw_priv->wsm_cmd_mux); mutex_init(&hw_priv->conf_mutex); mutex_init(&hw_priv->wsm_oper_lock); mutex_init(&hw_priv->wsm_cmd_save_mux); #ifdef CONFIG_RK960_TESTMODE spin_lock_init(&hw_priv->tsm_lock); #endif /*CONFIG_RK960_TESTMODE */ hw_priv->workqueue = create_singlethread_workqueue("rk960_wq"); sema_init(&hw_priv->scan.lock, 1); INIT_WORK(&hw_priv->scan.work, rk960_scan_work); #ifdef ROAM_OFFLOAD INIT_WORK(&hw_priv->scan.swork, rk960_sched_scan_work); #endif /*ROAM_OFFLOAD */ INIT_DELAYED_WORK(&hw_priv->scan.probe_work, rk960_probe_work); INIT_DELAYED_WORK(&hw_priv->scan.sched_scan_stop_work, rk960_sched_scan_stop_work); INIT_DELAYED_WORK(&hw_priv->scan.timeout, rk960_scan_timeout); #ifdef CONFIG_RK960_TESTMODE INIT_DELAYED_WORK(&hw_priv->advance_scan_timeout, rk960_advance_scan_timeout); #endif INIT_DELAYED_WORK(&hw_priv->rem_chan_timeout, rk960_rem_chan_timeout); INIT_WORK(&hw_priv->tx_policy_upload_work, tx_policy_upload_work); spin_lock_init(&hw_priv->event_queue_lock); INIT_LIST_HEAD(&hw_priv->event_queue); INIT_WORK(&hw_priv->event_handler, rk960_event_handler); INIT_WORK(&hw_priv->ba_work, rk960_ba_work); spin_lock_init(&hw_priv->ba_lock); #if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 6, 0)) timer_setup(&hw_priv->ba_timer, rk960_ba_timer, 0); #else init_timer(&hw_priv->ba_timer); hw_priv->ba_timer.data = (unsigned long)hw_priv; hw_priv->ba_timer.function = rk960_ba_timer; #endif #ifdef RK960_CSYNC_ADJUST spin_lock_init(&hw_priv->csync_lock); rk960_csync_param_init(hw_priv); INIT_WORK(&hw_priv->csync_work, rk960_csync_work); #if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 6, 0)) timer_setup(&hw_priv->csync_timer, rk960_csync_timer, 0); #else init_timer(&hw_priv->csync_timer); hw_priv->csync_timer.data = (unsigned long)hw_priv; hw_priv->csync_timer.function = rk960_csync_timer; #endif #endif hw_priv->fw_error_enable = 1; INIT_LIST_HEAD(&hw_priv->wsm_cmds_list); INIT_WORK(&hw_priv->fw_err_work, rk960_fw_error_work); wsm_sended_cmds_init(hw_priv); #ifdef SUPPORT_FWCR INIT_WORK(&hw_priv->fwcr_work, rk960_fwcr_work); init_waitqueue_head(&hw_priv->fwcr_resume_done); #endif if (unlikely(rk960_queue_stats_init(&hw_priv->tx_queue_stats, WLAN_LINK_ID_MAX, rk960_skb_dtor, hw_priv))) { ieee80211_free_hw(hw); return NULL; } for (i = 0; i < 4; ++i) { if (unlikely(rk960_queue_init(&hw_priv->tx_queue[i], &hw_priv->tx_queue_stats, i, RK960_MAX_QUEUE_SZ, rk960_ttl[i]))) { for (; i > 0; i--) rk960_queue_deinit(&hw_priv->tx_queue[i - 1]); rk960_queue_stats_deinit(&hw_priv->tx_queue_stats); ieee80211_free_hw(hw); return NULL; } } init_waitqueue_head(&hw_priv->channel_switch_done); init_waitqueue_head(&hw_priv->wsm_cmd_wq); init_waitqueue_head(&hw_priv->wsm_startup_done); init_waitqueue_head(&hw_priv->offchannel_wq); init_waitqueue_head(&hw_priv->debug_dump_done); init_waitqueue_head(&hw_priv->ps_mode_switch_done); hw_priv->offchannel_done = 0; wsm_buf_init(&hw_priv->wsm_cmd_buf); spin_lock_init(&hw_priv->wsm_cmd.lock); tx_policy_init(hw_priv); #ifdef CONFIG_RK960_TESTMODE hw_priv->test_frame.data = NULL; hw_priv->test_frame.len = 0; #endif /* CONFIG_RK960_TESTMODE */ #if defined(CONFIG_RK960_WSM_DUMPS_SHORT) hw_priv->wsm_dump_max_size = 20; #endif /* CONFIG_RK960_WSM_DUMPS_SHORT */ for (i = 0; i < RK960_MAX_VIFS; i++) hw_priv->hw_bufs_used_vif[i] = 0; #ifdef MCAST_FWDING for (i = 0; i < WSM_MAX_BUF; i++) wsm_init_release_buffer_request(hw_priv, i); hw_priv->buf_released = 0; #endif hw_priv->vif0_throttle = RK960_HOST_VIF0_11BG_THROTTLE; hw_priv->vif1_throttle = RK960_HOST_VIF1_11BG_THROTTLE; return hw; } //EXPORT_SYMBOL_GPL(rk960_init_common); int rk960_register_common(struct ieee80211_hw *dev) { struct rk960_common *hw_priv = dev->priv; int err; err = rk960_pm_init(&hw_priv->pm_state, hw_priv); if (err) { RK960_ERROR_MAIN("Cannot init PM. (%d).\n", err); return err; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) rk960_vendor_init(dev->wiphy); #endif err = ieee80211_register_hw(dev); if (err) { RK960_ERROR_MAIN("Cannot register device (%d).\n", err); rk960_pm_deinit(&hw_priv->pm_state); return err; } #ifdef CUSTOM_REG_SET regulatory_hint(dev->wiphy, "US"); #endif #ifdef CONFIG_RK960_LEDS err = rk960_init_leds(priv); if (err) { rk960_pm_deinit(&hw_priv->pm_state); ieee80211_unregister_hw(dev); return err; } #endif /* CONFIG_RK960_LEDS */ rk960_debug_init_common(hw_priv); RK960_INFO_MAIN("is registered as '%s'\n", wiphy_name(dev->wiphy)); return 0; } //EXPORT_SYMBOL_GPL(rk960_register_common); void rk960_free_common(struct ieee80211_hw *dev) { /* struct rk960_common *hw_priv = dev->priv; */ #ifdef CONFIG_RK960_TESTMODE struct rk960_common *hw_priv = dev->priv; kfree(hw_priv->test_frame.data); #endif /* CONFIG_RK960_TESTMODE */ /* unsigned int i; */ ieee80211_free_hw(dev); } //EXPORT_SYMBOL_GPL(rk960_free_common); void rk960_unregister_common(struct ieee80211_hw *dev) { struct rk960_common *hw_priv = dev->priv; int i; ieee80211_unregister_hw(dev); del_timer_sync(&hw_priv->ba_timer); #ifdef RK960_CSYNC_ADJUST del_timer_sync(&hw_priv->csync_timer); #endif //hw_priv->hwbus_ops->irq_unsubscribe(hw_priv->hwbus_priv); rk960_unregister_bh(hw_priv); rk960_debug_release_common(hw_priv); #ifdef CONFIG_RK960_LEDS rk960_unregister_leds(hw_priv); #endif /* CONFIG_RK960_LEDS */ mutex_destroy(&hw_priv->conf_mutex); wsm_buf_deinit(&hw_priv->wsm_cmd_buf); wsm_sended_cmds_deinit(hw_priv); destroy_workqueue(hw_priv->workqueue); hw_priv->workqueue = NULL; if (hw_priv->skb_cache) { dev_kfree_skb(hw_priv->skb_cache); hw_priv->skb_cache = NULL; } if (hw_priv->sdd) { release_firmware(hw_priv->sdd); hw_priv->sdd = NULL; } for (i = 0; i < 4; ++i) rk960_queue_deinit(&hw_priv->tx_queue[i]); rk960_queue_stats_deinit(&hw_priv->tx_queue_stats); rk960_pm_deinit(&hw_priv->pm_state); for (i = 0; i < RK960_MAX_VIFS; i++) { kfree(hw_priv->vif_list[i]); hw_priv->vif_list[i] = NULL; } if (hw_priv->hwbus_rcvbuf) kfree(hw_priv->hwbus_rcvbuf); if (hw_priv->hwbus_sndbuf) kfree(hw_priv->hwbus_sndbuf); } //EXPORT_SYMBOL_GPL(rk960_unregister_common); static void rk960_set_ifce_comb(struct rk960_common *hw_priv, struct ieee80211_hw *hw) { #ifdef P2P_MULTIVIF hw_priv->if_limits1[0].max = 2; #else hw_priv->if_limits1[0].max = 1; #endif hw_priv->if_limits1[0].types = BIT(NL80211_IFTYPE_STATION); hw_priv->if_limits1[1].max = 1; hw_priv->if_limits1[1].types = BIT(NL80211_IFTYPE_AP); #ifdef P2P_MULTIVIF hw_priv->if_limits2[0].max = 3; #else hw_priv->if_limits2[0].max = 2; #endif hw_priv->if_limits2[0].types = BIT(NL80211_IFTYPE_STATION); #ifdef P2P_MULTIVIF hw_priv->if_limits3[0].max = 2; #else hw_priv->if_limits3[0].max = 1; #endif hw_priv->if_limits3[0].types = BIT(NL80211_IFTYPE_STATION); hw_priv->if_limits3[1].max = 1; hw_priv->if_limits3[1].types = BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); /* TODO:COMBO: mac80211 doesn't yet support more than 1 * different channel */ hw_priv->if_combs[0].num_different_channels = 1; #ifdef P2P_MULTIVIF hw_priv->if_combs[0].max_interfaces = 3; #else hw_priv->if_combs[0].max_interfaces = 2; #endif hw_priv->if_combs[0].limits = hw_priv->if_limits1; hw_priv->if_combs[0].n_limits = 2; hw_priv->if_combs[1].num_different_channels = 1; #ifdef P2P_MULTIVIF hw_priv->if_combs[1].max_interfaces = 3; #else hw_priv->if_combs[1].max_interfaces = 2; #endif hw_priv->if_combs[1].limits = hw_priv->if_limits2; hw_priv->if_combs[1].n_limits = 1; hw_priv->if_combs[2].num_different_channels = 1; #ifdef P2P_MULTIVIF hw_priv->if_combs[2].max_interfaces = 3; #else hw_priv->if_combs[2].max_interfaces = 2; #endif hw_priv->if_combs[2].limits = hw_priv->if_limits3; hw_priv->if_combs[2].n_limits = 2; hw->wiphy->iface_combinations = &hw_priv->if_combs[0]; hw->wiphy->n_iface_combinations = 3; } int rk960_core_probe(const struct hwbus_ops *hwbus_ops, struct hwbus_priv *hwbus, struct device *pdev, int device_id, struct rk960_common **core, int ref_clk, const u8 * macaddr, const char *sdd_path, bool have_5ghz) { int err = -ENOMEM; struct ieee80211_hw *dev; struct rk960_common *hw_priv; struct wsm_operational_mode mode = { .power_mode = wsm_power_mode_quiescent, .disableMoreFlagUsage = true, }; int wait_time = 3; #ifdef CUSTOM_FEATURE /* To control ps mode */ char buffer[2]; savedpsm = mode.power_mode; if (rk960_access_file(PATH_WIFI_PSM_INFO, buffer, 2, 1) > 0) { if (buffer[0] == 0x30) { mode.power_mode = wsm_power_mode_active; } else { if (savedpsm) mode.power_mode = savedpsm; else /* Set default */ mode.power_mode = wsm_power_mode_quiescent; } RK960_INFO_MAIN("RK960 : PSM changed to %d\n", mode.power_mode); } else { RK960_INFO_MAIN("RK960 : Using default PSM %d\n", mode.power_mode); } #endif int if_id; u16 ctrl_reg; dev = rk960_init_common(sizeof(struct rk960_common)); if (!dev) goto err; hw_priv = dev->priv; hw_priv->chip_id = device_id; hw_priv->hwbus_ops = hwbus_ops; hw_priv->hwbus_priv = hwbus; hw_priv->pdev = pdev; SET_IEEE80211_DEV(hw_priv->hw, pdev); /* WSM callbacks. */ hw_priv->wsm_cbc.scan_complete = rk960_scan_complete_cb; hw_priv->wsm_cbc.tx_confirm = rk960_tx_confirm_cb; hw_priv->wsm_cbc.rx = rk960_rx_cb; hw_priv->wsm_cbc.suspend_resume = rk960_suspend_resume; /* hw_priv->wsm_cbc.set_pm_complete = rk960_set_pm_complete_cb; */ hw_priv->wsm_cbc.channel_switch = rk960_channel_switch_cb; /* Pass struct rk960_common back up */ *core = hw_priv; err = rk960_register_bh(hw_priv); if (err) goto err1; rk960_sdio_device_init(hw_priv->hwbus_priv); hw_priv->fw_hotboot = 0; rk960_bh_read_ctrl_reg(hw_priv, &ctrl_reg); if (ctrl_reg) { RK960_INFO_MAIN("FW hotboot\n"); hw_priv->fw_hotboot = 1; __rk960_clear_irq(hw_priv); } if (jtag_debug) { wait_time = 600; } else { err = rk960_load_firmware(hw_priv); if (err) goto err2; } err = rk960_sdio_irq_subscribe(hw_priv->hwbus_priv); if (err) goto err2; if (!hw_priv->fw_hotboot) rk960_start_fw(hw_priv); /*hw_priv->hwbus_ops->lock(hw_priv->hwbus_priv); WARN_ON(hw_priv->hwbus_ops->set_block_size(hw_priv->hwbus_priv, SDIO_BLOCK_SIZE)); hw_priv->hwbus_ops->unlock(hw_priv->hwbus_priv); */ rk960_set_ifce_comb(hw_priv, dev); /*hw_priv->hwbus_ops->lock(hw_priv->hwbus_priv); WARN_ON(hw_priv->hwbus_ops->set_block_size(hw_priv->hwbus_priv, SDIO_BLOCK_SIZE)); hw_priv->hwbus_ops->unlock(hw_priv->hwbus_priv); */ memcpy(hw_priv->tx_agg_ctrl.tx_max_agg_num, rk960_tx_max_agg_num_tbl, 8); #ifdef SUPPORT_FWCR rk960_fwcr_init(hw_priv); if (hw_priv->fw_hotboot) { rk960_fwcr_read(hw_priv); if (!hw_priv->fwcr_recovery) { RK960_ERROR_MAIN("%s: fwcr_read fail in fw_hotboot\n", __func__); goto err2; } hw_priv->fwcr_fw_resumed = 0; hw_priv->fwcr_update_key = 0; } #endif if (!hw_priv->fw_hotboot) { if (wait_event_interruptible_timeout(hw_priv->wsm_startup_done, hw_priv->wsm_caps. firmwareReady, wait_time * HZ) <= 0) { /* TODO: Needs to find how to reset device */ /* in QUEUE mode properly. */ RK960_ERROR_MAIN("Timeout waiting on device startup\n"); goto err3; } rk960_sdio_width_switch(hw_priv); wsm_read_efuse(hw_priv, hw_priv->efuse); RK960_INFO_MAIN("dump efuse:\n"); print_hex_dump(KERN_INFO, " ", DUMP_PREFIX_NONE, 16, 1, hw_priv->efuse, 64, 1); memcpy(hw_priv->wifi_efuse_mac_addr, &hw_priv->efuse[35], 6); memcpy(hw_priv->bt_efuse_mac_addr, &hw_priv->efuse[41], 6); rk960_init_mac_addr(hw_priv, 1); wsm_set_lpo_source(hw_priv, RK960_LPO_EXTERNAL, 0); #ifdef DISABLE_TX_POLICY wsm_disable_tx_policy(hw_priv, 1); #endif wsm_set_txpwr_comp(hw_priv); wsm_set_agg_control(hw_priv, &hw_priv->tx_agg_ctrl); for (if_id = 0; if_id < rk960_get_nr_hw_ifaces(hw_priv); if_id++) { /* Set low-power mode. */ WARN_ON(wsm_set_operational_mode (hw_priv, &mode, if_id)); /* Enable multi-TX confirmation */ WARN_ON(wsm_use_multi_tx_conf(hw_priv, true, if_id)); } } else { #ifdef SUPPORT_FWCR rk960_init_mac_addr(hw_priv, 0); #endif } err = rk960_register_common(dev); if (err) { //hw_priv->sbus_ops->hwbus_ops(hw_priv->hwbus_priv); goto err3; } #ifdef RK960_SDIO_RX_TP_TEST wsm_set_sdio_rx_tp_test(hw_priv, 1, 0); return err; #endif #ifdef RK960_SDIO_TX_TP_TEST hw_priv->sdio_tx_tp_start = 1; rk960_bh_wakeup(hw_priv); #endif *core = dev->priv; return err; err3: //sbus_ops->reset(sbus); err2: rk960_unregister_bh(hw_priv); err1: rk960_free_common(dev); err: return err; } //EXPORT_SYMBOL_GPL(rk960_core_probe); void rk960_core_release(struct rk960_common *self) { rk960_stop(self->hw); rk960_free_firmware_buf(&self->firmware); rk960_unregister_common(self->hw); /*while (atomic_read(&self->num_vifs) != 0) { msleep(10); } */ __rk960_reset_device(self); //__rk960_notify_device_pwrdown(self); rk960_free_common(self->hw); return; } //EXPORT_SYMBOL_GPL(rk960_core_release); int rk960_access_file(char *path, char *buffer, int size, int isRead) { int ret = 0; struct file *fp; //mm_segment_t old_fs = get_fs(); if (isRead) fp = filp_open(path, O_RDONLY, S_IRUSR); else fp = filp_open(path, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR); if (IS_ERR(fp)) { RK960_ERROR_MAIN("RK960 : can't open %s\n", path); return -1; } if (isRead) { /*if (fp->f_op->read == NULL) { RK960_ERROR_MAIN("RK960 : Not allow to read\n"); return -2; } else */{ fp->f_pos = 0; //set_fs(KERNEL_DS); ret = vfs_read(fp, buffer, size, &fp->f_pos); //set_fs(old_fs); } } else { /*if (fp->f_op->write == NULL) { RK960_ERROR_MAIN("RK960 : Not allow to write\n"); return -2; } else*/ { fp->f_pos = 0; //set_fs(KERNEL_DS); ret = vfs_write(fp, buffer, size, &fp->f_pos); //set_fs(old_fs); } } filp_close(fp, NULL); //RK960_DEBUG_MAIN("RK960 : access_file return code(%d)\n",ret); return ret; } int rk960_get_file_size(char *path) { struct file *filp; loff_t file_size; filp = filp_open(path, O_RDONLY, 0); if (IS_ERR(filp)) { RK960_ERROR_MAIN("RK960 : can't open %s\n", path); return 0; } file_size = filp->f_inode->i_size; filp_close(filp, NULL); return (int)file_size; }