forked from Minki/linux
Merge ath-next from ath.git
Major changes in ath10k: * add spectral scan support for 10.4 firmware * add qca6164 support * implement mesh support using firmware raw mode
This commit is contained in:
commit
f79683ded6
@ -34,16 +34,19 @@ unsigned int ath10k_debug_mask;
|
||||
static unsigned int ath10k_cryptmode_param;
|
||||
static bool uart_print;
|
||||
static bool skip_otp;
|
||||
static bool rawmode;
|
||||
|
||||
module_param_named(debug_mask, ath10k_debug_mask, uint, 0644);
|
||||
module_param_named(cryptmode, ath10k_cryptmode_param, uint, 0644);
|
||||
module_param(uart_print, bool, 0644);
|
||||
module_param(skip_otp, bool, 0644);
|
||||
module_param(rawmode, bool, 0644);
|
||||
|
||||
MODULE_PARM_DESC(debug_mask, "Debugging mask");
|
||||
MODULE_PARM_DESC(uart_print, "Uart target debugging");
|
||||
MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode");
|
||||
MODULE_PARM_DESC(cryptmode, "Crypto mode: 0-hardware, 1-software");
|
||||
MODULE_PARM_DESC(rawmode, "Use raw 802.11 frame datapath");
|
||||
|
||||
static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
{
|
||||
@ -54,6 +57,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.has_shifted_cc_wraparound = true,
|
||||
.otp_exe_param = 0,
|
||||
.channel_counters_freq_hz = 88000,
|
||||
.max_probe_resp_desc_thres = 0,
|
||||
.fw = {
|
||||
.dir = QCA988X_HW_2_0_FW_DIR,
|
||||
.fw = QCA988X_HW_2_0_FW_FILE,
|
||||
@ -70,6 +74,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.uart_pin = 6,
|
||||
.otp_exe_param = 0,
|
||||
.channel_counters_freq_hz = 88000,
|
||||
.max_probe_resp_desc_thres = 0,
|
||||
.fw = {
|
||||
.dir = QCA6174_HW_2_1_FW_DIR,
|
||||
.fw = QCA6174_HW_2_1_FW_FILE,
|
||||
@ -86,6 +91,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.uart_pin = 6,
|
||||
.otp_exe_param = 0,
|
||||
.channel_counters_freq_hz = 88000,
|
||||
.max_probe_resp_desc_thres = 0,
|
||||
.fw = {
|
||||
.dir = QCA6174_HW_3_0_FW_DIR,
|
||||
.fw = QCA6174_HW_3_0_FW_FILE,
|
||||
@ -102,6 +108,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.uart_pin = 6,
|
||||
.otp_exe_param = 0,
|
||||
.channel_counters_freq_hz = 88000,
|
||||
.max_probe_resp_desc_thres = 0,
|
||||
.fw = {
|
||||
/* uses same binaries as hw3.0 */
|
||||
.dir = QCA6174_HW_3_0_FW_DIR,
|
||||
@ -120,6 +127,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.otp_exe_param = 0x00000700,
|
||||
.continuous_frag_desc = true,
|
||||
.channel_counters_freq_hz = 150000,
|
||||
.max_probe_resp_desc_thres = 24,
|
||||
.fw = {
|
||||
.dir = QCA99X0_HW_2_0_FW_DIR,
|
||||
.fw = QCA99X0_HW_2_0_FW_FILE,
|
||||
@ -142,12 +150,17 @@ static const char *const ath10k_core_fw_feature_str[] = {
|
||||
[ATH10K_FW_FEATURE_IGNORE_OTP_RESULT] = "ignore-otp",
|
||||
[ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING] = "no-4addr-pad",
|
||||
[ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT] = "skip-clock-init",
|
||||
[ATH10K_FW_FEATURE_RAW_MODE_SUPPORT] = "raw-mode",
|
||||
};
|
||||
|
||||
static unsigned int ath10k_core_get_fw_feature_str(char *buf,
|
||||
size_t buf_len,
|
||||
enum ath10k_fw_features feat)
|
||||
{
|
||||
/* make sure that ath10k_core_fw_feature_str[] gets updated */
|
||||
BUILD_BUG_ON(ARRAY_SIZE(ath10k_core_fw_feature_str) !=
|
||||
ATH10K_FW_FEATURE_COUNT);
|
||||
|
||||
if (feat >= ARRAY_SIZE(ath10k_core_fw_feature_str) ||
|
||||
WARN_ON(!ath10k_core_fw_feature_str[feat])) {
|
||||
return scnprintf(buf, buf_len, "bit%d", feat);
|
||||
@ -1117,6 +1130,15 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
|
||||
ar->htt.max_num_amsdu = ATH10K_HTT_MAX_NUM_AMSDU_DEFAULT;
|
||||
ar->htt.max_num_ampdu = ATH10K_HTT_MAX_NUM_AMPDU_DEFAULT;
|
||||
|
||||
if (rawmode) {
|
||||
if (!test_bit(ATH10K_FW_FEATURE_RAW_MODE_SUPPORT,
|
||||
ar->fw_features)) {
|
||||
ath10k_err(ar, "rawmode = 1 requires support from firmware");
|
||||
return -EINVAL;
|
||||
}
|
||||
set_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags);
|
||||
}
|
||||
|
||||
if (test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {
|
||||
ar->wmi.rx_decap_mode = ATH10K_HW_TXRX_RAW;
|
||||
|
||||
@ -1714,6 +1736,7 @@ void ath10k_core_destroy(struct ath10k *ar)
|
||||
destroy_workqueue(ar->workqueue_aux);
|
||||
|
||||
ath10k_debug_destroy(ar);
|
||||
ath10k_wmi_free_host_mem(ar);
|
||||
ath10k_mac_destroy(ar);
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_core_destroy);
|
||||
|
@ -612,6 +612,11 @@ struct ath10k {
|
||||
|
||||
u32 channel_counters_freq_hz;
|
||||
|
||||
/* Mgmt tx descriptors threshold for limiting probe response
|
||||
* frames.
|
||||
*/
|
||||
u32 max_probe_resp_desc_thres;
|
||||
|
||||
struct ath10k_hw_params_fw {
|
||||
const char *dir;
|
||||
const char *fw;
|
||||
|
@ -1485,6 +1485,7 @@ struct ath10k_htt {
|
||||
spinlock_t tx_lock;
|
||||
int max_num_pending_tx;
|
||||
int num_pending_tx;
|
||||
int num_pending_mgmt_tx;
|
||||
struct idr pending_tx;
|
||||
wait_queue_head_t empty_tx_wq;
|
||||
struct dma_pool *tx_pool;
|
||||
@ -1587,7 +1588,7 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
|
||||
u8 max_subfrms_ampdu,
|
||||
u8 max_subfrms_amsdu);
|
||||
|
||||
void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt);
|
||||
void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt, bool limit_mgmt_desc);
|
||||
int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb);
|
||||
void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id);
|
||||
int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *);
|
||||
|
@ -643,6 +643,8 @@ struct amsdu_subframe_hdr {
|
||||
__be16 len;
|
||||
} __packed;
|
||||
|
||||
#define GROUP_ID_IS_SU_MIMO(x) ((x) == 0 || (x) == 63)
|
||||
|
||||
static void ath10k_htt_rx_h_rates(struct ath10k *ar,
|
||||
struct ieee80211_rx_status *status,
|
||||
struct htt_rx_desc *rxd)
|
||||
@ -650,6 +652,7 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
|
||||
struct ieee80211_supported_band *sband;
|
||||
u8 cck, rate, bw, sgi, mcs, nss;
|
||||
u8 preamble = 0;
|
||||
u8 group_id;
|
||||
u32 info1, info2, info3;
|
||||
|
||||
info1 = __le32_to_cpu(rxd->ppdu_start.info1);
|
||||
@ -692,10 +695,50 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
|
||||
case HTT_RX_VHT_WITH_TXBF:
|
||||
/* VHT-SIG-A1 in info2, VHT-SIG-A2 in info3
|
||||
TODO check this */
|
||||
mcs = (info3 >> 4) & 0x0F;
|
||||
nss = ((info2 >> 10) & 0x07) + 1;
|
||||
bw = info2 & 3;
|
||||
sgi = info3 & 1;
|
||||
group_id = (info2 >> 4) & 0x3F;
|
||||
|
||||
if (GROUP_ID_IS_SU_MIMO(group_id)) {
|
||||
mcs = (info3 >> 4) & 0x0F;
|
||||
nss = ((info2 >> 10) & 0x07) + 1;
|
||||
} else {
|
||||
/* Hardware doesn't decode VHT-SIG-B into Rx descriptor
|
||||
* so it's impossible to decode MCS. Also since
|
||||
* firmware consumes Group Id Management frames host
|
||||
* has no knowledge regarding group/user position
|
||||
* mapping so it's impossible to pick the correct Nsts
|
||||
* from VHT-SIG-A1.
|
||||
*
|
||||
* Bandwidth and SGI are valid so report the rateinfo
|
||||
* on best-effort basis.
|
||||
*/
|
||||
mcs = 0;
|
||||
nss = 1;
|
||||
}
|
||||
|
||||
if (mcs > 0x09) {
|
||||
ath10k_warn(ar, "invalid MCS received %u\n", mcs);
|
||||
ath10k_warn(ar, "rxd %08x mpdu start %08x %08x msdu start %08x %08x ppdu start %08x %08x %08x %08x %08x\n",
|
||||
__le32_to_cpu(rxd->attention.flags),
|
||||
__le32_to_cpu(rxd->mpdu_start.info0),
|
||||
__le32_to_cpu(rxd->mpdu_start.info1),
|
||||
__le32_to_cpu(rxd->msdu_start.common.info0),
|
||||
__le32_to_cpu(rxd->msdu_start.common.info1),
|
||||
rxd->ppdu_start.info0,
|
||||
__le32_to_cpu(rxd->ppdu_start.info1),
|
||||
__le32_to_cpu(rxd->ppdu_start.info2),
|
||||
__le32_to_cpu(rxd->ppdu_start.info3),
|
||||
__le32_to_cpu(rxd->ppdu_start.info4));
|
||||
|
||||
ath10k_warn(ar, "msdu end %08x mpdu end %08x\n",
|
||||
__le32_to_cpu(rxd->msdu_end.common.info0),
|
||||
__le32_to_cpu(rxd->mpdu_end.info0));
|
||||
|
||||
ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL,
|
||||
"rx desc msdu payload: ",
|
||||
rxd->msdu_payload, 50);
|
||||
}
|
||||
|
||||
status->rate_idx = mcs;
|
||||
status->vht_nss = nss;
|
||||
|
@ -22,22 +22,28 @@
|
||||
#include "txrx.h"
|
||||
#include "debug.h"
|
||||
|
||||
void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt)
|
||||
void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt, bool limit_mgmt_desc)
|
||||
{
|
||||
if (limit_mgmt_desc)
|
||||
htt->num_pending_mgmt_tx--;
|
||||
|
||||
htt->num_pending_tx--;
|
||||
if (htt->num_pending_tx == htt->max_num_pending_tx - 1)
|
||||
ath10k_mac_tx_unlock(htt->ar, ATH10K_TX_PAUSE_Q_FULL);
|
||||
}
|
||||
|
||||
static void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt)
|
||||
static void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt,
|
||||
bool limit_mgmt_desc)
|
||||
{
|
||||
spin_lock_bh(&htt->tx_lock);
|
||||
__ath10k_htt_tx_dec_pending(htt);
|
||||
__ath10k_htt_tx_dec_pending(htt, limit_mgmt_desc);
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
}
|
||||
|
||||
static int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt)
|
||||
static int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt,
|
||||
bool limit_mgmt_desc, bool is_probe_resp)
|
||||
{
|
||||
struct ath10k *ar = htt->ar;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_bh(&htt->tx_lock);
|
||||
@ -47,6 +53,15 @@ static int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (limit_mgmt_desc) {
|
||||
if (is_probe_resp && (htt->num_pending_mgmt_tx >
|
||||
ar->hw_params.max_probe_resp_desc_thres)) {
|
||||
ret = -EBUSY;
|
||||
goto exit;
|
||||
}
|
||||
htt->num_pending_mgmt_tx++;
|
||||
}
|
||||
|
||||
htt->num_pending_tx++;
|
||||
if (htt->num_pending_tx == htt->max_num_pending_tx)
|
||||
ath10k_mac_tx_lock(htt->ar, ATH10K_TX_PAUSE_Q_FULL);
|
||||
@ -417,8 +432,19 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
||||
int len = 0;
|
||||
int msdu_id = -1;
|
||||
int res;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
|
||||
bool limit_mgmt_desc = false;
|
||||
bool is_probe_resp = false;
|
||||
|
||||
if (ar->hw_params.max_probe_resp_desc_thres) {
|
||||
limit_mgmt_desc = true;
|
||||
|
||||
if (ieee80211_is_probe_resp(hdr->frame_control))
|
||||
is_probe_resp = true;
|
||||
}
|
||||
|
||||
res = ath10k_htt_tx_inc_pending(htt, limit_mgmt_desc, is_probe_resp);
|
||||
|
||||
res = ath10k_htt_tx_inc_pending(htt);
|
||||
if (res)
|
||||
goto err;
|
||||
|
||||
@ -476,7 +502,7 @@ err_free_msdu_id:
|
||||
ath10k_htt_tx_free_msdu_id(htt, msdu_id);
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
err_tx_dec:
|
||||
ath10k_htt_tx_dec_pending(htt);
|
||||
ath10k_htt_tx_dec_pending(htt, limit_mgmt_desc);
|
||||
err:
|
||||
return res;
|
||||
}
|
||||
@ -498,8 +524,18 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
||||
dma_addr_t paddr = 0;
|
||||
u32 frags_paddr = 0;
|
||||
struct htt_msdu_ext_desc *ext_desc = NULL;
|
||||
bool limit_mgmt_desc = false;
|
||||
bool is_probe_resp = false;
|
||||
|
||||
res = ath10k_htt_tx_inc_pending(htt);
|
||||
if (unlikely(ieee80211_is_mgmt(hdr->frame_control)) &&
|
||||
ar->hw_params.max_probe_resp_desc_thres) {
|
||||
limit_mgmt_desc = true;
|
||||
|
||||
if (ieee80211_is_probe_resp(hdr->frame_control))
|
||||
is_probe_resp = true;
|
||||
}
|
||||
|
||||
res = ath10k_htt_tx_inc_pending(htt, limit_mgmt_desc, is_probe_resp);
|
||||
if (res)
|
||||
goto err;
|
||||
|
||||
@ -528,7 +564,8 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
||||
ieee80211_has_protected(hdr->frame_control)) {
|
||||
skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
|
||||
} else if (!skb_cb->htt.nohwcrypt &&
|
||||
skb_cb->txmode == ATH10K_HW_TXRX_RAW) {
|
||||
skb_cb->txmode == ATH10K_HW_TXRX_RAW &&
|
||||
ieee80211_has_protected(hdr->frame_control)) {
|
||||
skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
|
||||
}
|
||||
|
||||
@ -678,7 +715,7 @@ err_free_msdu_id:
|
||||
ath10k_htt_tx_free_msdu_id(htt, msdu_id);
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
err_tx_dec:
|
||||
ath10k_htt_tx_dec_pending(htt);
|
||||
ath10k_htt_tx_dec_pending(htt, limit_mgmt_desc);
|
||||
err:
|
||||
return res;
|
||||
}
|
||||
|
@ -413,16 +413,6 @@ enum ath10k_hw_rate_cck {
|
||||
/* Number of Copy Engines supported */
|
||||
#define CE_COUNT ar->hw_values->ce_count
|
||||
|
||||
/*
|
||||
* Total number of PCIe MSI interrupts requested for all interrupt sources.
|
||||
* PCIe standard forces this to be a power of 2.
|
||||
* Some Host OS's limit MSI requests that can be granted to 8
|
||||
* so for now we abide by this limit and avoid requesting more
|
||||
* than that.
|
||||
*/
|
||||
#define MSI_NUM_REQUEST_LOG2 3
|
||||
#define MSI_NUM_REQUEST (1<<MSI_NUM_REQUEST_LOG2)
|
||||
|
||||
/*
|
||||
* Granted MSIs are assigned as follows:
|
||||
* Firmware uses the first
|
||||
|
@ -1070,6 +1070,7 @@ static bool ath10k_mac_monitor_vdev_is_needed(struct ath10k *ar)
|
||||
return false;
|
||||
|
||||
return ar->monitor ||
|
||||
ar->filter_flags & FIF_OTHER_BSS ||
|
||||
test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
|
||||
}
|
||||
|
||||
@ -3617,9 +3618,6 @@ static int ath10k_start_scan(struct ath10k *ar,
|
||||
}
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
/* Add a 200ms margin to account for event/command processing */
|
||||
ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout,
|
||||
msecs_to_jiffies(arg->max_scan_time+200));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -4064,21 +4062,56 @@ static u32 get_nss_from_chainmask(u16 chain_mask)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ath10k_mac_get_vht_cap_bf_sts(struct ath10k *ar)
|
||||
{
|
||||
int nsts = ar->vht_cap_info;
|
||||
nsts &= IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
|
||||
nsts >>= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
|
||||
|
||||
/* If firmware does not deliver to host number of space-time
|
||||
* streams supported, assume it support up to 4 BF STS and return
|
||||
* the value for VHT CAP: nsts-1)
|
||||
* */
|
||||
if (nsts == 0)
|
||||
return 3;
|
||||
|
||||
return nsts;
|
||||
}
|
||||
|
||||
static int ath10k_mac_get_vht_cap_bf_sound_dim(struct ath10k *ar)
|
||||
{
|
||||
int sound_dim = ar->vht_cap_info;
|
||||
sound_dim &= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
|
||||
sound_dim >>=IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
|
||||
|
||||
/* If the sounding dimension is not advertised by the firmware,
|
||||
* let's use a default value of 1
|
||||
*/
|
||||
if (sound_dim == 0)
|
||||
return 1;
|
||||
|
||||
return sound_dim;
|
||||
}
|
||||
|
||||
static int ath10k_mac_set_txbf_conf(struct ath10k_vif *arvif)
|
||||
{
|
||||
u32 value = 0;
|
||||
struct ath10k *ar = arvif->ar;
|
||||
int nsts;
|
||||
int sound_dim;
|
||||
|
||||
if (ath10k_wmi_get_txbf_conf_scheme(ar) != WMI_TXBF_CONF_BEFORE_ASSOC)
|
||||
return 0;
|
||||
|
||||
nsts = ath10k_mac_get_vht_cap_bf_sts(ar);
|
||||
if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
|
||||
IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE))
|
||||
value |= SM((ar->num_rf_chains - 1), WMI_TXBF_STS_CAP_OFFSET);
|
||||
value |= SM(nsts, WMI_TXBF_STS_CAP_OFFSET);
|
||||
|
||||
sound_dim = ath10k_mac_get_vht_cap_bf_sound_dim(ar);
|
||||
if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
|
||||
IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE))
|
||||
value |= SM((ar->num_rf_chains - 1), WMI_BF_SOUND_DIM_OFFSET);
|
||||
value |= SM(sound_dim, WMI_BF_SOUND_DIM_OFFSET);
|
||||
|
||||
if (!value)
|
||||
return 0;
|
||||
@ -4175,6 +4208,14 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
arvif->vdev_type = WMI_VDEV_TYPE_IBSS;
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {
|
||||
ret = -EINVAL;
|
||||
ath10k_warn(ar, "must load driver with rawmode=1 to add mesh interfaces\n");
|
||||
goto err;
|
||||
}
|
||||
arvif->vdev_type = WMI_VDEV_TYPE_AP;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
arvif->vdev_type = WMI_VDEV_TYPE_AP;
|
||||
|
||||
@ -4215,6 +4256,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
||||
* become corrupted, e.g. have garbled IEs or out-of-date TIM bitmap.
|
||||
*/
|
||||
if (vif->type == NL80211_IFTYPE_ADHOC ||
|
||||
vif->type == NL80211_IFTYPE_MESH_POINT ||
|
||||
vif->type == NL80211_IFTYPE_AP) {
|
||||
arvif->beacon_buf = dma_zalloc_coherent(ar->dev,
|
||||
IEEE80211_MAX_FRAME_LEN,
|
||||
@ -4554,6 +4596,13 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
||||
if (ret)
|
||||
ath10k_warn(ar, "failed to update beacon template: %d\n",
|
||||
ret);
|
||||
|
||||
if (ieee80211_vif_is_mesh(vif)) {
|
||||
/* mesh doesn't use SSID but firmware needs it */
|
||||
strncpy(arvif->u.ap.ssid, "mesh",
|
||||
sizeof(arvif->u.ap.ssid));
|
||||
arvif->u.ap.ssid_len = 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_AP_PROBE_RESP) {
|
||||
@ -4751,6 +4800,11 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw,
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
/* Add a 200ms margin to account for event/command processing */
|
||||
ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout,
|
||||
msecs_to_jiffies(arg.max_scan_time +
|
||||
200));
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
@ -5293,6 +5347,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
|
||||
} else if (old_state == IEEE80211_STA_AUTH &&
|
||||
new_state == IEEE80211_STA_ASSOC &&
|
||||
(vif->type == NL80211_IFTYPE_AP ||
|
||||
vif->type == NL80211_IFTYPE_MESH_POINT ||
|
||||
vif->type == NL80211_IFTYPE_ADHOC)) {
|
||||
/*
|
||||
* New association.
|
||||
@ -5328,6 +5383,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
|
||||
} else if (old_state == IEEE80211_STA_ASSOC &&
|
||||
new_state == IEEE80211_STA_AUTH &&
|
||||
(vif->type == NL80211_IFTYPE_AP ||
|
||||
vif->type == NL80211_IFTYPE_MESH_POINT ||
|
||||
vif->type == NL80211_IFTYPE_ADHOC)) {
|
||||
/*
|
||||
* Disassociation.
|
||||
@ -5901,7 +5957,7 @@ ath10k_mac_bitrate_mask_get_single_rate(struct ath10k *ar,
|
||||
}
|
||||
|
||||
static int ath10k_mac_set_fixed_rate_params(struct ath10k_vif *arvif,
|
||||
u8 rate, u8 nss, u8 sgi)
|
||||
u8 rate, u8 nss, u8 sgi, u8 ldpc)
|
||||
{
|
||||
struct ath10k *ar = arvif->ar;
|
||||
u32 vdev_param;
|
||||
@ -5934,6 +5990,13 @@ static int ath10k_mac_set_fixed_rate_params(struct ath10k_vif *arvif,
|
||||
return ret;
|
||||
}
|
||||
|
||||
vdev_param = ar->wmi.vdev_param->ldpc;
|
||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, ldpc);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to set ldpc param %d: %d\n", ldpc, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -5997,6 +6060,7 @@ static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
|
||||
u8 rate;
|
||||
u8 nss;
|
||||
u8 sgi;
|
||||
u8 ldpc;
|
||||
int single_nss;
|
||||
int ret;
|
||||
|
||||
@ -6006,6 +6070,7 @@ static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
|
||||
band = def.chan->band;
|
||||
ht_mcs_mask = mask->control[band].ht_mcs;
|
||||
vht_mcs_mask = mask->control[band].vht_mcs;
|
||||
ldpc = !!(ar->ht_cap_info & WMI_HT_CAP_LDPC);
|
||||
|
||||
sgi = mask->control[band].gi;
|
||||
if (sgi == NL80211_TXRATE_FORCE_LGI)
|
||||
@ -6044,7 +6109,7 @@ static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
ret = ath10k_mac_set_fixed_rate_params(arvif, rate, nss, sgi);
|
||||
ret = ath10k_mac_set_fixed_rate_params(arvif, rate, nss, sgi, ldpc);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to set fixed rate params on vdev %i: %d\n",
|
||||
arvif->vdev_id, ret);
|
||||
@ -6218,6 +6283,94 @@ ath10k_mac_update_rx_channel(struct ath10k *ar,
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void
|
||||
ath10k_mac_update_vif_chan(struct ath10k *ar,
|
||||
struct ieee80211_vif_chanctx_switch *vifs,
|
||||
int n_vifs)
|
||||
{
|
||||
struct ath10k_vif *arvif;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
/* First stop monitor interface. Some FW versions crash if there's a
|
||||
* lone monitor interface.
|
||||
*/
|
||||
if (ar->monitor_started)
|
||||
ath10k_monitor_stop(ar);
|
||||
|
||||
for (i = 0; i < n_vifs; i++) {
|
||||
arvif = ath10k_vif_to_arvif(vifs[i].vif);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_MAC,
|
||||
"mac chanctx switch vdev_id %i freq %hu->%hu width %d->%d\n",
|
||||
arvif->vdev_id,
|
||||
vifs[i].old_ctx->def.chan->center_freq,
|
||||
vifs[i].new_ctx->def.chan->center_freq,
|
||||
vifs[i].old_ctx->def.width,
|
||||
vifs[i].new_ctx->def.width);
|
||||
|
||||
if (WARN_ON(!arvif->is_started))
|
||||
continue;
|
||||
|
||||
if (WARN_ON(!arvif->is_up))
|
||||
continue;
|
||||
|
||||
ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to down vdev %d: %d\n",
|
||||
arvif->vdev_id, ret);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* All relevant vdevs are downed and associated channel resources
|
||||
* should be available for the channel switch now.
|
||||
*/
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
ath10k_mac_update_rx_channel(ar, NULL, vifs, n_vifs);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
for (i = 0; i < n_vifs; i++) {
|
||||
arvif = ath10k_vif_to_arvif(vifs[i].vif);
|
||||
|
||||
if (WARN_ON(!arvif->is_started))
|
||||
continue;
|
||||
|
||||
if (WARN_ON(!arvif->is_up))
|
||||
continue;
|
||||
|
||||
ret = ath10k_mac_setup_bcn_tmpl(arvif);
|
||||
if (ret)
|
||||
ath10k_warn(ar, "failed to update bcn tmpl during csa: %d\n",
|
||||
ret);
|
||||
|
||||
ret = ath10k_mac_setup_prb_tmpl(arvif);
|
||||
if (ret)
|
||||
ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n",
|
||||
ret);
|
||||
|
||||
ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to restart vdev %d: %d\n",
|
||||
arvif->vdev_id, ret);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
|
||||
arvif->bssid);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to bring vdev up %d: %d\n",
|
||||
arvif->vdev_id, ret);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ath10k_monitor_recalc(ar);
|
||||
}
|
||||
|
||||
static int
|
||||
ath10k_mac_op_add_chanctx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_chanctx_conf *ctx)
|
||||
@ -6264,12 +6417,52 @@ ath10k_mac_op_remove_chanctx(struct ieee80211_hw *hw,
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
}
|
||||
|
||||
struct ath10k_mac_change_chanctx_arg {
|
||||
struct ieee80211_chanctx_conf *ctx;
|
||||
struct ieee80211_vif_chanctx_switch *vifs;
|
||||
int n_vifs;
|
||||
int next_vif;
|
||||
};
|
||||
|
||||
static void
|
||||
ath10k_mac_change_chanctx_cnt_iter(void *data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath10k_mac_change_chanctx_arg *arg = data;
|
||||
|
||||
if (rcu_access_pointer(vif->chanctx_conf) != arg->ctx)
|
||||
return;
|
||||
|
||||
arg->n_vifs++;
|
||||
}
|
||||
|
||||
static void
|
||||
ath10k_mac_change_chanctx_fill_iter(void *data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath10k_mac_change_chanctx_arg *arg = data;
|
||||
struct ieee80211_chanctx_conf *ctx;
|
||||
|
||||
ctx = rcu_access_pointer(vif->chanctx_conf);
|
||||
if (ctx != arg->ctx)
|
||||
return;
|
||||
|
||||
if (WARN_ON(arg->next_vif == arg->n_vifs))
|
||||
return;
|
||||
|
||||
arg->vifs[arg->next_vif].vif = vif;
|
||||
arg->vifs[arg->next_vif].old_ctx = ctx;
|
||||
arg->vifs[arg->next_vif].new_ctx = ctx;
|
||||
arg->next_vif++;
|
||||
}
|
||||
|
||||
static void
|
||||
ath10k_mac_op_change_chanctx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_chanctx_conf *ctx,
|
||||
u32 changed)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_mac_change_chanctx_arg arg = { .ctx = ctx };
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
@ -6283,6 +6476,30 @@ ath10k_mac_op_change_chanctx(struct ieee80211_hw *hw,
|
||||
if (WARN_ON(changed & IEEE80211_CHANCTX_CHANGE_CHANNEL))
|
||||
goto unlock;
|
||||
|
||||
if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH) {
|
||||
ieee80211_iterate_active_interfaces_atomic(
|
||||
hw,
|
||||
IEEE80211_IFACE_ITER_NORMAL,
|
||||
ath10k_mac_change_chanctx_cnt_iter,
|
||||
&arg);
|
||||
if (arg.n_vifs == 0)
|
||||
goto radar;
|
||||
|
||||
arg.vifs = kcalloc(arg.n_vifs, sizeof(arg.vifs[0]),
|
||||
GFP_KERNEL);
|
||||
if (!arg.vifs)
|
||||
goto radar;
|
||||
|
||||
ieee80211_iterate_active_interfaces_atomic(
|
||||
hw,
|
||||
IEEE80211_IFACE_ITER_NORMAL,
|
||||
ath10k_mac_change_chanctx_fill_iter,
|
||||
&arg);
|
||||
ath10k_mac_update_vif_chan(ar, arg.vifs, arg.n_vifs);
|
||||
kfree(arg.vifs);
|
||||
}
|
||||
|
||||
radar:
|
||||
ath10k_recalc_radar_detection(ar);
|
||||
|
||||
/* FIXME: How to configure Rx chains properly? */
|
||||
@ -6402,91 +6619,13 @@ ath10k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw,
|
||||
enum ieee80211_chanctx_switch_mode mode)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_vif *arvif;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_MAC,
|
||||
"mac chanctx switch n_vifs %d mode %d\n",
|
||||
n_vifs, mode);
|
||||
|
||||
/* First stop monitor interface. Some FW versions crash if there's a
|
||||
* lone monitor interface.
|
||||
*/
|
||||
if (ar->monitor_started)
|
||||
ath10k_monitor_stop(ar);
|
||||
|
||||
for (i = 0; i < n_vifs; i++) {
|
||||
arvif = ath10k_vif_to_arvif(vifs[i].vif);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_MAC,
|
||||
"mac chanctx switch vdev_id %i freq %hu->%hu width %d->%d\n",
|
||||
arvif->vdev_id,
|
||||
vifs[i].old_ctx->def.chan->center_freq,
|
||||
vifs[i].new_ctx->def.chan->center_freq,
|
||||
vifs[i].old_ctx->def.width,
|
||||
vifs[i].new_ctx->def.width);
|
||||
|
||||
if (WARN_ON(!arvif->is_started))
|
||||
continue;
|
||||
|
||||
if (WARN_ON(!arvif->is_up))
|
||||
continue;
|
||||
|
||||
ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to down vdev %d: %d\n",
|
||||
arvif->vdev_id, ret);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* All relevant vdevs are downed and associated channel resources
|
||||
* should be available for the channel switch now.
|
||||
*/
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
ath10k_mac_update_rx_channel(ar, NULL, vifs, n_vifs);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
for (i = 0; i < n_vifs; i++) {
|
||||
arvif = ath10k_vif_to_arvif(vifs[i].vif);
|
||||
|
||||
if (WARN_ON(!arvif->is_started))
|
||||
continue;
|
||||
|
||||
if (WARN_ON(!arvif->is_up))
|
||||
continue;
|
||||
|
||||
ret = ath10k_mac_setup_bcn_tmpl(arvif);
|
||||
if (ret)
|
||||
ath10k_warn(ar, "failed to update bcn tmpl during csa: %d\n",
|
||||
ret);
|
||||
|
||||
ret = ath10k_mac_setup_prb_tmpl(arvif);
|
||||
if (ret)
|
||||
ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n",
|
||||
ret);
|
||||
|
||||
ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to restart vdev %d: %d\n",
|
||||
arvif->vdev_id, ret);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
|
||||
arvif->bssid);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to bring vdev up %d: %d\n",
|
||||
arvif->vdev_id, ret);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ath10k_monitor_recalc(ar);
|
||||
ath10k_mac_update_vif_chan(ar, vifs, n_vifs);
|
||||
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return 0;
|
||||
@ -6642,6 +6781,9 @@ static const struct ieee80211_iface_limit ath10k_if_limits[] = {
|
||||
{
|
||||
.max = 7,
|
||||
.types = BIT(NL80211_IFTYPE_AP)
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
| BIT(NL80211_IFTYPE_MESH_POINT)
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
@ -6649,6 +6791,9 @@ static const struct ieee80211_iface_limit ath10k_10x_if_limits[] = {
|
||||
{
|
||||
.max = 8,
|
||||
.types = BIT(NL80211_IFTYPE_AP)
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
| BIT(NL80211_IFTYPE_MESH_POINT)
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
@ -6686,6 +6831,9 @@ static const struct ieee80211_iface_limit ath10k_tlv_if_limit[] = {
|
||||
{
|
||||
.max = 2,
|
||||
.types = BIT(NL80211_IFTYPE_AP) |
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
BIT(NL80211_IFTYPE_MESH_POINT) |
|
||||
#endif
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO),
|
||||
},
|
||||
@ -6707,6 +6855,9 @@ static const struct ieee80211_iface_limit ath10k_tlv_qcs_if_limit[] = {
|
||||
{
|
||||
.max = 1,
|
||||
.types = BIT(NL80211_IFTYPE_AP) |
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
BIT(NL80211_IFTYPE_MESH_POINT) |
|
||||
#endif
|
||||
BIT(NL80211_IFTYPE_P2P_GO),
|
||||
},
|
||||
{
|
||||
@ -6773,6 +6924,9 @@ static const struct ieee80211_iface_limit ath10k_10_4_if_limits[] = {
|
||||
{
|
||||
.max = 16,
|
||||
.types = BIT(NL80211_IFTYPE_AP)
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
| BIT(NL80211_IFTYPE_MESH_POINT)
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
@ -6804,7 +6958,7 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
|
||||
|
||||
if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
|
||||
IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)) {
|
||||
val = ar->num_rf_chains - 1;
|
||||
val = ath10k_mac_get_vht_cap_bf_sts(ar);
|
||||
val <<= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
|
||||
val &= IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
|
||||
|
||||
@ -6813,7 +6967,7 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
|
||||
|
||||
if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
|
||||
IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) {
|
||||
val = ar->num_rf_chains - 1;
|
||||
val = ath10k_mac_get_vht_cap_bf_sound_dim(ar);
|
||||
val <<= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
|
||||
val &= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
|
||||
|
||||
@ -6997,7 +7151,8 @@ int ath10k_mac_register(struct ath10k *ar)
|
||||
|
||||
ar->hw->wiphy->interface_modes =
|
||||
BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_AP);
|
||||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_MESH_POINT);
|
||||
|
||||
ar->hw->wiphy->available_antennas_rx = ar->supp_rx_chainmask;
|
||||
ar->hw->wiphy->available_antennas_tx = ar->supp_tx_chainmask;
|
||||
|
@ -2609,12 +2609,9 @@ static int ath10k_pci_request_irq(struct ath10k *ar)
|
||||
return ath10k_pci_request_irq_legacy(ar);
|
||||
case 1:
|
||||
return ath10k_pci_request_irq_msi(ar);
|
||||
case MSI_NUM_REQUEST:
|
||||
default:
|
||||
return ath10k_pci_request_irq_msix(ar);
|
||||
}
|
||||
|
||||
ath10k_warn(ar, "unknown irq configuration upon request\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void ath10k_pci_free_irq(struct ath10k *ar)
|
||||
@ -2657,7 +2654,7 @@ static int ath10k_pci_init_irq(struct ath10k *ar)
|
||||
|
||||
/* Try MSI-X */
|
||||
if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO) {
|
||||
ar_pci->num_msi_intrs = MSI_NUM_REQUEST;
|
||||
ar_pci->num_msi_intrs = MSI_ASSIGN_CE_MAX + 1;
|
||||
ret = pci_enable_msi_range(ar_pci->pdev, ar_pci->num_msi_intrs,
|
||||
ar_pci->num_msi_intrs);
|
||||
if (ret > 0)
|
||||
@ -2705,18 +2702,13 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar)
|
||||
switch (ar_pci->num_msi_intrs) {
|
||||
case 0:
|
||||
ath10k_pci_deinit_irq_legacy(ar);
|
||||
return 0;
|
||||
case 1:
|
||||
/* fall-through */
|
||||
case MSI_NUM_REQUEST:
|
||||
pci_disable_msi(ar_pci->pdev);
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
pci_disable_msi(ar_pci->pdev);
|
||||
break;
|
||||
}
|
||||
|
||||
ath10k_warn(ar, "unknown irq configuration upon deinit\n");
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
|
||||
|
@ -52,6 +52,9 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
|
||||
struct ieee80211_tx_info *info;
|
||||
struct ath10k_skb_cb *skb_cb;
|
||||
struct sk_buff *msdu;
|
||||
struct ieee80211_hdr *hdr;
|
||||
__le16 fc;
|
||||
bool limit_mgmt_desc = false;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT,
|
||||
"htt tx completion msdu_id %u discard %d no_ack %d success %d\n",
|
||||
@ -72,14 +75,21 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
hdr = (struct ieee80211_hdr *)msdu->data;
|
||||
fc = hdr->frame_control;
|
||||
|
||||
if (unlikely(ieee80211_is_mgmt(fc)) &&
|
||||
ar->hw_params.max_probe_resp_desc_thres)
|
||||
limit_mgmt_desc = true;
|
||||
|
||||
ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);
|
||||
__ath10k_htt_tx_dec_pending(htt);
|
||||
__ath10k_htt_tx_dec_pending(htt, limit_mgmt_desc);
|
||||
if (htt->num_pending_tx == 0)
|
||||
wake_up(&htt->empty_tx_wq);
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
|
||||
skb_cb = ATH10K_SKB_CB(msdu);
|
||||
|
||||
dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
|
||||
|
||||
if (skb_cb->htt.txbuf)
|
||||
|
@ -3917,6 +3917,53 @@ static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
ath10k_wmi_is_host_mem_allocated(struct ath10k *ar,
|
||||
const struct wlan_host_mem_req **mem_reqs,
|
||||
u32 num_mem_reqs)
|
||||
{
|
||||
u32 req_id, num_units, unit_size, num_unit_info;
|
||||
u32 pool_size;
|
||||
int i, j;
|
||||
bool found;
|
||||
|
||||
if (ar->wmi.num_mem_chunks != num_mem_reqs)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < num_mem_reqs; ++i) {
|
||||
req_id = __le32_to_cpu(mem_reqs[i]->req_id);
|
||||
num_units = __le32_to_cpu(mem_reqs[i]->num_units);
|
||||
unit_size = __le32_to_cpu(mem_reqs[i]->unit_size);
|
||||
num_unit_info = __le32_to_cpu(mem_reqs[i]->num_unit_info);
|
||||
|
||||
if (num_unit_info & NUM_UNITS_IS_NUM_ACTIVE_PEERS) {
|
||||
if (ar->num_active_peers)
|
||||
num_units = ar->num_active_peers + 1;
|
||||
else
|
||||
num_units = ar->max_num_peers + 1;
|
||||
} else if (num_unit_info & NUM_UNITS_IS_NUM_PEERS) {
|
||||
num_units = ar->max_num_peers + 1;
|
||||
} else if (num_unit_info & NUM_UNITS_IS_NUM_VDEVS) {
|
||||
num_units = ar->max_num_vdevs + 1;
|
||||
}
|
||||
|
||||
found = false;
|
||||
for (j = 0; j < ar->wmi.num_mem_chunks; j++) {
|
||||
if (ar->wmi.mem_chunks[j].req_id == req_id) {
|
||||
pool_size = num_units * round_up(unit_size, 4);
|
||||
if (ar->wmi.mem_chunks[j].len == pool_size) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
ath10k_wmi_main_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb,
|
||||
struct wmi_svc_rdy_ev_arg *arg)
|
||||
@ -3997,6 +4044,7 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work)
|
||||
struct wmi_svc_rdy_ev_arg arg = {};
|
||||
u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i;
|
||||
int ret;
|
||||
bool allocated;
|
||||
|
||||
if (!skb) {
|
||||
ath10k_warn(ar, "invalid service ready event skb\n");
|
||||
@ -4073,6 +4121,18 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work)
|
||||
* and WMI_SERVICE_IRAM_TIDS, etc.
|
||||
*/
|
||||
|
||||
allocated = ath10k_wmi_is_host_mem_allocated(ar, arg.mem_reqs,
|
||||
num_mem_reqs);
|
||||
if (allocated)
|
||||
goto skip_mem_alloc;
|
||||
|
||||
/* Either this event is received during boot time or there is a change
|
||||
* in memory requirement from firmware when compared to last request.
|
||||
* Free any old memory and do a fresh allocation based on the current
|
||||
* memory requirement.
|
||||
*/
|
||||
ath10k_wmi_free_host_mem(ar);
|
||||
|
||||
for (i = 0; i < num_mem_reqs; ++i) {
|
||||
req_id = __le32_to_cpu(arg.mem_reqs[i]->req_id);
|
||||
num_units = __le32_to_cpu(arg.mem_reqs[i]->num_units);
|
||||
@ -4108,6 +4168,7 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work)
|
||||
return;
|
||||
}
|
||||
|
||||
skip_mem_alloc:
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI,
|
||||
"wmi event service ready min_tx_power 0x%08x max_tx_power 0x%08x ht_cap 0x%08x vht_cap 0x%08x sw_ver0 0x%08x sw_ver1 0x%08x fw_build 0x%08x phy_capab 0x%08x num_rf_chains 0x%08x eeprom_rd 0x%08x num_mem_reqs 0x%08x\n",
|
||||
__le32_to_cpu(arg.min_tx_power),
|
||||
@ -6660,15 +6721,10 @@ int ath10k_wmi_attach(struct ath10k *ar)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ath10k_wmi_detach(struct ath10k *ar)
|
||||
void ath10k_wmi_free_host_mem(struct ath10k *ar)
|
||||
{
|
||||
int i;
|
||||
|
||||
cancel_work_sync(&ar->svc_rdy_work);
|
||||
|
||||
if (ar->svc_rdy_skb)
|
||||
dev_kfree_skb(ar->svc_rdy_skb);
|
||||
|
||||
/* free the host memory chunks requested by firmware */
|
||||
for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
|
||||
dma_free_coherent(ar->dev,
|
||||
@ -6679,3 +6735,11 @@ void ath10k_wmi_detach(struct ath10k *ar)
|
||||
|
||||
ar->wmi.num_mem_chunks = 0;
|
||||
}
|
||||
|
||||
void ath10k_wmi_detach(struct ath10k *ar)
|
||||
{
|
||||
cancel_work_sync(&ar->svc_rdy_work);
|
||||
|
||||
if (ar->svc_rdy_skb)
|
||||
dev_kfree_skb(ar->svc_rdy_skb);
|
||||
}
|
||||
|
@ -6067,6 +6067,7 @@ struct ath10k_fw_stats_peer;
|
||||
|
||||
int ath10k_wmi_attach(struct ath10k *ar);
|
||||
void ath10k_wmi_detach(struct ath10k *ar);
|
||||
void ath10k_wmi_free_host_mem(struct ath10k *ar);
|
||||
int ath10k_wmi_wait_for_service_ready(struct ath10k *ar);
|
||||
int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar);
|
||||
|
||||
|
@ -21,12 +21,6 @@
|
||||
#include "dfs_pri_detector.h"
|
||||
#include "ath.h"
|
||||
|
||||
/*
|
||||
* tolerated deviation of radar time stamp in usecs on both sides
|
||||
* TODO: this might need to be HW-dependent
|
||||
*/
|
||||
#define PRI_TOLERANCE 16
|
||||
|
||||
/**
|
||||
* struct radar_types - contains array of patterns defined for one DFS domain
|
||||
* @domain: DFS regulatory domain
|
||||
@ -121,7 +115,7 @@ static const struct radar_detector_specs jp_radar_ref_types[] = {
|
||||
JP_PATTERN(4, 0, 5, 150, 230, 1, 23, 50, false),
|
||||
JP_PATTERN(5, 6, 10, 200, 500, 1, 16, 50, false),
|
||||
JP_PATTERN(6, 11, 20, 200, 500, 1, 12, 50, false),
|
||||
JP_PATTERN(7, 50, 100, 1000, 2000, 1, 20, 50, false),
|
||||
JP_PATTERN(7, 50, 100, 1000, 2000, 1, 3, 50, false),
|
||||
JP_PATTERN(5, 0, 1, 333, 333, 1, 9, 50, false),
|
||||
};
|
||||
|
||||
|
@ -21,6 +21,11 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/nl80211.h>
|
||||
|
||||
/* tolerated deviation of radar time stamp in usecs on both sides
|
||||
* TODO: this might need to be HW-dependent
|
||||
*/
|
||||
#define PRI_TOLERANCE 16
|
||||
|
||||
/**
|
||||
* struct ath_dfs_pool_stats - DFS Statistics for global pools
|
||||
*/
|
||||
|
@ -25,6 +25,9 @@ struct ath_dfs_pool_stats global_dfs_pool_stats = {};
|
||||
|
||||
#define DFS_POOL_STAT_INC(c) (global_dfs_pool_stats.c++)
|
||||
#define DFS_POOL_STAT_DEC(c) (global_dfs_pool_stats.c--)
|
||||
#define GET_PRI_TO_USE(MIN, MAX, RUNTIME) \
|
||||
(MIN + PRI_TOLERANCE == MAX - PRI_TOLERANCE ? \
|
||||
MIN + PRI_TOLERANCE : RUNTIME)
|
||||
|
||||
/**
|
||||
* struct pulse_elem - elements in pulse queue
|
||||
@ -243,7 +246,8 @@ static bool pseq_handler_create_sequences(struct pri_detector *pde,
|
||||
ps.count_falses = 0;
|
||||
ps.first_ts = p->ts;
|
||||
ps.last_ts = ts;
|
||||
ps.pri = ts - p->ts;
|
||||
ps.pri = GET_PRI_TO_USE(pde->rs->pri_min,
|
||||
pde->rs->pri_max, ts - p->ts);
|
||||
ps.dur = ps.pri * (pde->rs->ppb - 1)
|
||||
+ 2 * pde->rs->max_pri_tolerance;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user