summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c23
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h5
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.h3
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c47
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_tx.c55
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h10
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c333
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c18
-rw-r--r--drivers/net/wireless/ath/ath10k/txrx.c14
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c76
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_calib.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c106
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.h21
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c7
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c8
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c2
-rw-r--r--drivers/net/wireless/ath/carl9170/rx.c2
-rw-r--r--drivers/net/wireless/ath/dfs_pattern_detector.c8
-rw-r--r--drivers/net/wireless/ath/dfs_pattern_detector.h5
-rw-r--r--drivers/net/wireless/ath/dfs_pri_detector.c6
25 files changed, 590 insertions, 175 deletions
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index b87b98617073..879625adc63a 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -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);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 12542144fe12..04e040a06cb1 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -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;
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 573187512895..5a8e4eae7a9c 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -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 *);
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 1b7a04366256..606c1a34f004 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -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;
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index 43aa5e2d1b87..eb5ba9bb8b4d 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -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;
+
+ 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);
+ 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;
}
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 23afcda2de96..bc421a5c5356 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -414,16 +414,6 @@ enum ath10k_hw_rate_cck {
#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
* Remaining MSIs, if any, are used by Copy Engines
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index b04e7694c105..79490ad41ac5 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -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;
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 1046ab65b9ab..110fcad609b9 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -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)
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index e4a9c4c8d0cb..7db7d501726b 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -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)
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index ce01107ef37a..87d9de2aa8c5 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -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);
+}
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 52d35032d53e..3e5a1591f772 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -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);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index 174442beb952..0c391997a2f7 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -1249,7 +1249,8 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, 0x0);
- if (AR_SREV_9003_PCOEM(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
+ if (AR_SREV_9003_PCOEM(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
+ AR_SREV_9561(ah)) {
if (is_2g)
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR,
@@ -1640,7 +1641,8 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
skip_tx_iqcal:
if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
- if (AR_SREV_9330_11(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah)) {
+ if (AR_SREV_9330_11(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah) ||
+ AR_SREV_9561(ah)) {
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
if (!(ah->rxchainmask & (1 << i)))
continue;
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index c85c47978e1e..b42f4a963ef4 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -635,6 +635,7 @@ struct ath9k_vif_iter_data {
int nstations; /* number of station vifs */
int nwds; /* number of WDS vifs */
int nadhocs; /* number of adhoc vifs */
+ int nocbs; /* number of OCB vifs */
struct ieee80211_vif *primary_sta;
};
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index da32c8faad94..6de64cface3c 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -741,8 +741,8 @@ static int read_file_misc(struct seq_file *file, void *data)
i++, (int)(ctx->assigned), iter_data.naps,
iter_data.nstations,
iter_data.nmeshes, iter_data.nwds);
- seq_printf(file, " ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n",
- iter_data.nadhocs, sc->cur_chan->nvifs,
+ seq_printf(file, " ADHOC: %i OCB: %i TOTAL: %hi BEACON-VIF: %hi\n",
+ iter_data.nadhocs, iter_data.nocbs, sc->cur_chan->nvifs,
sc->nbcnvifs);
}
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 10c02f5cbc5e..165dd202c365 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -17,12 +17,8 @@
#include <asm/unaligned.h>
#include "htc.h"
-/* identify firmware images */
-#define FIRMWARE_AR7010_1_1 "htc_7010.fw"
-#define FIRMWARE_AR9271 "htc_9271.fw"
-
-MODULE_FIRMWARE(FIRMWARE_AR7010_1_1);
-MODULE_FIRMWARE(FIRMWARE_AR9271);
+MODULE_FIRMWARE(HTC_7010_MODULE_FW);
+MODULE_FIRMWARE(HTC_9271_MODULE_FW);
static struct usb_device_id ath9k_hif_usb_ids[] = {
{ USB_DEVICE(0x0cf3, 0x9271) }, /* Atheros */
@@ -1080,12 +1076,88 @@ static void ath9k_hif_usb_firmware_fail(struct hif_device_usb *hif_dev)
device_unlock(parent);
}
+static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context);
+
+/* taken from iwlwifi */
+static int ath9k_hif_request_firmware(struct hif_device_usb *hif_dev,
+ bool first)
+{
+ char index[8], *chip;
+ int ret;
+
+ if (first) {
+ if (htc_use_dev_fw) {
+ hif_dev->fw_minor_index = FIRMWARE_MINOR_IDX_MAX + 1;
+ sprintf(index, "%s", "dev");
+ } else {
+ hif_dev->fw_minor_index = FIRMWARE_MINOR_IDX_MAX;
+ sprintf(index, "%d", hif_dev->fw_minor_index);
+ }
+ } else {
+ hif_dev->fw_minor_index--;
+ sprintf(index, "%d", hif_dev->fw_minor_index);
+ }
+
+ /* test for FW 1.3 */
+ if (MAJOR_VERSION_REQ == 1 && hif_dev->fw_minor_index == 3) {
+ const char *filename;
+
+ if (IS_AR7010_DEVICE(hif_dev->usb_device_id->driver_info))
+ filename = FIRMWARE_AR7010_1_1;
+ else
+ filename = FIRMWARE_AR9271;
+
+ /* expected fw locations:
+ * - htc_9271.fw (stable version 1.3, depricated)
+ */
+ snprintf(hif_dev->fw_name, sizeof(hif_dev->fw_name),
+ "%s", filename);
+
+ } else if (hif_dev->fw_minor_index < FIRMWARE_MINOR_IDX_MIN) {
+ dev_err(&hif_dev->udev->dev, "no suitable firmware found!\n");
+
+ return -ENOENT;
+ } else {
+ if (IS_AR7010_DEVICE(hif_dev->usb_device_id->driver_info))
+ chip = "7010";
+ else
+ chip = "9271";
+
+ /* expected fw locations:
+ * - ath9k_htc/htc_9271-1.dev.0.fw (development version)
+ * - ath9k_htc/htc_9271-1.4.0.fw (stable version)
+ */
+ snprintf(hif_dev->fw_name, sizeof(hif_dev->fw_name),
+ "%s/htc_%s-%d.%s.0.fw", HTC_FW_PATH,
+ chip, MAJOR_VERSION_REQ, index);
+ }
+
+ ret = request_firmware_nowait(THIS_MODULE, true, hif_dev->fw_name,
+ &hif_dev->udev->dev, GFP_KERNEL,
+ hif_dev, ath9k_hif_usb_firmware_cb);
+ if (ret) {
+ dev_err(&hif_dev->udev->dev,
+ "ath9k_htc: Async request for firmware %s failed\n",
+ hif_dev->fw_name);
+ return ret;
+ }
+
+ dev_info(&hif_dev->udev->dev, "ath9k_htc: Firmware %s requested\n",
+ hif_dev->fw_name);
+
+ return ret;
+}
+
static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context)
{
struct hif_device_usb *hif_dev = context;
int ret;
if (!fw) {
+ ret = ath9k_hif_request_firmware(hif_dev, false);
+ if (!ret)
+ return;
+
dev_err(&hif_dev->udev->dev,
"ath9k_htc: Failed to get firmware %s\n",
hif_dev->fw_name);
@@ -1215,27 +1287,11 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
init_completion(&hif_dev->fw_done);
- /* Find out which firmware to load */
-
- if (IS_AR7010_DEVICE(id->driver_info))
- hif_dev->fw_name = FIRMWARE_AR7010_1_1;
- else
- hif_dev->fw_name = FIRMWARE_AR9271;
-
- ret = request_firmware_nowait(THIS_MODULE, true, hif_dev->fw_name,
- &hif_dev->udev->dev, GFP_KERNEL,
- hif_dev, ath9k_hif_usb_firmware_cb);
- if (ret) {
- dev_err(&hif_dev->udev->dev,
- "ath9k_htc: Async request for firmware %s failed\n",
- hif_dev->fw_name);
+ ret = ath9k_hif_request_firmware(hif_dev, true);
+ if (ret)
goto err_fw_req;
- }
- dev_info(&hif_dev->udev->dev, "ath9k_htc: Firmware %s requested\n",
- hif_dev->fw_name);
-
- return 0;
+ return ret;
err_fw_req:
usb_set_intfdata(interface, NULL);
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h
index 51496e74b83e..7c2ef7ecd98b 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.h
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.h
@@ -17,8 +17,26 @@
#ifndef HTC_USB_H
#define HTC_USB_H
+/* old firmware images */
+#define FIRMWARE_AR7010_1_1 "htc_7010.fw"
+#define FIRMWARE_AR9271 "htc_9271.fw"
+
+/* supported Major FW version */
#define MAJOR_VERSION_REQ 1
#define MINOR_VERSION_REQ 3
+/* minimal and maximal supported Minor FW version. */
+#define FIRMWARE_MINOR_IDX_MAX 4
+#define FIRMWARE_MINOR_IDX_MIN 3
+#define HTC_FW_PATH "ath9k_htc"
+
+#define HTC_9271_MODULE_FW HTC_FW_PATH "/htc_9271-" \
+ __stringify(MAJOR_VERSION_REQ) \
+ "." __stringify(FIRMWARE_MINOR_IDX_MAX) ".0.fw"
+#define HTC_7010_MODULE_FW HTC_FW_PATH "/htc_7010-" \
+ __stringify(MAJOR_VERSION_REQ) \
+ "." __stringify(FIRMWARE_MINOR_IDX_MAX) ".0.fw"
+
+extern int htc_use_dev_fw;
#define IS_AR7010_DEVICE(_v) (((_v) == AR9280_USB) || ((_v) == AR9287_USB))
@@ -101,7 +119,8 @@ struct hif_device_usb {
struct usb_anchor reg_in_submitted;
struct usb_anchor mgmt_submitted;
struct sk_buff *remain_skb;
- const char *fw_name;
+ char fw_name[32];
+ int fw_minor_index;
int rx_remain_len;
int rx_pkt_len;
int rx_transfer_len;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 1e84882f8c5b..8647ab77c019 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -38,6 +38,10 @@ static int ath9k_ps_enable;
module_param_named(ps_enable, ath9k_ps_enable, int, 0444);
MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave");
+int htc_use_dev_fw = 0;
+module_param_named(use_dev_fw, htc_use_dev_fw, int, 0444);
+MODULE_PARM_DESC(use_dev_fw, "Use development FW version");
+
#ifdef CONFIG_MAC80211_LEDS
int ath9k_htc_led_blink = 1;
module_param_named(blink, ath9k_htc_led_blink, int, 0444);
@@ -736,7 +740,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_P2P_CLIENT) |
- BIT(NL80211_IFTYPE_MESH_POINT);
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+ BIT(NL80211_IFTYPE_OCB);
hw->wiphy->iface_combinations = &if_comb;
hw->wiphy->n_iface_combinations = 1;
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 1dd0339de372..bdfff4641931 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1241,6 +1241,7 @@ static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode)
break;
}
/* fall through */
+ case NL80211_IFTYPE_OCB:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP:
set |= AR_STA_ID1_STA_AP;
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 57f95f2dca5b..5d532c7b813f 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -855,7 +855,8 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_MESH_POINT) |
- BIT(NL80211_IFTYPE_WDS);
+ BIT(NL80211_IFTYPE_WDS) |
+ BIT(NL80211_IFTYPE_OCB);
if (ath9k_is_chanctx_enabled())
hw->wiphy->interface_modes |=
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 323eb33c3c6e..d184e682e636 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -938,6 +938,9 @@ static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data,
if (avp->assoc && !iter_data->primary_sta)
iter_data->primary_sta = vif;
break;
+ case NL80211_IFTYPE_OCB:
+ iter_data->nocbs++;
+ break;
case NL80211_IFTYPE_ADHOC:
iter_data->nadhocs++;
if (vif->bss_conf.enable_beacon)
@@ -1111,6 +1114,8 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
if (iter_data.nmeshes)
ah->opmode = NL80211_IFTYPE_MESH_POINT;
+ else if (iter_data.nocbs)
+ ah->opmode = NL80211_IFTYPE_OCB;
else if (iter_data.nwds)
ah->opmode = NL80211_IFTYPE_AP;
else if (iter_data.nadhocs)
@@ -1760,7 +1765,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
ath9k_calculate_summary_state(sc, avp->chanctx);
}
- if (changed & BSS_CHANGED_IBSS) {
+ if ((changed & BSS_CHANGED_IBSS) ||
+ (changed & BSS_CHANGED_OCB)) {
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
common->curaid = bss_conf->aid;
ath9k_hw_write_associd(sc->sc_ah);
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index d3189daf9996..994daf6c6297 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -403,7 +403,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
(sc->cur_chan->nvifs <= 1) &&
!(sc->cur_chan->rxfilter & FIF_BCN_PRBRESP_PROMISC))
rfilt |= ATH9K_RX_FILTER_MYBEACON;
- else
+ else if (sc->sc_ah->opmode != NL80211_IFTYPE_OCB)
rfilt |= ATH9K_RX_FILTER_BEACON;
if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
index 924135b8e575..d66533cbc38a 100644
--- a/drivers/net/wireless/ath/carl9170/rx.c
+++ b/drivers/net/wireless/ath/carl9170/rx.c
@@ -453,7 +453,7 @@ static void carl9170_rx_phy_status(struct ar9170 *ar,
/* post-process RSSI */
for (i = 0; i < 7; i++)
if (phy->rssi[i] & 0x80)
- phy->rssi[i] = ((phy->rssi[i] & 0x7f) + 1) & 0x7f;
+ phy->rssi[i] = ((~phy->rssi[i] & 0x7f) + 1) & 0x7f;
/* TODO: we could do something with phy_errors */
status->signal = ar->noise[0] + phy->rssi_combined;
diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.c b/drivers/net/wireless/ath/dfs_pattern_detector.c
index 656ce42b339a..9d687121b2bf 100644
--- a/drivers/net/wireless/ath/dfs_pattern_detector.c
+++ b/drivers/net/wireless/ath/dfs_pattern_detector.c
@@ -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),
};
diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.h b/drivers/net/wireless/ath/dfs_pattern_detector.h
index 25a43d632f90..92be3530e9b5 100644
--- a/drivers/net/wireless/ath/dfs_pattern_detector.h
+++ b/drivers/net/wireless/ath/dfs_pattern_detector.h
@@ -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
*/
diff --git a/drivers/net/wireless/ath/dfs_pri_detector.c b/drivers/net/wireless/ath/dfs_pri_detector.c
index cc5c592fc4c0..05b0464c6b92 100644
--- a/drivers/net/wireless/ath/dfs_pri_detector.c
+++ b/drivers/net/wireless/ath/dfs_pri_detector.c
@@ -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;