diff --git a/include/config b/include/config index f73603ad..ac754391 100644 --- a/include/config +++ b/include/config @@ -15,5 +15,6 @@ CONFIG_BUSYBOX_CONFIG_FEATURE_WGET_TIMEOUT=y CONFIG_ATH_USER_REGD=y CONFIG_PACKAGE_ATH_DEBUG=y +CONFIG_ATH10K_CT_COMMUNITY_FW=y CONFIG_PACKAGE_luci-base_srcdiet=y diff --git a/patches/openwrt/0017-mac80211-update-ath10k-to-compat-wireless-2015-03-05.patch b/patches/openwrt/0017-mac80211-update-ath10k-to-compat-wireless-2015-03-05.patch new file mode 100644 index 00000000..82b2bc9d --- /dev/null +++ b/patches/openwrt/0017-mac80211-update-ath10k-to-compat-wireless-2015-03-05.patch @@ -0,0 +1,33501 @@ +From: Matthias Schiffer +Date: Tue, 10 Mar 2015 12:40:53 +0100 +Subject: mac80211: update ath10k to compat-wireless-2015-03-05 + +Taken from http://openwrt.reigndropsfall.net/ + +diff --git a/package/kernel/mac80211/patches/917-mac80211-rx-reordering.patch b/package/kernel/mac80211/patches/917-mac80211-rx-reordering.patch +new file mode 100644 +index 0000000..1d0c559 +--- /dev/null ++++ b/package/kernel/mac80211/patches/917-mac80211-rx-reordering.patch +@@ -0,0 +1,271 @@ ++commit 08cf42e843f9a7e253502011c81677f61f7e5c42 ++Author: Michal Kazior ++Date: Wed Jul 16 12:12:15 2014 +0200 ++ ++ mac80211: add support for Rx reordering offloading ++ ++ Some drivers may be performing most of Tx/Rx ++ aggregation on their own (e.g. in firmware) ++ including AddBa/DelBa negotiations but may ++ otherwise require Rx reordering assistance. ++ ++ The patch exports 2 new functions for establishing ++ Rx aggregation sessions in assumption device ++ driver has taken care of the necessary ++ negotiations. ++ ++ Signed-off-by: Michal Kazior ++ [fix endian bug] ++ Signed-off-by: Johannes Berg ++ ++--- a/include/net/mac80211.h +++++ b/include/net/mac80211.h ++@@ -4481,6 +4481,40 @@ void ieee80211_stop_rx_ba_session(struct ++ */ ++ void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn); ++ +++/** +++ * ieee80211_start_rx_ba_session_offl - start a Rx BA session +++ * +++ * Some device drivers may offload part of the Rx aggregation flow including +++ * AddBa/DelBa negotiation but may otherwise be incapable of full Rx +++ * reordering. +++ * +++ * Create structures responsible for reordering so device drivers may call here +++ * when they complete AddBa negotiation. +++ * +++ * @vif: &struct ieee80211_vif pointer from the add_interface callback +++ * @addr: station mac address +++ * @tid: the rx tid +++ */ +++void ieee80211_start_rx_ba_session_offl(struct ieee80211_vif *vif, +++ const u8 *addr, u16 tid); +++ +++/** +++ * ieee80211_stop_rx_ba_session_offl - stop a Rx BA session +++ * +++ * Some device drivers may offload part of the Rx aggregation flow including +++ * AddBa/DelBa negotiation but may otherwise be incapable of full Rx +++ * reordering. +++ * +++ * Destroy structures responsible for reordering so device drivers may call here +++ * when they complete DelBa negotiation. +++ * +++ * @vif: &struct ieee80211_vif pointer from the add_interface callback +++ * @addr: station mac address +++ * @tid: the rx tid +++ */ +++void ieee80211_stop_rx_ba_session_offl(struct ieee80211_vif *vif, +++ const u8 *addr, u16 tid); +++ ++ /* Rate control API */ ++ ++ /** ++--- a/net/mac80211/agg-rx.c +++++ b/net/mac80211/agg-rx.c ++@@ -224,28 +224,15 @@ static void ieee80211_send_addba_resp(st ++ ieee80211_tx_skb(sdata, skb); ++ } ++ ++-void ieee80211_process_addba_request(struct ieee80211_local *local, ++- struct sta_info *sta, ++- struct ieee80211_mgmt *mgmt, ++- size_t len) +++void __ieee80211_start_rx_ba_session(struct sta_info *sta, +++ u8 dialog_token, u16 timeout, +++ u16 start_seq_num, u16 ba_policy, u16 tid, +++ u16 buf_size, bool tx) ++ { +++ struct ieee80211_local *local = sta->sdata->local; ++ struct tid_ampdu_rx *tid_agg_rx; ++- u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status; ++- u8 dialog_token; ++ int ret = -EOPNOTSUPP; ++- ++- /* extract session parameters from addba request frame */ ++- dialog_token = mgmt->u.action.u.addba_req.dialog_token; ++- timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout); ++- start_seq_num = ++- le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4; ++- ++- capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); ++- ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1; ++- tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; ++- buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; ++- ++- status = WLAN_STATUS_REQUEST_DECLINED; +++ u16 status = WLAN_STATUS_REQUEST_DECLINED; ++ ++ if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { ++ ht_dbg(sta->sdata, ++@@ -264,7 +251,7 @@ void ieee80211_process_addba_request(str ++ status = WLAN_STATUS_INVALID_QOS_PARAM; ++ ht_dbg_ratelimited(sta->sdata, ++ "AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n", ++- mgmt->sa, tid, ba_policy, buf_size); +++ sta->sta.addr, tid, ba_policy, buf_size); ++ goto end_no_lock; ++ } ++ /* determine default buffer size */ ++@@ -281,7 +268,7 @@ void ieee80211_process_addba_request(str ++ if (sta->ampdu_mlme.tid_rx[tid]) { ++ ht_dbg_ratelimited(sta->sdata, ++ "unexpected AddBA Req from %pM on tid %u\n", ++- mgmt->sa, tid); +++ sta->sta.addr, tid); ++ ++ /* delete existing Rx BA session on the same tid */ ++ ___ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, ++@@ -350,6 +337,74 @@ end: ++ mutex_unlock(&sta->ampdu_mlme.mtx); ++ ++ end_no_lock: ++- ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid, ++- dialog_token, status, 1, buf_size, timeout); +++ if (tx) +++ ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid, +++ dialog_token, status, 1, buf_size, +++ timeout); +++} +++ +++void ieee80211_process_addba_request(struct ieee80211_local *local, +++ struct sta_info *sta, +++ struct ieee80211_mgmt *mgmt, +++ size_t len) +++{ +++ u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num; +++ u8 dialog_token; +++ +++ /* extract session parameters from addba request frame */ +++ dialog_token = mgmt->u.action.u.addba_req.dialog_token; +++ timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout); +++ start_seq_num = +++ le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4; +++ +++ capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); +++ ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1; +++ tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; +++ buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; +++ +++ __ieee80211_start_rx_ba_session(sta, dialog_token, timeout, +++ start_seq_num, ba_policy, tid, +++ buf_size, true); +++} +++ +++void ieee80211_start_rx_ba_session_offl(struct ieee80211_vif *vif, +++ const u8 *addr, u16 tid) +++{ +++ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); +++ struct ieee80211_local *local = sdata->local; +++ struct ieee80211_rx_agg *rx_agg; +++ struct sk_buff *skb = dev_alloc_skb(0); +++ +++ if (unlikely(!skb)) +++ return; +++ +++ rx_agg = (struct ieee80211_rx_agg *) &skb->cb; +++ memcpy(&rx_agg->addr, addr, ETH_ALEN); +++ rx_agg->tid = tid; +++ +++ skb->pkt_type = IEEE80211_SDATA_QUEUE_RX_AGG_START; +++ skb_queue_tail(&sdata->skb_queue, skb); +++ ieee80211_queue_work(&local->hw, &sdata->work); +++} +++EXPORT_SYMBOL(ieee80211_start_rx_ba_session_offl); +++ +++void ieee80211_stop_rx_ba_session_offl(struct ieee80211_vif *vif, +++ const u8 *addr, u16 tid) +++{ +++ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); +++ struct ieee80211_local *local = sdata->local; +++ struct ieee80211_rx_agg *rx_agg; +++ struct sk_buff *skb = dev_alloc_skb(0); +++ +++ if (unlikely(!skb)) +++ return; +++ +++ rx_agg = (struct ieee80211_rx_agg *) &skb->cb; +++ memcpy(&rx_agg->addr, addr, ETH_ALEN); +++ rx_agg->tid = tid; +++ +++ skb->pkt_type = IEEE80211_SDATA_QUEUE_RX_AGG_STOP; +++ skb_queue_tail(&sdata->skb_queue, skb); +++ ieee80211_queue_work(&local->hw, &sdata->work); ++ } +++EXPORT_SYMBOL(ieee80211_stop_rx_ba_session_offl); ++--- a/net/mac80211/ieee80211_i.h +++++ b/net/mac80211/ieee80211_i.h ++@@ -902,10 +902,17 @@ ieee80211_vif_get_shift(struct ieee80211 ++ return shift; ++ } ++ +++struct ieee80211_rx_agg { +++ u8 addr[ETH_ALEN]; +++ u16 tid; +++}; +++ ++ enum sdata_queue_type { ++ IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0, ++ IEEE80211_SDATA_QUEUE_AGG_START = 1, ++ IEEE80211_SDATA_QUEUE_AGG_STOP = 2, +++ IEEE80211_SDATA_QUEUE_RX_AGG_START = 3, +++ IEEE80211_SDATA_QUEUE_RX_AGG_STOP = 4, ++ }; ++ ++ enum { ++@@ -1554,6 +1561,10 @@ void ___ieee80211_stop_rx_ba_session(str ++ u16 initiator, u16 reason, bool stop); ++ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, ++ u16 initiator, u16 reason, bool stop); +++void __ieee80211_start_rx_ba_session(struct sta_info *sta, +++ u8 dialog_token, u16 timeout, +++ u16 start_seq_num, u16 ba_policy, u16 tid, +++ u16 buf_size, bool tx); ++ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, ++ enum ieee80211_agg_stop_reason reason); ++ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, ++--- a/net/mac80211/iface.c +++++ b/net/mac80211/iface.c ++@@ -1154,6 +1154,7 @@ static void ieee80211_iface_work(struct ++ struct sk_buff *skb; ++ struct sta_info *sta; ++ struct ieee80211_ra_tid *ra_tid; +++ struct ieee80211_rx_agg *rx_agg; ++ ++ if (!ieee80211_sdata_running(sdata)) ++ return; ++@@ -1181,6 +1182,34 @@ static void ieee80211_iface_work(struct ++ ra_tid = (void *)&skb->cb; ++ ieee80211_stop_tx_ba_cb(&sdata->vif, ra_tid->ra, ++ ra_tid->tid); +++ } else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_RX_AGG_START) { +++ rx_agg = (void *)&skb->cb; +++ mutex_lock(&local->sta_mtx); +++ sta = sta_info_get_bss(sdata, rx_agg->addr); +++ if (sta) { +++ u16 last_seq; +++ +++ last_seq = le16_to_cpu( +++ sta->last_seq_ctrl[rx_agg->tid]); +++ +++ __ieee80211_start_rx_ba_session(sta, +++ 0, 0, +++ ieee80211_sn_inc(last_seq), +++ 1, rx_agg->tid, +++ IEEE80211_MAX_AMPDU_BUF, +++ false); +++ } +++ mutex_unlock(&local->sta_mtx); +++ } else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_RX_AGG_STOP) { +++ rx_agg = (void *)&skb->cb; +++ mutex_lock(&local->sta_mtx); +++ sta = sta_info_get_bss(sdata, rx_agg->addr); +++ if (sta) +++ __ieee80211_stop_rx_ba_session(sta, +++ rx_agg->tid, +++ WLAN_BACK_RECIPIENT, 0, +++ false); +++ mutex_unlock(&local->sta_mtx); ++ } else if (ieee80211_is_action(mgmt->frame_control) && ++ mgmt->u.action.category == WLAN_CATEGORY_BACK) { ++ int len = skb->len; +diff --git a/package/kernel/mac80211/patches/918-ath-spectral-debugfs.patch b/package/kernel/mac80211/patches/918-ath-spectral-debugfs.patch +new file mode 100644 +index 0000000..d0c1bbd +--- /dev/null ++++ b/package/kernel/mac80211/patches/918-ath-spectral-debugfs.patch +@@ -0,0 +1,192 @@ ++--- a/drivers/net/wireless/ath/ath9k/spectral.h +++++ b/drivers/net/wireless/ath/ath9k/spectral.h ++@@ -17,6 +17,8 @@ ++ #ifndef SPECTRAL_H ++ #define SPECTRAL_H ++ +++#include "../spectral_common.h" +++ ++ /* enum spectral_mode: ++ * ++ * @SPECTRAL_DISABLED: spectral mode is disabled ++@@ -54,8 +56,6 @@ struct ath_ht20_mag_info { ++ u8 max_exp; ++ } __packed; ++ ++-#define SPECTRAL_HT20_NUM_BINS 56 ++- ++ /* WARNING: don't actually use this struct! MAC may vary the amount of ++ * data by -1/+2. This struct is for reference only. ++ */ ++@@ -83,8 +83,6 @@ struct ath_ht20_40_mag_info { ++ u8 max_exp; ++ } __packed; ++ ++-#define SPECTRAL_HT20_40_NUM_BINS 128 ++- ++ /* WARNING: don't actually use this struct! MAC may vary the amount of ++ * data. This struct is for reference only. ++ */ ++@@ -125,71 +123,6 @@ static inline u8 spectral_bitmap_weight( ++ return bins[0] & 0x3f; ++ } ++ ++-/* FFT sample format given to userspace via debugfs. ++- * ++- * Please keep the type/length at the front position and change ++- * other fields after adding another sample type ++- * ++- * TODO: this might need rework when switching to nl80211-based ++- * interface. ++- */ ++-enum ath_fft_sample_type { ++- ATH_FFT_SAMPLE_HT20 = 1, ++- ATH_FFT_SAMPLE_HT20_40, ++-}; ++- ++-struct fft_sample_tlv { ++- u8 type; /* see ath_fft_sample */ ++- __be16 length; ++- /* type dependent data follows */ ++-} __packed; ++- ++-struct fft_sample_ht20 { ++- struct fft_sample_tlv tlv; ++- ++- u8 max_exp; ++- ++- __be16 freq; ++- s8 rssi; ++- s8 noise; ++- ++- __be16 max_magnitude; ++- u8 max_index; ++- u8 bitmap_weight; ++- ++- __be64 tsf; ++- ++- u8 data[SPECTRAL_HT20_NUM_BINS]; ++-} __packed; ++- ++-struct fft_sample_ht20_40 { ++- struct fft_sample_tlv tlv; ++- ++- u8 channel_type; ++- __be16 freq; ++- ++- s8 lower_rssi; ++- s8 upper_rssi; ++- ++- __be64 tsf; ++- ++- s8 lower_noise; ++- s8 upper_noise; ++- ++- __be16 lower_max_magnitude; ++- __be16 upper_max_magnitude; ++- ++- u8 lower_max_index; ++- u8 upper_max_index; ++- ++- u8 lower_bitmap_weight; ++- u8 upper_bitmap_weight; ++- ++- u8 max_exp; ++- ++- u8 data[SPECTRAL_HT20_40_NUM_BINS]; ++-} __packed; ++- ++ void ath9k_spectral_init_debug(struct ath_softc *sc); ++ void ath9k_spectral_deinit_debug(struct ath_softc *sc); ++ ++--- /dev/null +++++ b/drivers/net/wireless/ath/spectral_common.h ++@@ -0,0 +1,88 @@ +++/* +++ * Copyright (c) 2013 Qualcomm Atheros, Inc. +++ * +++ * Permission to use, copy, modify, and/or distribute this software for any +++ * purpose with or without fee is hereby granted, provided that the above +++ * copyright notice and this permission notice appear in all copies. +++ * +++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +++ */ +++ +++#ifndef SPECTRAL_COMMON_H +++#define SPECTRAL_COMMON_H +++ +++#define SPECTRAL_HT20_NUM_BINS 56 +++#define SPECTRAL_HT20_40_NUM_BINS 128 +++ +++/* FFT sample format given to userspace via debugfs. +++ * +++ * Please keep the type/length at the front position and change +++ * other fields after adding another sample type +++ * +++ * TODO: this might need rework when switching to nl80211-based +++ * interface. +++ */ +++enum ath_fft_sample_type { +++ ATH_FFT_SAMPLE_HT20 = 1, +++ ATH_FFT_SAMPLE_HT20_40, +++}; +++ +++struct fft_sample_tlv { +++ u8 type; /* see ath_fft_sample */ +++ __be16 length; +++ /* type dependent data follows */ +++} __packed; +++ +++struct fft_sample_ht20 { +++ struct fft_sample_tlv tlv; +++ +++ u8 max_exp; +++ +++ __be16 freq; +++ s8 rssi; +++ s8 noise; +++ +++ __be16 max_magnitude; +++ u8 max_index; +++ u8 bitmap_weight; +++ +++ __be64 tsf; +++ +++ u8 data[SPECTRAL_HT20_NUM_BINS]; +++} __packed; +++ +++struct fft_sample_ht20_40 { +++ struct fft_sample_tlv tlv; +++ +++ u8 channel_type; +++ __be16 freq; +++ +++ s8 lower_rssi; +++ s8 upper_rssi; +++ +++ __be64 tsf; +++ +++ s8 lower_noise; +++ s8 upper_noise; +++ +++ __be16 lower_max_magnitude; +++ __be16 upper_max_magnitude; +++ +++ u8 lower_max_index; +++ u8 upper_max_index; +++ +++ u8 lower_bitmap_weight; +++ u8 upper_bitmap_weight; +++ +++ u8 max_exp; +++ +++ u8 data[SPECTRAL_HT20_40_NUM_BINS]; +++} __packed; +++ +++#endif /* SPECTRAL_COMMON_H */ +diff --git a/package/kernel/mac80211/patches/919-update-ath10k.patch b/package/kernel/mac80211/patches/919-update-ath10k.patch +new file mode 100644 +index 0000000..0f5d87a +--- /dev/null ++++ b/package/kernel/mac80211/patches/919-update-ath10k.patch +@@ -0,0 +1,32869 @@ ++--- a/drivers/net/wireless/ath/ath10k/Kconfig +++++ b/drivers/net/wireless/ath/ath10k/Kconfig ++@@ -26,13 +26,15 @@ config ATH10K_DEBUG ++ ++ config ATH10K_DEBUGFS ++ bool "Atheros ath10k debugfs support" ++- depends on ATH10K +++ depends on ATH10K && DEBUG_FS +++ depends on RELAY ++ ---help--- ++ Enabled debugfs support ++ ++ If unsure, say Y to make it easier to debug problems. ++ ++ config ATH10K_TRACING +++ depends on !KERNEL_3_4 ++ bool "Atheros ath10k tracing support" ++ depends on ATH10K ++ depends on EVENT_TRACING ++--- a/drivers/net/wireless/ath/ath10k/Makefile +++++ b/drivers/net/wireless/ath/ath10k/Makefile ++@@ -8,9 +8,15 @@ ath10k_core-y += mac.o \ ++ htt_tx.o \ ++ txrx.o \ ++ wmi.o \ ++- bmi.o +++ wmi-tlv.o \ +++ bmi.o \ +++ hw.o ++ +++ath10k_core-$(CPTCFG_ATH10K_DEBUGFS) += spectral.o +++ath10k_core-$(CPTCFG_NL80211_TESTMODE) += testmode.o ++ ath10k_core-$(CPTCFG_ATH10K_TRACING) += trace.o +++ath10k_core-$(CONFIG_THERMAL) += thermal.o +++ath10k_core-$(CPTCFG_MAC80211_DEBUGFS) += debugfs_sta.o ++ ++ obj-$(CPTCFG_ATH10K_PCI) += ath10k_pci.o ++ ath10k_pci-y += pci.o \ ++--- a/drivers/net/wireless/ath/ath10k/bmi.c +++++ b/drivers/net/wireless/ath/ath10k/bmi.c ++@@ -22,7 +22,7 @@ ++ ++ void ath10k_bmi_start(struct ath10k *ar) ++ { ++- ath10k_dbg(ATH10K_DBG_BMI, "bmi start\n"); +++ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi start\n"); ++ ++ ar->bmi.done_sent = false; ++ } ++@@ -33,10 +33,10 @@ int ath10k_bmi_done(struct ath10k *ar) ++ u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.done); ++ int ret; ++ ++- ath10k_dbg(ATH10K_DBG_BMI, "bmi done\n"); +++ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi done\n"); ++ ++ if (ar->bmi.done_sent) { ++- ath10k_dbg(ATH10K_DBG_BMI, "bmi skipped\n"); +++ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi skipped\n"); ++ return 0; ++ } ++ ++@@ -45,7 +45,7 @@ int ath10k_bmi_done(struct ath10k *ar) ++ ++ ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL); ++ if (ret) { ++- ath10k_warn("unable to write to the device: %d\n", ret); +++ ath10k_warn(ar, "unable to write to the device: %d\n", ret); ++ return ret; ++ } ++ ++@@ -61,10 +61,10 @@ int ath10k_bmi_get_target_info(struct at ++ u32 resplen = sizeof(resp.get_target_info); ++ int ret; ++ ++- ath10k_dbg(ATH10K_DBG_BMI, "bmi get target info\n"); +++ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi get target info\n"); ++ ++ if (ar->bmi.done_sent) { ++- ath10k_warn("BMI Get Target Info Command disallowed\n"); +++ ath10k_warn(ar, "BMI Get Target Info Command disallowed\n"); ++ return -EBUSY; ++ } ++ ++@@ -72,12 +72,12 @@ int ath10k_bmi_get_target_info(struct at ++ ++ ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen); ++ if (ret) { ++- ath10k_warn("unable to get target info from device\n"); +++ ath10k_warn(ar, "unable to get target info from device\n"); ++ return ret; ++ } ++ ++ if (resplen < sizeof(resp.get_target_info)) { ++- ath10k_warn("invalid get_target_info response length (%d)\n", +++ ath10k_warn(ar, "invalid get_target_info response length (%d)\n", ++ resplen); ++ return -EIO; ++ } ++@@ -97,11 +97,11 @@ int ath10k_bmi_read_memory(struct ath10k ++ u32 rxlen; ++ int ret; ++ ++- ath10k_dbg(ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n", +++ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n", ++ address, length); ++ ++ if (ar->bmi.done_sent) { ++- ath10k_warn("command disallowed\n"); +++ ath10k_warn(ar, "command disallowed\n"); ++ return -EBUSY; ++ } ++ ++@@ -115,7 +115,7 @@ int ath10k_bmi_read_memory(struct ath10k ++ ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, ++ &resp, &rxlen); ++ if (ret) { ++- ath10k_warn("unable to read from the device (%d)\n", +++ ath10k_warn(ar, "unable to read from the device (%d)\n", ++ ret); ++ return ret; ++ } ++@@ -137,11 +137,11 @@ int ath10k_bmi_write_memory(struct ath10 ++ u32 txlen; ++ int ret; ++ ++- ath10k_dbg(ATH10K_DBG_BMI, "bmi write address 0x%x length %d\n", +++ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi write address 0x%x length %d\n", ++ address, length); ++ ++ if (ar->bmi.done_sent) { ++- ath10k_warn("command disallowed\n"); +++ ath10k_warn(ar, "command disallowed\n"); ++ return -EBUSY; ++ } ++ ++@@ -159,7 +159,7 @@ int ath10k_bmi_write_memory(struct ath10 ++ ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen, ++ NULL, NULL); ++ if (ret) { ++- ath10k_warn("unable to write to the device (%d)\n", +++ ath10k_warn(ar, "unable to write to the device (%d)\n", ++ ret); ++ return ret; ++ } ++@@ -183,11 +183,11 @@ int ath10k_bmi_execute(struct ath10k *ar ++ u32 resplen = sizeof(resp.execute); ++ int ret; ++ ++- ath10k_dbg(ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n", +++ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n", ++ address, param); ++ ++ if (ar->bmi.done_sent) { ++- ath10k_warn("command disallowed\n"); +++ ath10k_warn(ar, "command disallowed\n"); ++ return -EBUSY; ++ } ++ ++@@ -197,19 +197,19 @@ int ath10k_bmi_execute(struct ath10k *ar ++ ++ ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen); ++ if (ret) { ++- ath10k_warn("unable to read from the device\n"); +++ ath10k_warn(ar, "unable to read from the device\n"); ++ return ret; ++ } ++ ++ if (resplen < sizeof(resp.execute)) { ++- ath10k_warn("invalid execute response length (%d)\n", +++ ath10k_warn(ar, "invalid execute response length (%d)\n", ++ resplen); ++ return -EIO; ++ } ++ ++ *result = __le32_to_cpu(resp.execute.result); ++ ++- ath10k_dbg(ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result); +++ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result); ++ ++ return 0; ++ } ++@@ -221,11 +221,11 @@ int ath10k_bmi_lz_data(struct ath10k *ar ++ u32 txlen; ++ int ret; ++ ++- ath10k_dbg(ATH10K_DBG_BMI, "bmi lz data buffer 0x%p length %d\n", +++ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz data buffer 0x%p length %d\n", ++ buffer, length); ++ ++ if (ar->bmi.done_sent) { ++- ath10k_warn("command disallowed\n"); +++ ath10k_warn(ar, "command disallowed\n"); ++ return -EBUSY; ++ } ++ ++@@ -241,7 +241,7 @@ int ath10k_bmi_lz_data(struct ath10k *ar ++ ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen, ++ NULL, NULL); ++ if (ret) { ++- ath10k_warn("unable to write to the device\n"); +++ ath10k_warn(ar, "unable to write to the device\n"); ++ return ret; ++ } ++ ++@@ -258,11 +258,11 @@ int ath10k_bmi_lz_stream_start(struct at ++ u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.lz_start); ++ int ret; ++ ++- ath10k_dbg(ATH10K_DBG_BMI, "bmi lz stream start address 0x%x\n", +++ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz stream start address 0x%x\n", ++ address); ++ ++ if (ar->bmi.done_sent) { ++- ath10k_warn("command disallowed\n"); +++ ath10k_warn(ar, "command disallowed\n"); ++ return -EBUSY; ++ } ++ ++@@ -271,7 +271,7 @@ int ath10k_bmi_lz_stream_start(struct at ++ ++ ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL); ++ if (ret) { ++- ath10k_warn("unable to Start LZ Stream to the device\n"); +++ ath10k_warn(ar, "unable to Start LZ Stream to the device\n"); ++ return ret; ++ } ++ ++@@ -286,7 +286,7 @@ int ath10k_bmi_fast_download(struct ath1 ++ u32 trailer_len = length - head_len; ++ int ret; ++ ++- ath10k_dbg(ATH10K_DBG_BMI, +++ ath10k_dbg(ar, ATH10K_DBG_BMI, ++ "bmi fast download address 0x%x buffer 0x%p length %d\n", ++ address, buffer, length); ++ ++--- a/drivers/net/wireless/ath/ath10k/bmi.h +++++ b/drivers/net/wireless/ath/ath10k/bmi.h ++@@ -177,7 +177,6 @@ struct bmi_target_info { ++ u32 type; ++ }; ++ ++- ++ /* in msec */ ++ #define BMI_COMMUNICATION_TIMEOUT_HZ (1*HZ) ++ ++@@ -201,7 +200,8 @@ int ath10k_bmi_write_memory(struct ath10 ++ \ ++ addr = host_interest_item_address(HI_ITEM(item)); \ ++ ret = ath10k_bmi_read_memory(ar, addr, (u8 *)&tmp, 4); \ ++- *val = __le32_to_cpu(tmp); \ +++ if (!ret) \ +++ *val = __le32_to_cpu(tmp); \ ++ ret; \ ++ }) ++ ++--- a/drivers/net/wireless/ath/ath10k/ce.c +++++ b/drivers/net/wireless/ath/ath10k/ce.c ++@@ -260,7 +260,6 @@ static inline void ath10k_ce_engine_int_ ++ ath10k_pci_write32(ar, ce_ctrl_addr + HOST_IS_ADDRESS, mask); ++ } ++ ++- ++ /* ++ * Guts of ath10k_ce_send, used by both ath10k_ce_send and ++ * ath10k_ce_sendlist_send. ++@@ -284,13 +283,9 @@ int ath10k_ce_send_nolock(struct ath10k_ ++ int ret = 0; ++ ++ if (nbytes > ce_state->src_sz_max) ++- ath10k_warn("%s: send more we can (nbytes: %d, max: %d)\n", +++ ath10k_warn(ar, "%s: send more we can (nbytes: %d, max: %d)\n", ++ __func__, nbytes, ce_state->src_sz_max); ++ ++- ret = ath10k_pci_wake(ar); ++- if (ret) ++- return ret; ++- ++ if (unlikely(CE_RING_DELTA(nentries_mask, ++ write_index, sw_index - 1) <= 0)) { ++ ret = -ENOSR; ++@@ -325,10 +320,36 @@ int ath10k_ce_send_nolock(struct ath10k_ ++ ++ src_ring->write_index = write_index; ++ exit: ++- ath10k_pci_sleep(ar); ++ return ret; ++ } ++ +++void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe) +++{ +++ struct ath10k *ar = pipe->ar; +++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); +++ struct ath10k_ce_ring *src_ring = pipe->src_ring; +++ u32 ctrl_addr = pipe->ctrl_addr; +++ +++ lockdep_assert_held(&ar_pci->ce_lock); +++ +++ /* +++ * This function must be called only if there is an incomplete +++ * scatter-gather transfer (before index register is updated) +++ * that needs to be cleaned up. +++ */ +++ if (WARN_ON_ONCE(src_ring->write_index == src_ring->sw_index)) +++ return; +++ +++ if (WARN_ON_ONCE(src_ring->write_index == +++ ath10k_ce_src_ring_write_index_get(ar, ctrl_addr))) +++ return; +++ +++ src_ring->write_index--; +++ src_ring->write_index &= src_ring->nentries_mask; +++ +++ src_ring->per_transfer_context[src_ring->write_index] = NULL; +++} +++ ++ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state, ++ void *per_transfer_context, ++ u32 buffer, ++@@ -363,49 +384,56 @@ int ath10k_ce_num_free_src_entries(struc ++ return delta; ++ } ++ ++-int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state, ++- void *per_recv_context, ++- u32 buffer) +++int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe) ++ { ++- struct ath10k_ce_ring *dest_ring = ce_state->dest_ring; ++- u32 ctrl_addr = ce_state->ctrl_addr; ++- struct ath10k *ar = ce_state->ar; +++ struct ath10k *ar = pipe->ar; ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); +++ struct ath10k_ce_ring *dest_ring = pipe->dest_ring; ++ unsigned int nentries_mask = dest_ring->nentries_mask; ++- unsigned int write_index; ++- unsigned int sw_index; ++- int ret; +++ unsigned int write_index = dest_ring->write_index; +++ unsigned int sw_index = dest_ring->sw_index; ++ ++- spin_lock_bh(&ar_pci->ce_lock); ++- write_index = dest_ring->write_index; ++- sw_index = dest_ring->sw_index; +++ lockdep_assert_held(&ar_pci->ce_lock); ++ ++- ret = ath10k_pci_wake(ar); ++- if (ret) ++- goto out; +++ return CE_RING_DELTA(nentries_mask, write_index, sw_index - 1); +++} ++ ++- if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) > 0) { ++- struct ce_desc *base = dest_ring->base_addr_owner_space; ++- struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, write_index); +++int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr) +++{ +++ struct ath10k *ar = pipe->ar; +++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); +++ struct ath10k_ce_ring *dest_ring = pipe->dest_ring; +++ unsigned int nentries_mask = dest_ring->nentries_mask; +++ unsigned int write_index = dest_ring->write_index; +++ unsigned int sw_index = dest_ring->sw_index; +++ struct ce_desc *base = dest_ring->base_addr_owner_space; +++ struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, write_index); +++ u32 ctrl_addr = pipe->ctrl_addr; ++ ++- /* Update destination descriptor */ ++- desc->addr = __cpu_to_le32(buffer); ++- desc->nbytes = 0; +++ lockdep_assert_held(&ar_pci->ce_lock); ++ ++- dest_ring->per_transfer_context[write_index] = ++- per_recv_context; +++ if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) == 0) +++ return -EIO; ++ ++- /* Update Destination Ring Write Index */ ++- write_index = CE_RING_IDX_INCR(nentries_mask, write_index); ++- ath10k_ce_dest_ring_write_index_set(ar, ctrl_addr, write_index); ++- dest_ring->write_index = write_index; ++- ret = 0; ++- } else { ++- ret = -EIO; ++- } ++- ath10k_pci_sleep(ar); +++ desc->addr = __cpu_to_le32(paddr); +++ desc->nbytes = 0; +++ +++ dest_ring->per_transfer_context[write_index] = ctx; +++ write_index = CE_RING_IDX_INCR(nentries_mask, write_index); +++ ath10k_ce_dest_ring_write_index_set(ar, ctrl_addr, write_index); +++ dest_ring->write_index = write_index; +++ +++ return 0; +++} ++ ++-out: +++int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr) +++{ +++ struct ath10k *ar = pipe->ar; +++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); +++ int ret; +++ +++ spin_lock_bh(&ar_pci->ce_lock); +++ ret = __ath10k_ce_rx_post_buf(pipe, ctx, paddr); ++ spin_unlock_bh(&ar_pci->ce_lock); ++ ++ return ret; ++@@ -415,12 +443,12 @@ out: ++ * Guts of ath10k_ce_completed_recv_next. ++ * The caller takes responsibility for any necessary locking. ++ */ ++-static int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state, ++- void **per_transfer_contextp, ++- u32 *bufferp, ++- unsigned int *nbytesp, ++- unsigned int *transfer_idp, ++- unsigned int *flagsp) +++int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state, +++ void **per_transfer_contextp, +++ u32 *bufferp, +++ unsigned int *nbytesp, +++ unsigned int *transfer_idp, +++ unsigned int *flagsp) ++ { ++ struct ath10k_ce_ring *dest_ring = ce_state->dest_ring; ++ unsigned int nentries_mask = dest_ring->nentries_mask; ++@@ -530,6 +558,7 @@ int ath10k_ce_revoke_recv_next(struct at ++ ++ /* sanity */ ++ dest_ring->per_transfer_context[sw_index] = NULL; +++ desc->nbytes = 0; ++ ++ /* Update sw_index */ ++ sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); ++@@ -548,11 +577,11 @@ int ath10k_ce_revoke_recv_next(struct at ++ * Guts of ath10k_ce_completed_send_next. ++ * The caller takes responsibility for any necessary locking. ++ */ ++-static int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state, ++- void **per_transfer_contextp, ++- u32 *bufferp, ++- unsigned int *nbytesp, ++- unsigned int *transfer_idp) +++int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state, +++ void **per_transfer_contextp, +++ u32 *bufferp, +++ unsigned int *nbytesp, +++ unsigned int *transfer_idp) ++ { ++ struct ath10k_ce_ring *src_ring = ce_state->src_ring; ++ u32 ctrl_addr = ce_state->ctrl_addr; ++@@ -561,7 +590,6 @@ static int ath10k_ce_completed_send_next ++ unsigned int sw_index = src_ring->sw_index; ++ struct ce_desc *sdesc, *sbase; ++ unsigned int read_index; ++- int ret; ++ ++ if (src_ring->hw_index == sw_index) { ++ /* ++@@ -572,20 +600,17 @@ static int ath10k_ce_completed_send_next ++ * value of the HW index has become stale. ++ */ ++ ++- ret = ath10k_pci_wake(ar); ++- if (ret) ++- return ret; ++- ++- src_ring->hw_index = ++- ath10k_ce_src_ring_read_index_get(ar, ctrl_addr); ++- src_ring->hw_index &= nentries_mask; +++ read_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr); +++ if (read_index == 0xffffffff) +++ return -ENODEV; ++ ++- ath10k_pci_sleep(ar); +++ read_index &= nentries_mask; +++ src_ring->hw_index = read_index; ++ } ++ ++ read_index = src_ring->hw_index; ++ ++- if ((read_index == sw_index) || (read_index == 0xffffffff)) +++ if (read_index == sw_index) ++ return -EIO; ++ ++ sbase = src_ring->shadow_base; ++@@ -701,11 +726,6 @@ void ath10k_ce_per_engine_service(struct ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++ struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; ++ u32 ctrl_addr = ce_state->ctrl_addr; ++- int ret; ++- ++- ret = ath10k_pci_wake(ar); ++- if (ret) ++- return; ++ ++ spin_lock_bh(&ar_pci->ce_lock); ++ ++@@ -730,7 +750,6 @@ void ath10k_ce_per_engine_service(struct ++ ath10k_ce_engine_int_status_clear(ar, ctrl_addr, CE_WATERMARK_MASK); ++ ++ spin_unlock_bh(&ar_pci->ce_lock); ++- ath10k_pci_sleep(ar); ++ } ++ ++ /* ++@@ -741,13 +760,9 @@ void ath10k_ce_per_engine_service(struct ++ ++ void ath10k_ce_per_engine_service_any(struct ath10k *ar) ++ { ++- int ce_id, ret; +++ int ce_id; ++ u32 intr_summary; ++ ++- ret = ath10k_pci_wake(ar); ++- if (ret) ++- return; ++- ++ intr_summary = CE_INTERRUPT_SUMMARY(ar); ++ ++ for (ce_id = 0; intr_summary && (ce_id < CE_COUNT); ce_id++) { ++@@ -759,8 +774,6 @@ void ath10k_ce_per_engine_service_any(st ++ ++ ath10k_ce_per_engine_service(ar, ce_id); ++ } ++- ++- ath10k_pci_sleep(ar); ++ } ++ ++ /* ++@@ -770,16 +783,11 @@ void ath10k_ce_per_engine_service_any(st ++ * ++ * Called with ce_lock held. ++ */ ++-static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state, ++- int disable_copy_compl_intr) +++static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state) ++ { ++ u32 ctrl_addr = ce_state->ctrl_addr; ++ struct ath10k *ar = ce_state->ar; ++- int ret; ++- ++- ret = ath10k_pci_wake(ar); ++- if (ret) ++- return; +++ bool disable_copy_compl_intr = ce_state->attr_flags & CE_ATTR_DIS_INTR; ++ ++ if ((!disable_copy_compl_intr) && ++ (ce_state->send_cb || ce_state->recv_cb)) ++@@ -788,54 +796,33 @@ static void ath10k_ce_per_engine_handler ++ ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr); ++ ++ ath10k_ce_watermark_intr_disable(ar, ctrl_addr); ++- ++- ath10k_pci_sleep(ar); ++ } ++ ++ int ath10k_ce_disable_interrupts(struct ath10k *ar) ++ { ++- int ce_id, ret; ++- ++- ret = ath10k_pci_wake(ar); ++- if (ret) ++- return ret; +++ int ce_id; ++ ++ for (ce_id = 0; ce_id < CE_COUNT; ce_id++) { ++- u32 ctrl_addr = ath10k_ce_base_address(ce_id); +++ u32 ctrl_addr = ath10k_ce_base_address(ar, ce_id); ++ ++ ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr); ++ ath10k_ce_error_intr_disable(ar, ctrl_addr); ++ ath10k_ce_watermark_intr_disable(ar, ctrl_addr); ++ } ++ ++- ath10k_pci_sleep(ar); ++- ++ return 0; ++ } ++ ++-void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state, ++- void (*send_cb)(struct ath10k_ce_pipe *), ++- int disable_interrupts) +++void ath10k_ce_enable_interrupts(struct ath10k *ar) ++ { ++- struct ath10k *ar = ce_state->ar; ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); +++ int ce_id; ++ ++- spin_lock_bh(&ar_pci->ce_lock); ++- ce_state->send_cb = send_cb; ++- ath10k_ce_per_engine_handler_adjust(ce_state, disable_interrupts); ++- spin_unlock_bh(&ar_pci->ce_lock); ++-} ++- ++-void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state, ++- void (*recv_cb)(struct ath10k_ce_pipe *)) ++-{ ++- struct ath10k *ar = ce_state->ar; ++- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++- ++- spin_lock_bh(&ar_pci->ce_lock); ++- ce_state->recv_cb = recv_cb; ++- ath10k_ce_per_engine_handler_adjust(ce_state, 0); ++- spin_unlock_bh(&ar_pci->ce_lock); +++ /* Skip the last copy engine, CE7 the diagnostic window, as that +++ * uses polling and isn't initialized for interrupts. +++ */ +++ for (ce_id = 0; ce_id < CE_COUNT - 1; ce_id++) +++ ath10k_ce_per_engine_handler_adjust(&ar_pci->ce_states[ce_id]); ++ } ++ ++ static int ath10k_ce_init_src_ring(struct ath10k *ar, ++@@ -845,12 +832,12 @@ static int ath10k_ce_init_src_ring(struc ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++ struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; ++ struct ath10k_ce_ring *src_ring = ce_state->src_ring; ++- u32 nentries, ctrl_addr = ath10k_ce_base_address(ce_id); +++ u32 nentries, ctrl_addr = ath10k_ce_base_address(ar, ce_id); ++ ++ nentries = roundup_pow_of_two(attr->src_nentries); ++ ++- memset(src_ring->per_transfer_context, 0, ++- nentries * sizeof(*src_ring->per_transfer_context)); +++ memset(src_ring->base_addr_owner_space, 0, +++ nentries * sizeof(struct ce_desc)); ++ ++ src_ring->sw_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr); ++ src_ring->sw_index &= src_ring->nentries_mask; ++@@ -868,7 +855,7 @@ static int ath10k_ce_init_src_ring(struc ++ ath10k_ce_src_ring_lowmark_set(ar, ctrl_addr, 0); ++ ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, nentries); ++ ++- ath10k_dbg(ATH10K_DBG_BOOT, +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, ++ "boot init ce src ring id %d entries %d base_addr %p\n", ++ ce_id, nentries, src_ring->base_addr_owner_space); ++ ++@@ -882,12 +869,12 @@ static int ath10k_ce_init_dest_ring(stru ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++ struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; ++ struct ath10k_ce_ring *dest_ring = ce_state->dest_ring; ++- u32 nentries, ctrl_addr = ath10k_ce_base_address(ce_id); +++ u32 nentries, ctrl_addr = ath10k_ce_base_address(ar, ce_id); ++ ++ nentries = roundup_pow_of_two(attr->dest_nentries); ++ ++- memset(dest_ring->per_transfer_context, 0, ++- nentries * sizeof(*dest_ring->per_transfer_context)); +++ memset(dest_ring->base_addr_owner_space, 0, +++ nentries * sizeof(struct ce_desc)); ++ ++ dest_ring->sw_index = ath10k_ce_dest_ring_read_index_get(ar, ctrl_addr); ++ dest_ring->sw_index &= dest_ring->nentries_mask; ++@@ -902,7 +889,7 @@ static int ath10k_ce_init_dest_ring(stru ++ ath10k_ce_dest_ring_lowmark_set(ar, ctrl_addr, 0); ++ ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, nentries); ++ ++- ath10k_dbg(ATH10K_DBG_BOOT, +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, ++ "boot ce dest ring id %d entries %d base_addr %p\n", ++ ce_id, nentries, dest_ring->base_addr_owner_space); ++ ++@@ -1039,59 +1026,32 @@ ath10k_ce_alloc_dest_ring(struct ath10k ++ int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id, ++ const struct ce_attr *attr) ++ { ++- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++- struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; ++ int ret; ++ ++- /* ++- * Make sure there's enough CE ringbuffer entries for HTT TX to avoid ++- * additional TX locking checks. ++- * ++- * For the lack of a better place do the check here. ++- */ ++- BUILD_BUG_ON(2*TARGET_NUM_MSDU_DESC > ++- (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); ++- BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC > ++- (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); ++- ++- ret = ath10k_pci_wake(ar); ++- if (ret) ++- return ret; ++- ++- spin_lock_bh(&ar_pci->ce_lock); ++- ce_state->ar = ar; ++- ce_state->id = ce_id; ++- ce_state->ctrl_addr = ath10k_ce_base_address(ce_id); ++- ce_state->attr_flags = attr->flags; ++- ce_state->src_sz_max = attr->src_sz_max; ++- spin_unlock_bh(&ar_pci->ce_lock); ++- ++ if (attr->src_nentries) { ++ ret = ath10k_ce_init_src_ring(ar, ce_id, attr); ++ if (ret) { ++- ath10k_err("Failed to initialize CE src ring for ID: %d (%d)\n", +++ ath10k_err(ar, "Failed to initialize CE src ring for ID: %d (%d)\n", ++ ce_id, ret); ++- goto out; +++ return ret; ++ } ++ } ++ ++ if (attr->dest_nentries) { ++ ret = ath10k_ce_init_dest_ring(ar, ce_id, attr); ++ if (ret) { ++- ath10k_err("Failed to initialize CE dest ring for ID: %d (%d)\n", +++ ath10k_err(ar, "Failed to initialize CE dest ring for ID: %d (%d)\n", ++ ce_id, ret); ++- goto out; +++ return ret; ++ } ++ } ++ ++-out: ++- ath10k_pci_sleep(ar); ++- return ret; +++ return 0; ++ } ++ ++ static void ath10k_ce_deinit_src_ring(struct ath10k *ar, unsigned int ce_id) ++ { ++- u32 ctrl_addr = ath10k_ce_base_address(ce_id); +++ u32 ctrl_addr = ath10k_ce_base_address(ar, ce_id); ++ ++ ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr, 0); ++ ath10k_ce_src_ring_size_set(ar, ctrl_addr, 0); ++@@ -1101,7 +1061,7 @@ static void ath10k_ce_deinit_src_ring(st ++ ++ static void ath10k_ce_deinit_dest_ring(struct ath10k *ar, unsigned int ce_id) ++ { ++- u32 ctrl_addr = ath10k_ce_base_address(ce_id); +++ u32 ctrl_addr = ath10k_ce_base_address(ar, ce_id); ++ ++ ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr, 0); ++ ath10k_ce_dest_ring_size_set(ar, ctrl_addr, 0); ++@@ -1110,30 +1070,49 @@ static void ath10k_ce_deinit_dest_ring(s ++ ++ void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id) ++ { ++- int ret; ++- ++- ret = ath10k_pci_wake(ar); ++- if (ret) ++- return; ++- ++ ath10k_ce_deinit_src_ring(ar, ce_id); ++ ath10k_ce_deinit_dest_ring(ar, ce_id); ++- ++- ath10k_pci_sleep(ar); ++ } ++ ++ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, ++- const struct ce_attr *attr) +++ const struct ce_attr *attr, +++ void (*send_cb)(struct ath10k_ce_pipe *), +++ void (*recv_cb)(struct ath10k_ce_pipe *)) ++ { ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++ struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; ++ int ret; ++ +++ /* +++ * Make sure there's enough CE ringbuffer entries for HTT TX to avoid +++ * additional TX locking checks. +++ * +++ * For the lack of a better place do the check here. +++ */ +++ BUILD_BUG_ON(2*TARGET_NUM_MSDU_DESC > +++ (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); +++ BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC > +++ (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); +++ BUILD_BUG_ON(2*TARGET_TLV_NUM_MSDU_DESC > +++ (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); +++ +++ ce_state->ar = ar; +++ ce_state->id = ce_id; +++ ce_state->ctrl_addr = ath10k_ce_base_address(ar, ce_id); +++ ce_state->attr_flags = attr->flags; +++ ce_state->src_sz_max = attr->src_sz_max; +++ +++ if (attr->src_nentries) +++ ce_state->send_cb = send_cb; +++ +++ if (attr->dest_nentries) +++ ce_state->recv_cb = recv_cb; +++ ++ if (attr->src_nentries) { ++ ce_state->src_ring = ath10k_ce_alloc_src_ring(ar, ce_id, attr); ++ if (IS_ERR(ce_state->src_ring)) { ++ ret = PTR_ERR(ce_state->src_ring); ++- ath10k_err("failed to allocate copy engine source ring %d: %d\n", +++ ath10k_err(ar, "failed to allocate copy engine source ring %d: %d\n", ++ ce_id, ret); ++ ce_state->src_ring = NULL; ++ return ret; ++@@ -1145,7 +1124,7 @@ int ath10k_ce_alloc_pipe(struct ath10k * ++ attr); ++ if (IS_ERR(ce_state->dest_ring)) { ++ ret = PTR_ERR(ce_state->dest_ring); ++- ath10k_err("failed to allocate copy engine destination ring %d: %d\n", +++ ath10k_err(ar, "failed to allocate copy engine destination ring %d: %d\n", ++ ce_id, ret); ++ ce_state->dest_ring = NULL; ++ return ret; ++--- a/drivers/net/wireless/ath/ath10k/ce.h +++++ b/drivers/net/wireless/ath/ath10k/ce.h ++@@ -20,7 +20,6 @@ ++ ++ #include "hif.h" ++ ++- ++ /* Maximum number of Copy Engine's supported */ ++ #define CE_COUNT_MAX 8 ++ #define CE_HTT_H2T_MSG_SRC_NENTRIES 4096 ++@@ -37,11 +36,10 @@ ++ ++ struct ath10k_ce_pipe; ++ ++- ++ #define CE_DESC_FLAGS_GATHER (1 << 0) ++ #define CE_DESC_FLAGS_BYTE_SWAP (1 << 1) ++ #define CE_DESC_FLAGS_META_DATA_MASK 0xFFFC ++-#define CE_DESC_FLAGS_META_DATA_LSB 3 +++#define CE_DESC_FLAGS_META_DATA_LSB 2 ++ ++ struct ce_desc { ++ __le32 addr; ++@@ -160,30 +158,15 @@ int ath10k_ce_send_nolock(struct ath10k_ ++ unsigned int transfer_id, ++ unsigned int flags); ++ ++-void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state, ++- void (*send_cb)(struct ath10k_ce_pipe *), ++- int disable_interrupts); +++void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe); ++ ++ int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe); ++ ++ /*==================Recv=======================*/ ++ ++-/* ++- * Make a buffer available to receive. The buffer must be at least of a ++- * minimal size appropriate for this copy engine (src_sz_max attribute). ++- * ce - which copy engine to use ++- * per_transfer_recv_context - context passed back to caller's recv_cb ++- * buffer - address of buffer in CE space ++- * Returns 0 on success; otherwise an error status. ++- * ++- * Implemenation note: Pushes a buffer to Dest ring. ++- */ ++-int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state, ++- void *per_transfer_recv_context, ++- u32 buffer); ++- ++-void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state, ++- void (*recv_cb)(struct ath10k_ce_pipe *)); +++int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe); +++int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr); +++int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr); ++ ++ /* recv flags */ ++ /* Data is byte-swapped */ ++@@ -204,10 +187,16 @@ int ath10k_ce_completed_recv_next(struct ++ * Pops 1 completed send buffer from Source ring. ++ */ ++ int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state, ++- void **per_transfer_contextp, ++- u32 *bufferp, ++- unsigned int *nbytesp, ++- unsigned int *transfer_idp); +++ void **per_transfer_contextp, +++ u32 *bufferp, +++ unsigned int *nbytesp, +++ unsigned int *transfer_idp); +++ +++int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state, +++ void **per_transfer_contextp, +++ u32 *bufferp, +++ unsigned int *nbytesp, +++ unsigned int *transfer_idp); ++ ++ /*==================CE Engine Initialization=======================*/ ++ ++@@ -215,7 +204,9 @@ int ath10k_ce_init_pipe(struct ath10k *a ++ const struct ce_attr *attr); ++ void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id); ++ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, ++- const struct ce_attr *attr); +++ const struct ce_attr *attr, +++ void (*send_cb)(struct ath10k_ce_pipe *), +++ void (*recv_cb)(struct ath10k_ce_pipe *)); ++ void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id); ++ ++ /*==================CE Engine Shutdown=======================*/ ++@@ -228,6 +219,13 @@ int ath10k_ce_revoke_recv_next(struct at ++ void **per_transfer_contextp, ++ u32 *bufferp); ++ +++int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state, +++ void **per_transfer_contextp, +++ u32 *bufferp, +++ unsigned int *nbytesp, +++ unsigned int *transfer_idp, +++ unsigned int *flagsp); +++ ++ /* ++ * Support clean shutdown by allowing the caller to cancel ++ * pending sends. Target DMA must be stopped before using ++@@ -243,6 +241,7 @@ int ath10k_ce_cancel_send_next(struct at ++ void ath10k_ce_per_engine_service_any(struct ath10k *ar); ++ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id); ++ int ath10k_ce_disable_interrupts(struct ath10k *ar); +++void ath10k_ce_enable_interrupts(struct ath10k *ar); ++ ++ /* ce_attr.flags values */ ++ /* Use NonSnooping PCIe accesses? */ ++@@ -395,8 +394,7 @@ struct ce_attr { ++ #define DST_WATERMARK_HIGH_RESET 0 ++ #define DST_WATERMARK_ADDRESS 0x0050 ++ ++- ++-static inline u32 ath10k_ce_base_address(unsigned int ce_id) +++static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) ++ { ++ return CE0_BASE_ADDRESS + (CE1_BASE_ADDRESS - CE0_BASE_ADDRESS) * ce_id; ++ } ++--- a/drivers/net/wireless/ath/ath10k/core.c +++++ b/drivers/net/wireless/ath/ath10k/core.c ++@@ -17,6 +17,7 @@ ++ ++ #include ++ #include +++#include ++ ++ #include "core.h" ++ #include "mac.h" ++@@ -26,68 +27,88 @@ ++ #include "bmi.h" ++ #include "debug.h" ++ #include "htt.h" +++#include "testmode.h" +++#include "wmi-ops.h" ++ ++ unsigned int ath10k_debug_mask; ++ static bool uart_print; ++-static unsigned int ath10k_p2p; +++static bool skip_otp; +++ ++ module_param_named(debug_mask, ath10k_debug_mask, uint, 0644); ++ module_param(uart_print, bool, 0644); ++-module_param_named(p2p, ath10k_p2p, uint, 0644); +++module_param(skip_otp, bool, 0644); +++ ++ MODULE_PARM_DESC(debug_mask, "Debugging mask"); ++ MODULE_PARM_DESC(uart_print, "Uart target debugging"); ++-MODULE_PARM_DESC(p2p, "Enable ath10k P2P support"); +++MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); ++ ++ static const struct ath10k_hw_params ath10k_hw_params_list[] = { ++ { ++ .id = QCA988X_HW_2_0_VERSION, ++ .name = "qca988x hw2.0", ++ .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR, +++ .uart_pin = 7, ++ .fw = { ++ .dir = QCA988X_HW_2_0_FW_DIR, ++ .fw = QCA988X_HW_2_0_FW_FILE, ++ .otp = QCA988X_HW_2_0_OTP_FILE, ++ .board = QCA988X_HW_2_0_BOARD_DATA_FILE, +++ .board_size = QCA988X_BOARD_DATA_SZ, +++ .board_ext_size = QCA988X_BOARD_EXT_DATA_SZ, +++ }, +++ }, +++ { +++ .id = QCA6174_HW_2_1_VERSION, +++ .name = "qca6174 hw2.1", +++ .patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR, +++ .uart_pin = 6, +++ .fw = { +++ .dir = QCA6174_HW_2_1_FW_DIR, +++ .fw = QCA6174_HW_2_1_FW_FILE, +++ .otp = QCA6174_HW_2_1_OTP_FILE, +++ .board = QCA6174_HW_2_1_BOARD_DATA_FILE, +++ .board_size = QCA6174_BOARD_DATA_SZ, +++ .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, +++ }, +++ }, +++ { +++ .id = QCA6174_HW_3_0_VERSION, +++ .name = "qca6174 hw3.0", +++ .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, +++ .uart_pin = 6, +++ .fw = { +++ .dir = QCA6174_HW_3_0_FW_DIR, +++ .fw = QCA6174_HW_3_0_FW_FILE, +++ .otp = QCA6174_HW_3_0_OTP_FILE, +++ .board = QCA6174_HW_3_0_BOARD_DATA_FILE, +++ .board_size = QCA6174_BOARD_DATA_SZ, +++ .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, +++ }, +++ }, +++ { +++ .id = QCA6174_HW_3_2_VERSION, +++ .name = "qca6174 hw3.2", +++ .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, +++ .uart_pin = 6, +++ .fw = { +++ /* uses same binaries as hw3.0 */ +++ .dir = QCA6174_HW_3_0_FW_DIR, +++ .fw = QCA6174_HW_3_0_FW_FILE, +++ .otp = QCA6174_HW_3_0_OTP_FILE, +++ .board = QCA6174_HW_3_0_BOARD_DATA_FILE, +++ .board_size = QCA6174_BOARD_DATA_SZ, +++ .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, ++ }, ++ }, ++ }; ++ ++ static void ath10k_send_suspend_complete(struct ath10k *ar) ++ { ++- ath10k_dbg(ATH10K_DBG_BOOT, "boot suspend complete\n"); +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot suspend complete\n"); ++ ++ complete(&ar->target_suspend); ++ } ++ ++-static int ath10k_init_connect_htc(struct ath10k *ar) ++-{ ++- int status; ++- ++- status = ath10k_wmi_connect_htc_service(ar); ++- if (status) ++- goto conn_fail; ++- ++- /* Start HTC */ ++- status = ath10k_htc_start(&ar->htc); ++- if (status) ++- goto conn_fail; ++- ++- /* Wait for WMI event to be ready */ ++- status = ath10k_wmi_wait_for_service_ready(ar); ++- if (status <= 0) { ++- ath10k_warn("wmi service ready event not received"); ++- status = -ETIMEDOUT; ++- goto timeout; ++- } ++- ++- ath10k_dbg(ATH10K_DBG_BOOT, "boot wmi ready\n"); ++- return 0; ++- ++-timeout: ++- ath10k_htc_stop(&ar->htc); ++-conn_fail: ++- return status; ++-} ++- ++ static int ath10k_init_configure_target(struct ath10k *ar) ++ { ++ u32 param_host; ++@@ -97,14 +118,14 @@ static int ath10k_init_configure_target( ++ ret = ath10k_bmi_write32(ar, hi_app_host_interest, ++ HTC_PROTOCOL_VERSION); ++ if (ret) { ++- ath10k_err("settings HTC version failed\n"); +++ ath10k_err(ar, "settings HTC version failed\n"); ++ return ret; ++ } ++ ++ /* set the firmware mode to STA/IBSS/AP */ ++ ret = ath10k_bmi_read32(ar, hi_option_flag, ¶m_host); ++ if (ret) { ++- ath10k_err("setting firmware mode (1/2) failed\n"); +++ ath10k_err(ar, "setting firmware mode (1/2) failed\n"); ++ return ret; ++ } ++ ++@@ -123,14 +144,14 @@ static int ath10k_init_configure_target( ++ ++ ret = ath10k_bmi_write32(ar, hi_option_flag, param_host); ++ if (ret) { ++- ath10k_err("setting firmware mode (2/2) failed\n"); +++ ath10k_err(ar, "setting firmware mode (2/2) failed\n"); ++ return ret; ++ } ++ ++ /* We do all byte-swapping on the host */ ++ ret = ath10k_bmi_write32(ar, hi_be, 0); ++ if (ret) { ++- ath10k_err("setting host CPU BE mode failed\n"); +++ ath10k_err(ar, "setting host CPU BE mode failed\n"); ++ return ret; ++ } ++ ++@@ -138,7 +159,7 @@ static int ath10k_init_configure_target( ++ ret = ath10k_bmi_write32(ar, hi_fw_swap, 0); ++ ++ if (ret) { ++- ath10k_err("setting FW data/desc swap flags failed\n"); +++ ath10k_err(ar, "setting FW data/desc swap flags failed\n"); ++ return ret; ++ } ++ ++@@ -167,79 +188,83 @@ static const struct firmware *ath10k_fet ++ return fw; ++ } ++ ++-static int ath10k_push_board_ext_data(struct ath10k *ar) +++static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data, +++ size_t data_len) ++ { ++- u32 board_data_size = QCA988X_BOARD_DATA_SZ; ++- u32 board_ext_data_size = QCA988X_BOARD_EXT_DATA_SZ; +++ u32 board_data_size = ar->hw_params.fw.board_size; +++ u32 board_ext_data_size = ar->hw_params.fw.board_ext_size; ++ u32 board_ext_data_addr; ++ int ret; ++ ++ ret = ath10k_bmi_read32(ar, hi_board_ext_data, &board_ext_data_addr); ++ if (ret) { ++- ath10k_err("could not read board ext data addr (%d)\n", ret); +++ ath10k_err(ar, "could not read board ext data addr (%d)\n", +++ ret); ++ return ret; ++ } ++ ++- ath10k_dbg(ATH10K_DBG_BOOT, +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, ++ "boot push board extended data addr 0x%x\n", ++ board_ext_data_addr); ++ ++ if (board_ext_data_addr == 0) ++ return 0; ++ ++- if (ar->board_len != (board_data_size + board_ext_data_size)) { ++- ath10k_err("invalid board (ext) data sizes %zu != %d+%d\n", ++- ar->board_len, board_data_size, board_ext_data_size); +++ if (data_len != (board_data_size + board_ext_data_size)) { +++ ath10k_err(ar, "invalid board (ext) data sizes %zu != %d+%d\n", +++ data_len, board_data_size, board_ext_data_size); ++ return -EINVAL; ++ } ++ ++ ret = ath10k_bmi_write_memory(ar, board_ext_data_addr, ++- ar->board_data + board_data_size, +++ data + board_data_size, ++ board_ext_data_size); ++ if (ret) { ++- ath10k_err("could not write board ext data (%d)\n", ret); +++ ath10k_err(ar, "could not write board ext data (%d)\n", ret); ++ return ret; ++ } ++ ++ ret = ath10k_bmi_write32(ar, hi_board_ext_data_config, ++ (board_ext_data_size << 16) | 1); ++ if (ret) { ++- ath10k_err("could not write board ext data bit (%d)\n", ret); +++ ath10k_err(ar, "could not write board ext data bit (%d)\n", +++ ret); ++ return ret; ++ } ++ ++ return 0; ++ } ++ ++-static int ath10k_download_board_data(struct ath10k *ar) +++static int ath10k_download_board_data(struct ath10k *ar, const void *data, +++ size_t data_len) ++ { ++- u32 board_data_size = QCA988X_BOARD_DATA_SZ; +++ u32 board_data_size = ar->hw_params.fw.board_size; ++ u32 address; ++ int ret; ++ ++- ret = ath10k_push_board_ext_data(ar); +++ ret = ath10k_push_board_ext_data(ar, data, data_len); ++ if (ret) { ++- ath10k_err("could not push board ext data (%d)\n", ret); +++ ath10k_err(ar, "could not push board ext data (%d)\n", ret); ++ goto exit; ++ } ++ ++ ret = ath10k_bmi_read32(ar, hi_board_data, &address); ++ if (ret) { ++- ath10k_err("could not read board data addr (%d)\n", ret); +++ ath10k_err(ar, "could not read board data addr (%d)\n", ret); ++ goto exit; ++ } ++ ++- ret = ath10k_bmi_write_memory(ar, address, ar->board_data, +++ ret = ath10k_bmi_write_memory(ar, address, data, ++ min_t(u32, board_data_size, ++- ar->board_len)); +++ data_len)); ++ if (ret) { ++- ath10k_err("could not write board data (%d)\n", ret); +++ ath10k_err(ar, "could not write board data (%d)\n", ret); ++ goto exit; ++ } ++ ++ ret = ath10k_bmi_write32(ar, hi_board_data_initialized, 1); ++ if (ret) { ++- ath10k_err("could not write board data bit (%d)\n", ret); +++ ath10k_err(ar, "could not write board data bit (%d)\n", ret); ++ goto exit; ++ } ++ ++@@ -247,73 +272,182 @@ exit: ++ return ret; ++ } ++ +++static int ath10k_download_cal_file(struct ath10k *ar) +++{ +++ int ret; +++ +++ if (!ar->cal_file) +++ return -ENOENT; +++ +++ if (IS_ERR(ar->cal_file)) +++ return PTR_ERR(ar->cal_file); +++ +++ ret = ath10k_download_board_data(ar, ar->cal_file->data, +++ ar->cal_file->size); +++ if (ret) { +++ ath10k_err(ar, "failed to download cal_file data: %d\n", ret); +++ return ret; +++ } +++ +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cal file downloaded\n"); +++ +++ return 0; +++} +++ +++static int ath10k_download_cal_dt(struct ath10k *ar) +++{ +++ struct device_node *node; +++ int data_len; +++ void *data; +++ int ret; +++ +++ node = ar->dev->of_node; +++ if (!node) +++ /* Device Tree is optional, don't print any warnings if +++ * there's no node for ath10k. +++ */ +++ return -ENOENT; +++ +++ if (!of_get_property(node, "qcom,ath10k-calibration-data", +++ &data_len)) { +++ /* The calibration data node is optional */ +++ return -ENOENT; +++ } +++ +++ if (data_len != QCA988X_CAL_DATA_LEN) { +++ ath10k_warn(ar, "invalid calibration data length in DT: %d\n", +++ data_len); +++ ret = -EMSGSIZE; +++ goto out; +++ } +++ +++ data = kmalloc(data_len, GFP_KERNEL); +++ if (!data) { +++ ret = -ENOMEM; +++ goto out; +++ } +++ +++ ret = of_property_read_u8_array(node, "qcom,ath10k-calibration-data", +++ data, data_len); +++ if (ret) { +++ ath10k_warn(ar, "failed to read calibration data from DT: %d\n", +++ ret); +++ goto out_free; +++ } +++ +++ ret = ath10k_download_board_data(ar, data, data_len); +++ if (ret) { +++ ath10k_warn(ar, "failed to download calibration data from Device Tree: %d\n", +++ ret); +++ goto out_free; +++ } +++ +++ ret = 0; +++ +++out_free: +++ kfree(data); +++ +++out: +++ return ret; +++} +++ ++ static int ath10k_download_and_run_otp(struct ath10k *ar) ++ { ++ u32 result, address = ar->hw_params.patch_load_addr; ++ int ret; ++ +++ ret = ath10k_download_board_data(ar, ar->board_data, ar->board_len); +++ if (ret) { +++ ath10k_err(ar, "failed to download board data: %d\n", ret); +++ return ret; +++ } +++ ++ /* OTP is optional */ ++ ++ if (!ar->otp_data || !ar->otp_len) { ++- ath10k_warn("Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n", +++ ath10k_warn(ar, "Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n", ++ ar->otp_data, ar->otp_len); ++ return 0; ++ } ++ ++- ath10k_dbg(ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n", +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n", ++ address, ar->otp_len); ++ ++ ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len); ++ if (ret) { ++- ath10k_err("could not write otp (%d)\n", ret); +++ ath10k_err(ar, "could not write otp (%d)\n", ret); ++ return ret; ++ } ++ ++ ret = ath10k_bmi_execute(ar, address, 0, &result); ++ if (ret) { ++- ath10k_err("could not execute otp (%d)\n", ret); +++ ath10k_err(ar, "could not execute otp (%d)\n", ret); ++ return ret; ++ } ++ ++- ath10k_dbg(ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); ++ ++- if (result != 0) { ++- ath10k_err("otp calibration failed: %d", result); +++ if (!skip_otp && result != 0) { +++ ath10k_err(ar, "otp calibration failed: %d", result); ++ return -EINVAL; ++ } ++ ++ return 0; ++ } ++ ++-static int ath10k_download_fw(struct ath10k *ar) +++static int ath10k_download_fw(struct ath10k *ar, enum ath10k_firmware_mode mode) ++ { ++- u32 address; +++ u32 address, data_len; +++ const char *mode_name; +++ const void *data; ++ int ret; ++ ++ address = ar->hw_params.patch_load_addr; ++ ++- ret = ath10k_bmi_fast_download(ar, address, ar->firmware_data, ++- ar->firmware_len); +++ switch (mode) { +++ case ATH10K_FIRMWARE_MODE_NORMAL: +++ data = ar->firmware_data; +++ data_len = ar->firmware_len; +++ mode_name = "normal"; +++ break; +++ case ATH10K_FIRMWARE_MODE_UTF: +++ data = ar->testmode.utf->data; +++ data_len = ar->testmode.utf->size; +++ mode_name = "utf"; +++ break; +++ default: +++ ath10k_err(ar, "unknown firmware mode: %d\n", mode); +++ return -EINVAL; +++ } +++ +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, +++ "boot uploading firmware image %p len %d mode %s\n", +++ data, data_len, mode_name); +++ +++ ret = ath10k_bmi_fast_download(ar, address, data, data_len); ++ if (ret) { ++- ath10k_err("could not write fw (%d)\n", ret); ++- goto exit; +++ ath10k_err(ar, "failed to download %s firmware: %d\n", +++ mode_name, ret); +++ return ret; ++ } ++ ++-exit: ++ return ret; ++ } ++ ++ static void ath10k_core_free_firmware_files(struct ath10k *ar) ++ { ++- if (ar->board && !IS_ERR(ar->board)) +++ if (!IS_ERR(ar->board)) ++ release_firmware(ar->board); ++ ++- if (ar->otp && !IS_ERR(ar->otp)) +++ if (!IS_ERR(ar->otp)) ++ release_firmware(ar->otp); ++ ++- if (ar->firmware && !IS_ERR(ar->firmware)) +++ if (!IS_ERR(ar->firmware)) ++ release_firmware(ar->firmware); ++ +++ if (!IS_ERR(ar->cal_file)) +++ release_firmware(ar->cal_file); +++ ++ ar->board = NULL; ++ ar->board_data = NULL; ++ ar->board_len = 0; ++@@ -325,6 +459,27 @@ static void ath10k_core_free_firmware_fi ++ ar->firmware = NULL; ++ ar->firmware_data = NULL; ++ ar->firmware_len = 0; +++ +++ ar->cal_file = NULL; +++} +++ +++static int ath10k_fetch_cal_file(struct ath10k *ar) +++{ +++ char filename[100]; +++ +++ /* cal--.bin */ +++ scnprintf(filename, sizeof(filename), "cal-%s-%s.bin", +++ ath10k_bus_str(ar->hif.bus), dev_name(ar->dev)); +++ +++ ar->cal_file = ath10k_fetch_fw_file(ar, ATH10K_FW_DIR, filename); +++ if (IS_ERR(ar->cal_file)) +++ /* calibration file is optional, don't print any warnings */ +++ return PTR_ERR(ar->cal_file); +++ +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "found calibration file %s/%s\n", +++ ATH10K_FW_DIR, filename); +++ +++ return 0; ++ } ++ ++ static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar) ++@@ -332,12 +487,12 @@ static int ath10k_core_fetch_firmware_ap ++ int ret = 0; ++ ++ if (ar->hw_params.fw.fw == NULL) { ++- ath10k_err("firmware file not defined\n"); +++ ath10k_err(ar, "firmware file not defined\n"); ++ return -EINVAL; ++ } ++ ++ if (ar->hw_params.fw.board == NULL) { ++- ath10k_err("board data file not defined"); +++ ath10k_err(ar, "board data file not defined"); ++ return -EINVAL; ++ } ++ ++@@ -346,7 +501,7 @@ static int ath10k_core_fetch_firmware_ap ++ ar->hw_params.fw.board); ++ if (IS_ERR(ar->board)) { ++ ret = PTR_ERR(ar->board); ++- ath10k_err("could not fetch board data (%d)\n", ret); +++ ath10k_err(ar, "could not fetch board data (%d)\n", ret); ++ goto err; ++ } ++ ++@@ -358,7 +513,7 @@ static int ath10k_core_fetch_firmware_ap ++ ar->hw_params.fw.fw); ++ if (IS_ERR(ar->firmware)) { ++ ret = PTR_ERR(ar->firmware); ++- ath10k_err("could not fetch firmware (%d)\n", ret); +++ ath10k_err(ar, "could not fetch firmware (%d)\n", ret); ++ goto err; ++ } ++ ++@@ -374,7 +529,7 @@ static int ath10k_core_fetch_firmware_ap ++ ar->hw_params.fw.otp); ++ if (IS_ERR(ar->otp)) { ++ ret = PTR_ERR(ar->otp); ++- ath10k_err("could not fetch otp (%d)\n", ret); +++ ath10k_err(ar, "could not fetch otp (%d)\n", ret); ++ goto err; ++ } ++ ++@@ -394,12 +549,12 @@ static int ath10k_core_fetch_firmware_ap ++ int ie_id, i, index, bit, ret; ++ struct ath10k_fw_ie *hdr; ++ const u8 *data; ++- __le32 *timestamp; +++ __le32 *timestamp, *version; ++ ++ /* first fetch the firmware file (firmware-*.bin) */ ++ ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name); ++ if (IS_ERR(ar->firmware)) { ++- ath10k_err("could not fetch firmware file '%s/%s': %ld\n", +++ ath10k_err(ar, "could not fetch firmware file '%s/%s': %ld\n", ++ ar->hw_params.fw.dir, name, PTR_ERR(ar->firmware)); ++ return PTR_ERR(ar->firmware); ++ } ++@@ -411,14 +566,14 @@ static int ath10k_core_fetch_firmware_ap ++ magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1; ++ ++ if (len < magic_len) { ++- ath10k_err("firmware file '%s/%s' too small to contain magic: %zu\n", +++ ath10k_err(ar, "firmware file '%s/%s' too small to contain magic: %zu\n", ++ ar->hw_params.fw.dir, name, len); ++ ret = -EINVAL; ++ goto err; ++ } ++ ++ if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) { ++- ath10k_err("invalid firmware magic\n"); +++ ath10k_err(ar, "invalid firmware magic\n"); ++ ret = -EINVAL; ++ goto err; ++ } ++@@ -440,7 +595,7 @@ static int ath10k_core_fetch_firmware_ap ++ data += sizeof(*hdr); ++ ++ if (len < ie_len) { ++- ath10k_err("invalid length for FW IE %d (%zu < %zu)\n", +++ ath10k_err(ar, "invalid length for FW IE %d (%zu < %zu)\n", ++ ie_id, len, ie_len); ++ ret = -EINVAL; ++ goto err; ++@@ -454,7 +609,7 @@ static int ath10k_core_fetch_firmware_ap ++ memcpy(ar->hw->wiphy->fw_version, data, ie_len); ++ ar->hw->wiphy->fw_version[ie_len] = '\0'; ++ ++- ath10k_dbg(ATH10K_DBG_BOOT, +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, ++ "found fw version %s\n", ++ ar->hw->wiphy->fw_version); ++ break; ++@@ -464,11 +619,11 @@ static int ath10k_core_fetch_firmware_ap ++ ++ timestamp = (__le32 *)data; ++ ++- ath10k_dbg(ATH10K_DBG_BOOT, "found fw timestamp %d\n", +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw timestamp %d\n", ++ le32_to_cpup(timestamp)); ++ break; ++ case ATH10K_FW_IE_FEATURES: ++- ath10k_dbg(ATH10K_DBG_BOOT, +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, ++ "found firmware features ie (%zd B)\n", ++ ie_len); ++ ++@@ -480,19 +635,19 @@ static int ath10k_core_fetch_firmware_ap ++ break; ++ ++ if (data[index] & (1 << bit)) { ++- ath10k_dbg(ATH10K_DBG_BOOT, +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, ++ "Enabling feature bit: %i\n", ++ i); ++ __set_bit(i, ar->fw_features); ++ } ++ } ++ ++- ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "", +++ ath10k_dbg_dump(ar, ATH10K_DBG_BOOT, "features", "", ++ ar->fw_features, ++ sizeof(ar->fw_features)); ++ break; ++ case ATH10K_FW_IE_FW_IMAGE: ++- ath10k_dbg(ATH10K_DBG_BOOT, +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, ++ "found fw image ie (%zd B)\n", ++ ie_len); ++ ++@@ -501,7 +656,7 @@ static int ath10k_core_fetch_firmware_ap ++ ++ break; ++ case ATH10K_FW_IE_OTP_IMAGE: ++- ath10k_dbg(ATH10K_DBG_BOOT, +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, ++ "found otp image ie (%zd B)\n", ++ ie_len); ++ ++@@ -509,8 +664,19 @@ static int ath10k_core_fetch_firmware_ap ++ ar->otp_len = ie_len; ++ ++ break; +++ case ATH10K_FW_IE_WMI_OP_VERSION: +++ if (ie_len != sizeof(u32)) +++ break; +++ +++ version = (__le32 *)data; +++ +++ ar->wmi.op_version = le32_to_cpup(version); +++ +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie wmi op version %d\n", +++ ar->wmi.op_version); +++ break; ++ default: ++- ath10k_warn("Unknown FW IE: %u\n", +++ ath10k_warn(ar, "Unknown FW IE: %u\n", ++ le32_to_cpu(hdr->id)); ++ break; ++ } ++@@ -523,7 +689,7 @@ static int ath10k_core_fetch_firmware_ap ++ } ++ ++ if (!ar->firmware_data || !ar->firmware_len) { ++- ath10k_warn("No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n", +++ ath10k_warn(ar, "No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n", ++ ar->hw_params.fw.dir, name); ++ ret = -ENOMEDIUM; ++ goto err; ++@@ -531,7 +697,7 @@ static int ath10k_core_fetch_firmware_ap ++ ++ /* now fetch the board file */ ++ if (ar->hw_params.fw.board == NULL) { ++- ath10k_err("board data file not defined"); +++ ath10k_err(ar, "board data file not defined"); ++ ret = -EINVAL; ++ goto err; ++ } ++@@ -541,7 +707,7 @@ static int ath10k_core_fetch_firmware_ap ++ ar->hw_params.fw.board); ++ if (IS_ERR(ar->board)) { ++ ret = PTR_ERR(ar->board); ++- ath10k_err("could not fetch board data '%s/%s' (%d)\n", +++ ath10k_err(ar, "could not fetch board data '%s/%s' (%d)\n", ++ ar->hw_params.fw.dir, ar->hw_params.fw.board, ++ ret); ++ goto err; ++@@ -561,49 +727,79 @@ static int ath10k_core_fetch_firmware_fi ++ { ++ int ret; ++ +++ /* calibration file is optional, don't check for any errors */ +++ ath10k_fetch_cal_file(ar); +++ +++ ar->fw_api = 4; +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); +++ +++ ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API4_FILE); +++ if (ret == 0) +++ goto success; +++ +++ ar->fw_api = 3; +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); +++ +++ ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API3_FILE); +++ if (ret == 0) +++ goto success; +++ ++ ar->fw_api = 2; ++- ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); ++ ++ ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE); ++ if (ret == 0) ++ goto success; ++ ++ ar->fw_api = 1; ++- ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); ++ ++ ret = ath10k_core_fetch_firmware_api_1(ar); ++ if (ret) ++ return ret; ++ ++ success: ++- ath10k_dbg(ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api); +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api); ++ ++ return 0; ++ } ++ ++-static int ath10k_init_download_firmware(struct ath10k *ar) +++static int ath10k_download_cal_data(struct ath10k *ar) ++ { ++ int ret; ++ ++- ret = ath10k_download_board_data(ar); ++- if (ret) { ++- ath10k_err("failed to download board data: %d\n", ret); ++- return ret; +++ ret = ath10k_download_cal_file(ar); +++ if (ret == 0) { +++ ar->cal_mode = ATH10K_CAL_MODE_FILE; +++ goto done; ++ } ++ ++- ret = ath10k_download_and_run_otp(ar); ++- if (ret) { ++- ath10k_err("failed to run otp: %d\n", ret); ++- return ret; +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, +++ "boot did not find a calibration file, try DT next: %d\n", +++ ret); +++ +++ ret = ath10k_download_cal_dt(ar); +++ if (ret == 0) { +++ ar->cal_mode = ATH10K_CAL_MODE_DT; +++ goto done; ++ } ++ ++- ret = ath10k_download_fw(ar); +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, +++ "boot did not find DT entry, try OTP next: %d\n", +++ ret); +++ +++ ret = ath10k_download_and_run_otp(ar); ++ if (ret) { ++- ath10k_err("failed to download firmware: %d\n", ret); +++ ath10k_err(ar, "failed to run otp: %d\n", ret); ++ return ret; ++ } ++ ++- return ret; +++ ar->cal_mode = ATH10K_CAL_MODE_OTP; +++ +++done: +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using calibration mode %s\n", +++ ath10k_cal_mode_str(ar->cal_mode)); +++ return 0; ++ } ++ ++ static int ath10k_init_uart(struct ath10k *ar) ++@@ -616,33 +812,33 @@ static int ath10k_init_uart(struct ath10 ++ */ ++ ret = ath10k_bmi_write32(ar, hi_serial_enable, 0); ++ if (ret) { ++- ath10k_warn("could not disable UART prints (%d)\n", ret); +++ ath10k_warn(ar, "could not disable UART prints (%d)\n", ret); ++ return ret; ++ } ++ ++ if (!uart_print) ++ return 0; ++ ++- ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, 7); +++ ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, ar->hw_params.uart_pin); ++ if (ret) { ++- ath10k_warn("could not enable UART prints (%d)\n", ret); +++ ath10k_warn(ar, "could not enable UART prints (%d)\n", ret); ++ return ret; ++ } ++ ++ ret = ath10k_bmi_write32(ar, hi_serial_enable, 1); ++ if (ret) { ++- ath10k_warn("could not enable UART prints (%d)\n", ret); +++ ath10k_warn(ar, "could not enable UART prints (%d)\n", ret); ++ return ret; ++ } ++ ++ /* Set the UART baud rate to 19200. */ ++ ret = ath10k_bmi_write32(ar, hi_desired_baud_rate, 19200); ++ if (ret) { ++- ath10k_warn("could not set the baud rate (%d)\n", ret); +++ ath10k_warn(ar, "could not set the baud rate (%d)\n", ret); ++ return ret; ++ } ++ ++- ath10k_info("UART prints enabled\n"); +++ ath10k_info(ar, "UART prints enabled\n"); ++ return 0; ++ } ++ ++@@ -659,14 +855,14 @@ static int ath10k_init_hw_params(struct ++ } ++ ++ if (i == ARRAY_SIZE(ath10k_hw_params_list)) { ++- ath10k_err("Unsupported hardware version: 0x%x\n", +++ ath10k_err(ar, "Unsupported hardware version: 0x%x\n", ++ ar->target_version); ++ return -EINVAL; ++ } ++ ++ ar->hw_params = *hw_params; ++ ++- ath10k_dbg(ATH10K_DBG_BOOT, "Hardware name %s version 0x%x\n", +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "Hardware name %s version 0x%x\n", ++ ar->hw_params.name, ar->target_version); ++ ++ return 0; ++@@ -676,101 +872,124 @@ static void ath10k_core_restart(struct w ++ { ++ struct ath10k *ar = container_of(work, struct ath10k, restart_work); ++ +++ set_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags); +++ +++ /* Place a barrier to make sure the compiler doesn't reorder +++ * CRASH_FLUSH and calling other functions. +++ */ +++ barrier(); +++ +++ ieee80211_stop_queues(ar->hw); +++ ath10k_drain_tx(ar); +++ complete_all(&ar->scan.started); +++ complete_all(&ar->scan.completed); +++ complete_all(&ar->scan.on_channel); +++ complete_all(&ar->offchan_tx_completed); +++ complete_all(&ar->install_key_done); +++ complete_all(&ar->vdev_setup_done); +++ complete_all(&ar->thermal.wmi_sync); +++ wake_up(&ar->htt.empty_tx_wq); +++ wake_up(&ar->wmi.tx_credits_wq); +++ wake_up(&ar->peer_mapping_wq); +++ ++ mutex_lock(&ar->conf_mutex); ++ ++ switch (ar->state) { ++ case ATH10K_STATE_ON: ++ ar->state = ATH10K_STATE_RESTARTING; ++- ath10k_halt(ar); +++ ath10k_hif_stop(ar); +++ ath10k_scan_finish(ar); ++ ieee80211_restart_hw(ar->hw); ++ break; ++ case ATH10K_STATE_OFF: ++ /* this can happen if driver is being unloaded ++ * or if the crash happens during FW probing */ ++- ath10k_warn("cannot restart a device that hasn't been started\n"); +++ ath10k_warn(ar, "cannot restart a device that hasn't been started\n"); ++ break; ++ case ATH10K_STATE_RESTARTING: +++ /* hw restart might be requested from multiple places */ +++ break; ++ case ATH10K_STATE_RESTARTED: ++ ar->state = ATH10K_STATE_WEDGED; ++ /* fall through */ ++ case ATH10K_STATE_WEDGED: ++- ath10k_warn("device is wedged, will not restart\n"); +++ ath10k_warn(ar, "device is wedged, will not restart\n"); +++ break; +++ case ATH10K_STATE_UTF: +++ ath10k_warn(ar, "firmware restart in UTF mode not supported\n"); ++ break; ++ } ++ ++ mutex_unlock(&ar->conf_mutex); ++ } ++ ++-struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, ++- const struct ath10k_hif_ops *hif_ops) +++static int ath10k_core_init_firmware_features(struct ath10k *ar) ++ { ++- struct ath10k *ar; ++- ++- ar = ath10k_mac_create(); ++- if (!ar) ++- return NULL; ++- ++- ar->ath_common.priv = ar; ++- ar->ath_common.hw = ar->hw; ++- ++- ar->p2p = !!ath10k_p2p; ++- ar->dev = dev; ++- ++- ar->hif.priv = hif_priv; ++- ar->hif.ops = hif_ops; ++- ++- init_completion(&ar->scan.started); ++- init_completion(&ar->scan.completed); ++- init_completion(&ar->scan.on_channel); ++- init_completion(&ar->target_suspend); ++- ++- init_completion(&ar->install_key_done); ++- init_completion(&ar->vdev_setup_done); ++- ++- setup_timer(&ar->scan.timeout, ath10k_reset_scan, (unsigned long)ar); ++- ++- ar->workqueue = create_singlethread_workqueue("ath10k_wq"); ++- if (!ar->workqueue) ++- goto err_wq; ++- ++- mutex_init(&ar->conf_mutex); ++- spin_lock_init(&ar->data_lock); ++- ++- INIT_LIST_HEAD(&ar->peers); ++- init_waitqueue_head(&ar->peer_mapping_wq); ++- ++- init_completion(&ar->offchan_tx_completed); ++- INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work); ++- skb_queue_head_init(&ar->offchan_tx_queue); ++- ++- INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work); ++- skb_queue_head_init(&ar->wmi_mgmt_tx_queue); ++- ++- INIT_WORK(&ar->restart_work, ath10k_core_restart); +++ if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features) && +++ !test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { +++ ath10k_err(ar, "feature bits corrupted: 10.2 feature requires 10.x feature to be set as well"); +++ return -EINVAL; +++ } ++ ++- return ar; +++ if (ar->wmi.op_version >= ATH10K_FW_WMI_OP_VERSION_MAX) { +++ ath10k_err(ar, "unsupported WMI OP version (max %d): %d\n", +++ ATH10K_FW_WMI_OP_VERSION_MAX, ar->wmi.op_version); +++ return -EINVAL; +++ } ++ ++-err_wq: ++- ath10k_mac_destroy(ar); ++- return NULL; ++-} ++-EXPORT_SYMBOL(ath10k_core_create); +++ /* Backwards compatibility for firmwares without +++ * ATH10K_FW_IE_WMI_OP_VERSION. +++ */ +++ if (ar->wmi.op_version == ATH10K_FW_WMI_OP_VERSION_UNSET) { +++ if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { +++ if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, +++ ar->fw_features)) +++ ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_2; +++ else +++ ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_1; +++ } else { +++ ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_MAIN; +++ } +++ } ++ ++-void ath10k_core_destroy(struct ath10k *ar) ++-{ ++- flush_workqueue(ar->workqueue); ++- destroy_workqueue(ar->workqueue); +++ switch (ar->wmi.op_version) { +++ case ATH10K_FW_WMI_OP_VERSION_MAIN: +++ ar->max_num_peers = TARGET_NUM_PEERS; +++ ar->max_num_stations = TARGET_NUM_STATIONS; +++ ar->max_num_vdevs = TARGET_NUM_VDEVS; +++ ar->htt.max_num_pending_tx = TARGET_NUM_MSDU_DESC; +++ break; +++ case ATH10K_FW_WMI_OP_VERSION_10_1: +++ case ATH10K_FW_WMI_OP_VERSION_10_2: +++ case ATH10K_FW_WMI_OP_VERSION_10_2_4: +++ ar->max_num_peers = TARGET_10X_NUM_PEERS; +++ ar->max_num_stations = TARGET_10X_NUM_STATIONS; +++ ar->max_num_vdevs = TARGET_10X_NUM_VDEVS; +++ ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC; +++ break; +++ case ATH10K_FW_WMI_OP_VERSION_TLV: +++ ar->max_num_peers = TARGET_TLV_NUM_PEERS; +++ ar->max_num_stations = TARGET_TLV_NUM_STATIONS; +++ ar->max_num_vdevs = TARGET_TLV_NUM_VDEVS; +++ ar->htt.max_num_pending_tx = TARGET_TLV_NUM_MSDU_DESC; +++ break; +++ case ATH10K_FW_WMI_OP_VERSION_UNSET: +++ case ATH10K_FW_WMI_OP_VERSION_MAX: +++ WARN_ON(1); +++ return -EINVAL; +++ } ++ ++- ath10k_mac_destroy(ar); +++ return 0; ++ } ++-EXPORT_SYMBOL(ath10k_core_destroy); ++ ++-int ath10k_core_start(struct ath10k *ar) +++int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) ++ { ++ int status; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ +++ clear_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags); +++ ++ ath10k_bmi_start(ar); ++ ++ if (ath10k_init_configure_target(ar)) { ++@@ -778,7 +997,11 @@ int ath10k_core_start(struct ath10k *ar) ++ goto err; ++ } ++ ++- status = ath10k_init_download_firmware(ar); +++ status = ath10k_download_cal_data(ar); +++ if (status) +++ goto err; +++ +++ status = ath10k_download_fw(ar, mode); ++ if (status) ++ goto err; ++ ++@@ -791,7 +1014,7 @@ int ath10k_core_start(struct ath10k *ar) ++ ++ status = ath10k_htc_init(ar); ++ if (status) { ++- ath10k_err("could not init HTC (%d)\n", status); +++ ath10k_err(ar, "could not init HTC (%d)\n", status); ++ goto err; ++ } ++ ++@@ -801,79 +1024,123 @@ int ath10k_core_start(struct ath10k *ar) ++ ++ status = ath10k_wmi_attach(ar); ++ if (status) { ++- ath10k_err("WMI attach failed: %d\n", status); +++ ath10k_err(ar, "WMI attach failed: %d\n", status); ++ goto err; ++ } ++ ++- status = ath10k_hif_start(ar); +++ status = ath10k_htt_init(ar); +++ if (status) { +++ ath10k_err(ar, "failed to init htt: %d\n", status); +++ goto err_wmi_detach; +++ } +++ +++ status = ath10k_htt_tx_alloc(&ar->htt); ++ if (status) { ++- ath10k_err("could not start HIF: %d\n", status); +++ ath10k_err(ar, "failed to alloc htt tx: %d\n", status); ++ goto err_wmi_detach; ++ } ++ +++ status = ath10k_htt_rx_alloc(&ar->htt); +++ if (status) { +++ ath10k_err(ar, "failed to alloc htt rx: %d\n", status); +++ goto err_htt_tx_detach; +++ } +++ +++ status = ath10k_hif_start(ar); +++ if (status) { +++ ath10k_err(ar, "could not start HIF: %d\n", status); +++ goto err_htt_rx_detach; +++ } +++ ++ status = ath10k_htc_wait_target(&ar->htc); ++ if (status) { ++- ath10k_err("failed to connect to HTC: %d\n", status); +++ ath10k_err(ar, "failed to connect to HTC: %d\n", status); ++ goto err_hif_stop; ++ } ++ ++- status = ath10k_htt_attach(ar); +++ if (mode == ATH10K_FIRMWARE_MODE_NORMAL) { +++ status = ath10k_htt_connect(&ar->htt); +++ if (status) { +++ ath10k_err(ar, "failed to connect htt (%d)\n", status); +++ goto err_hif_stop; +++ } +++ } +++ +++ status = ath10k_wmi_connect(ar); ++ if (status) { ++- ath10k_err("could not attach htt (%d)\n", status); +++ ath10k_err(ar, "could not connect wmi: %d\n", status); ++ goto err_hif_stop; ++ } ++ ++- status = ath10k_init_connect_htc(ar); ++- if (status) ++- goto err_htt_detach; +++ status = ath10k_htc_start(&ar->htc); +++ if (status) { +++ ath10k_err(ar, "failed to start htc: %d\n", status); +++ goto err_hif_stop; +++ } ++ ++- ath10k_dbg(ATH10K_DBG_BOOT, "firmware %s booted\n", +++ if (mode == ATH10K_FIRMWARE_MODE_NORMAL) { +++ status = ath10k_wmi_wait_for_service_ready(ar); +++ if (status <= 0) { +++ ath10k_warn(ar, "wmi service ready event not received"); +++ status = -ETIMEDOUT; +++ goto err_hif_stop; +++ } +++ } +++ +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "firmware %s booted\n", ++ ar->hw->wiphy->fw_version); ++ ++ status = ath10k_wmi_cmd_init(ar); ++ if (status) { ++- ath10k_err("could not send WMI init command (%d)\n", status); ++- goto err_disconnect_htc; +++ ath10k_err(ar, "could not send WMI init command (%d)\n", +++ status); +++ goto err_hif_stop; ++ } ++ ++ status = ath10k_wmi_wait_for_unified_ready(ar); ++ if (status <= 0) { ++- ath10k_err("wmi unified ready event not received\n"); +++ ath10k_err(ar, "wmi unified ready event not received\n"); ++ status = -ETIMEDOUT; ++- goto err_disconnect_htc; +++ goto err_hif_stop; ++ } ++ ++- status = ath10k_htt_attach_target(&ar->htt); ++- if (status) ++- goto err_disconnect_htc; +++ /* If firmware indicates Full Rx Reorder support it must be used in a +++ * slightly different manner. Let HTT code know. +++ */ +++ ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER, +++ ar->wmi.svc_map)); +++ +++ status = ath10k_htt_rx_ring_refill(ar); +++ if (status) { +++ ath10k_err(ar, "failed to refill htt rx ring: %d\n", status); +++ goto err_hif_stop; +++ } +++ +++ /* we don't care about HTT in UTF mode */ +++ if (mode == ATH10K_FIRMWARE_MODE_NORMAL) { +++ status = ath10k_htt_setup(&ar->htt); +++ if (status) { +++ ath10k_err(ar, "failed to setup htt: %d\n", status); +++ goto err_hif_stop; +++ } +++ } ++ ++ status = ath10k_debug_start(ar); ++ if (status) ++- goto err_disconnect_htc; ++- ++- ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1; ++- INIT_LIST_HEAD(&ar->arvifs); +++ goto err_hif_stop; ++ ++- if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) ++- ath10k_info("%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n", ++- ar->hw_params.name, ++- ar->target_version, ++- ar->chip_id, ++- ar->hw->wiphy->fw_version, ++- ar->fw_api, ++- ar->htt.target_version_major, ++- ar->htt.target_version_minor); +++ ar->free_vdev_map = (1LL << ar->max_num_vdevs) - 1; ++ ++- __set_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags); +++ INIT_LIST_HEAD(&ar->arvifs); ++ ++ return 0; ++ ++-err_disconnect_htc: ++- ath10k_htc_stop(&ar->htc); ++-err_htt_detach: ++- ath10k_htt_detach(&ar->htt); ++ err_hif_stop: ++ ath10k_hif_stop(ar); +++err_htt_rx_detach: +++ ath10k_htt_rx_free(&ar->htt); +++err_htt_tx_detach: +++ ath10k_htt_tx_free(&ar->htt); ++ err_wmi_detach: ++ ath10k_wmi_detach(ar); ++ err: ++@@ -889,14 +1156,14 @@ int ath10k_wait_for_suspend(struct ath10 ++ ++ ret = ath10k_wmi_pdev_suspend_target(ar, suspend_opt); ++ if (ret) { ++- ath10k_warn("could not suspend target (%d)\n", ret); +++ ath10k_warn(ar, "could not suspend target (%d)\n", ret); ++ return ret; ++ } ++ ++ ret = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ); ++ ++ if (ret == 0) { ++- ath10k_warn("suspend timed out - target pause event never came\n"); +++ ath10k_warn(ar, "suspend timed out - target pause event never came\n"); ++ return -ETIMEDOUT; ++ } ++ ++@@ -908,12 +1175,14 @@ void ath10k_core_stop(struct ath10k *ar) ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ /* try to suspend target */ ++- if (ar->state != ATH10K_STATE_RESTARTING) +++ if (ar->state != ATH10K_STATE_RESTARTING && +++ ar->state != ATH10K_STATE_UTF) ++ ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR); ++ ++ ath10k_debug_stop(ar); ++- ath10k_htc_stop(&ar->htc); ++- ath10k_htt_detach(&ar->htt); +++ ath10k_hif_stop(ar); +++ ath10k_htt_tx_free(&ar->htt); +++ ath10k_htt_rx_free(&ar->htt); ++ ath10k_wmi_detach(ar); ++ } ++ EXPORT_SYMBOL(ath10k_core_stop); ++@@ -929,16 +1198,15 @@ static int ath10k_core_probe_fw(struct a ++ ++ ret = ath10k_hif_power_up(ar); ++ if (ret) { ++- ath10k_err("could not start pci hif (%d)\n", ret); +++ ath10k_err(ar, "could not start pci hif (%d)\n", ret); ++ return ret; ++ } ++ ++ memset(&target_info, 0, sizeof(target_info)); ++ ret = ath10k_bmi_get_target_info(ar, &target_info); ++ if (ret) { ++- ath10k_err("could not get target info (%d)\n", ret); ++- ath10k_hif_power_down(ar); ++- return ret; +++ ath10k_err(ar, "could not get target info (%d)\n", ret); +++ goto err_power_down; ++ } ++ ++ ar->target_version = target_info.version; ++@@ -946,118 +1214,233 @@ static int ath10k_core_probe_fw(struct a ++ ++ ret = ath10k_init_hw_params(ar); ++ if (ret) { ++- ath10k_err("could not get hw params (%d)\n", ret); ++- ath10k_hif_power_down(ar); ++- return ret; +++ ath10k_err(ar, "could not get hw params (%d)\n", ret); +++ goto err_power_down; ++ } ++ ++ ret = ath10k_core_fetch_firmware_files(ar); ++ if (ret) { ++- ath10k_err("could not fetch firmware files (%d)\n", ret); ++- ath10k_hif_power_down(ar); ++- return ret; +++ ath10k_err(ar, "could not fetch firmware files (%d)\n", ret); +++ goto err_power_down; +++ } +++ +++ ret = ath10k_core_init_firmware_features(ar); +++ if (ret) { +++ ath10k_err(ar, "fatal problem with firmware features: %d\n", +++ ret); +++ goto err_free_firmware_files; ++ } ++ ++ mutex_lock(&ar->conf_mutex); ++ ++- ret = ath10k_core_start(ar); +++ ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL); ++ if (ret) { ++- ath10k_err("could not init core (%d)\n", ret); ++- ath10k_core_free_firmware_files(ar); ++- ath10k_hif_power_down(ar); ++- mutex_unlock(&ar->conf_mutex); ++- return ret; +++ ath10k_err(ar, "could not init core (%d)\n", ret); +++ goto err_unlock; ++ } ++ +++ ath10k_print_driver_info(ar); ++ ath10k_core_stop(ar); ++ ++ mutex_unlock(&ar->conf_mutex); ++ ++ ath10k_hif_power_down(ar); ++ return 0; ++-} ++- ++-static int ath10k_core_check_chip_id(struct ath10k *ar) ++-{ ++- u32 hw_revision = MS(ar->chip_id, SOC_CHIP_ID_REV); ++- ++- ath10k_dbg(ATH10K_DBG_BOOT, "boot chip_id 0x%08x hw_revision 0x%x\n", ++- ar->chip_id, hw_revision); ++ ++- /* Check that we are not using hw1.0 (some of them have same pci id ++- * as hw2.0) before doing anything else as ath10k crashes horribly ++- * due to missing hw1.0 workarounds. */ ++- switch (hw_revision) { ++- case QCA988X_HW_1_0_CHIP_ID_REV: ++- ath10k_err("ERROR: qca988x hw1.0 is not supported\n"); ++- return -EOPNOTSUPP; +++err_unlock: +++ mutex_unlock(&ar->conf_mutex); ++ ++- case QCA988X_HW_2_0_CHIP_ID_REV: ++- /* known hardware revision, continue normally */ ++- return 0; +++err_free_firmware_files: +++ ath10k_core_free_firmware_files(ar); ++ ++- default: ++- ath10k_warn("Warning: hardware revision unknown (0x%x), expect problems\n", ++- ar->chip_id); ++- return 0; ++- } +++err_power_down: +++ ath10k_hif_power_down(ar); ++ ++- return 0; +++ return ret; ++ } ++ ++-int ath10k_core_register(struct ath10k *ar, u32 chip_id) +++static void ath10k_core_register_work(struct work_struct *work) ++ { +++ struct ath10k *ar = container_of(work, struct ath10k, register_work); ++ int status; ++ ++- ar->chip_id = chip_id; ++- ++- status = ath10k_core_check_chip_id(ar); ++- if (status) { ++- ath10k_err("Unsupported chip id 0x%08x\n", ar->chip_id); ++- return status; ++- } ++- ++ status = ath10k_core_probe_fw(ar); ++ if (status) { ++- ath10k_err("could not probe fw (%d)\n", status); ++- return status; +++ ath10k_err(ar, "could not probe fw (%d)\n", status); +++ goto err; ++ } ++ ++ status = ath10k_mac_register(ar); ++ if (status) { ++- ath10k_err("could not register to mac80211 (%d)\n", status); +++ ath10k_err(ar, "could not register to mac80211 (%d)\n", status); ++ goto err_release_fw; ++ } ++ ++- status = ath10k_debug_create(ar); +++ status = ath10k_debug_register(ar); ++ if (status) { ++- ath10k_err("unable to initialize debugfs\n"); +++ ath10k_err(ar, "unable to initialize debugfs\n"); ++ goto err_unregister_mac; ++ } ++ ++- return 0; +++ status = ath10k_spectral_create(ar); +++ if (status) { +++ ath10k_err(ar, "failed to initialize spectral\n"); +++ goto err_debug_destroy; +++ } ++ +++ status = ath10k_thermal_register(ar); +++ if (status) { +++ ath10k_err(ar, "could not register thermal device: %d\n", +++ status); +++ goto err_spectral_destroy; +++ } +++ +++ set_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags); +++ return; +++ +++err_spectral_destroy: +++ ath10k_spectral_destroy(ar); +++err_debug_destroy: +++ ath10k_debug_destroy(ar); ++ err_unregister_mac: ++ ath10k_mac_unregister(ar); ++ err_release_fw: ++ ath10k_core_free_firmware_files(ar); ++- return status; +++err: +++ /* TODO: It's probably a good idea to release device from the driver +++ * but calling device_release_driver() here will cause a deadlock. +++ */ +++ return; +++} +++ +++int ath10k_core_register(struct ath10k *ar, u32 chip_id) +++{ +++ ar->chip_id = chip_id; +++ queue_work(ar->workqueue, &ar->register_work); +++ +++ return 0; ++ } ++ EXPORT_SYMBOL(ath10k_core_register); ++ ++ void ath10k_core_unregister(struct ath10k *ar) ++ { +++ cancel_work_sync(&ar->register_work); +++ +++ if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags)) +++ return; +++ +++ ath10k_thermal_unregister(ar); +++ /* Stop spectral before unregistering from mac80211 to remove the +++ * relayfs debugfs file cleanly. Otherwise the parent debugfs tree +++ * would be already be free'd recursively, leading to a double free. +++ */ +++ ath10k_spectral_destroy(ar); +++ ++ /* We must unregister from mac80211 before we stop HTC and HIF. ++ * Otherwise we will fail to submit commands to FW and mac80211 will be ++ * unhappy about callback failures. */ ++ ath10k_mac_unregister(ar); ++ +++ ath10k_testmode_destroy(ar); +++ ++ ath10k_core_free_firmware_files(ar); ++ ++- ath10k_debug_destroy(ar); +++ ath10k_debug_unregister(ar); ++ } ++ EXPORT_SYMBOL(ath10k_core_unregister); ++ +++struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, +++ enum ath10k_bus bus, +++ enum ath10k_hw_rev hw_rev, +++ const struct ath10k_hif_ops *hif_ops) +++{ +++ struct ath10k *ar; +++ int ret; +++ +++ ar = ath10k_mac_create(priv_size); +++ if (!ar) +++ return NULL; +++ +++ ar->ath_common.priv = ar; +++ ar->ath_common.hw = ar->hw; +++ ar->dev = dev; +++ ar->hw_rev = hw_rev; +++ ar->hif.ops = hif_ops; +++ ar->hif.bus = bus; +++ +++ switch (hw_rev) { +++ case ATH10K_HW_QCA988X: +++ ar->regs = &qca988x_regs; +++ break; +++ case ATH10K_HW_QCA6174: +++ ar->regs = &qca6174_regs; +++ break; +++ default: +++ ath10k_err(ar, "unsupported core hardware revision %d\n", +++ hw_rev); +++ ret = -ENOTSUPP; +++ goto err_free_mac; +++ } +++ +++ init_completion(&ar->scan.started); +++ init_completion(&ar->scan.completed); +++ init_completion(&ar->scan.on_channel); +++ init_completion(&ar->target_suspend); +++ +++ init_completion(&ar->install_key_done); +++ init_completion(&ar->vdev_setup_done); +++ init_completion(&ar->thermal.wmi_sync); +++ +++ INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work); +++ +++ ar->workqueue = create_singlethread_workqueue("ath10k_wq"); +++ if (!ar->workqueue) +++ goto err_free_mac; +++ +++ mutex_init(&ar->conf_mutex); +++ spin_lock_init(&ar->data_lock); +++ +++ INIT_LIST_HEAD(&ar->peers); +++ init_waitqueue_head(&ar->peer_mapping_wq); +++ init_waitqueue_head(&ar->htt.empty_tx_wq); +++ init_waitqueue_head(&ar->wmi.tx_credits_wq); +++ +++ init_completion(&ar->offchan_tx_completed); +++ INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work); +++ skb_queue_head_init(&ar->offchan_tx_queue); +++ +++ INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work); +++ skb_queue_head_init(&ar->wmi_mgmt_tx_queue); +++ +++ INIT_WORK(&ar->register_work, ath10k_core_register_work); +++ INIT_WORK(&ar->restart_work, ath10k_core_restart); +++ +++ ret = ath10k_debug_create(ar); +++ if (ret) +++ goto err_free_wq; +++ +++ return ar; +++ +++err_free_wq: +++ destroy_workqueue(ar->workqueue); +++ +++err_free_mac: +++ ath10k_mac_destroy(ar); +++ +++ return NULL; +++} +++EXPORT_SYMBOL(ath10k_core_create); +++ +++void ath10k_core_destroy(struct ath10k *ar) +++{ +++ flush_workqueue(ar->workqueue); +++ destroy_workqueue(ar->workqueue); +++ +++ ath10k_debug_destroy(ar); +++ ath10k_mac_destroy(ar); +++} +++EXPORT_SYMBOL(ath10k_core_destroy); +++ ++ MODULE_AUTHOR("Qualcomm Atheros"); ++ MODULE_DESCRIPTION("Core module for QCA988X PCIe devices."); ++ MODULE_LICENSE("Dual BSD/GPL"); ++--- a/drivers/net/wireless/ath/ath10k/core.h +++++ b/drivers/net/wireless/ath/ath10k/core.h ++@@ -22,6 +22,8 @@ ++ #include ++ #include ++ #include +++#include +++#include ++ ++ #include "htt.h" ++ #include "htc.h" ++@@ -31,6 +33,8 @@ ++ #include "../ath.h" ++ #include "../regd.h" ++ #include "../dfs_pattern_detector.h" +++#include "spectral.h" +++#include "thermal.h" ++ ++ #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB) ++ #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) ++@@ -60,12 +64,28 @@ ++ ++ struct ath10k; ++ +++enum ath10k_bus { +++ ATH10K_BUS_PCI, +++}; +++ +++static inline const char *ath10k_bus_str(enum ath10k_bus bus) +++{ +++ switch (bus) { +++ case ATH10K_BUS_PCI: +++ return "pci"; +++ } +++ +++ return "unknown"; +++} +++ ++ struct ath10k_skb_cb { ++ dma_addr_t paddr; +++ u8 eid; ++ u8 vdev_id; ++ ++ struct { ++ u8 tid; +++ u16 freq; ++ bool is_offchan; ++ struct ath10k_htt_txbuf *txbuf; ++ u32 txbuf_paddr; ++@@ -77,6 +97,11 @@ struct ath10k_skb_cb { ++ } bcn; ++ } __packed; ++ +++struct ath10k_skb_rxcb { +++ dma_addr_t paddr; +++ struct hlist_node hlist; +++}; +++ ++ static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb) ++ { ++ BUILD_BUG_ON(sizeof(struct ath10k_skb_cb) > ++@@ -84,6 +109,15 @@ static inline struct ath10k_skb_cb *ATH1 ++ return (struct ath10k_skb_cb *)&IEEE80211_SKB_CB(skb)->driver_data; ++ } ++ +++static inline struct ath10k_skb_rxcb *ATH10K_SKB_RXCB(struct sk_buff *skb) +++{ +++ BUILD_BUG_ON(sizeof(struct ath10k_skb_rxcb) > sizeof(skb->cb)); +++ return (struct ath10k_skb_rxcb *)skb->cb; +++} +++ +++#define ATH10K_RXCB_SKB(rxcb) \ +++ container_of((void *)rxcb, struct sk_buff, cb) +++ ++ static inline u32 host_interest_item_address(u32 item_offset) ++ { ++ return QCA988X_HOST_INTEREST_ADDRESS + item_offset; ++@@ -93,8 +127,6 @@ struct ath10k_bmi { ++ bool done_sent; ++ }; ++ ++-#define ATH10K_MAX_MEM_REQS 16 ++- ++ struct ath10k_mem_chunk { ++ void *vaddr; ++ dma_addr_t paddr; ++@@ -103,26 +135,52 @@ struct ath10k_mem_chunk { ++ }; ++ ++ struct ath10k_wmi { +++ enum ath10k_fw_wmi_op_version op_version; ++ enum ath10k_htc_ep_id eid; ++ struct completion service_ready; ++ struct completion unified_ready; ++ wait_queue_head_t tx_credits_wq; +++ DECLARE_BITMAP(svc_map, WMI_SERVICE_MAX); ++ struct wmi_cmd_map *cmd; ++ struct wmi_vdev_param_map *vdev_param; ++ struct wmi_pdev_param_map *pdev_param; +++ const struct wmi_ops *ops; ++ ++ u32 num_mem_chunks; ++- struct ath10k_mem_chunk mem_chunks[ATH10K_MAX_MEM_REQS]; +++ struct ath10k_mem_chunk mem_chunks[WMI_MAX_MEM_REQS]; ++ }; ++ ++-struct ath10k_peer_stat { +++struct ath10k_fw_stats_peer { +++ struct list_head list; +++ ++ u8 peer_macaddr[ETH_ALEN]; ++ u32 peer_rssi; ++ u32 peer_tx_rate; ++ u32 peer_rx_rate; /* 10x only */ ++ }; ++ ++-struct ath10k_target_stats { +++struct ath10k_fw_stats_vdev { +++ struct list_head list; +++ +++ u32 vdev_id; +++ u32 beacon_snr; +++ u32 data_snr; +++ u32 num_tx_frames[4]; +++ u32 num_rx_frames; +++ u32 num_tx_frames_retries[4]; +++ u32 num_tx_frames_failures[4]; +++ u32 num_rts_fail; +++ u32 num_rts_success; +++ u32 num_rx_err; +++ u32 num_rx_discard; +++ u32 num_tx_not_acked; +++ u32 tx_rate_history[10]; +++ u32 beacon_rssi_history[10]; +++}; +++ +++struct ath10k_fw_stats_pdev { +++ struct list_head list; +++ ++ /* PDEV stats */ ++ s32 ch_noise_floor; ++ u32 tx_frame_count; ++@@ -177,15 +235,12 @@ struct ath10k_target_stats { ++ s32 phy_errs; ++ s32 phy_err_drop; ++ s32 mpdu_errs; +++}; ++ ++- /* VDEV STATS */ ++- ++- /* PEER STATS */ ++- u8 peers; ++- struct ath10k_peer_stat peer_stat[TARGET_NUM_PEERS]; ++- ++- /* TODO: Beacon filter stats */ ++- +++struct ath10k_fw_stats { +++ struct list_head pdevs; +++ struct list_head vdevs; +++ struct list_head peers; ++ }; ++ ++ struct ath10k_dfs_stats { ++@@ -203,6 +258,8 @@ struct ath10k_peer { ++ int vdev_id; ++ u8 addr[ETH_ALEN]; ++ DECLARE_BITMAP(peer_ids, ATH10K_MAX_NUM_PEER_IDS); +++ +++ /* protected by ar->data_lock */ ++ struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1]; ++ }; ++ ++@@ -216,10 +273,21 @@ struct ath10k_sta { ++ u32 smps; ++ ++ struct work_struct update_wk; +++ +++#ifdef CPTCFG_MAC80211_DEBUGFS +++ /* protected by conf_mutex */ +++ bool aggr_mode; +++#endif ++ }; ++ ++ #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ) ++ +++enum ath10k_beacon_state { +++ ATH10K_BEACON_SCHEDULED = 0, +++ ATH10K_BEACON_SENDING, +++ ATH10K_BEACON_SENT, +++}; +++ ++ struct ath10k_vif { ++ struct list_head list; ++ ++@@ -230,20 +298,22 @@ struct ath10k_vif { ++ u32 dtim_period; ++ struct sk_buff *beacon; ++ /* protected by data_lock */ ++- bool beacon_sent; +++ enum ath10k_beacon_state beacon_state; +++ void *beacon_buf; +++ dma_addr_t beacon_paddr; ++ ++ struct ath10k *ar; ++ struct ieee80211_vif *vif; ++ ++ bool is_started; ++ bool is_up; +++ bool spectral_enabled; +++ bool ps; ++ u32 aid; ++ u8 bssid[ETH_ALEN]; ++ ++- struct work_struct wep_key_work; ++ struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1]; ++- u8 def_wep_key_idx; ++- u8 def_wep_key_newidx; +++ s8 def_wep_key_idx; ++ ++ u16 tx_seq_no; ++ ++@@ -269,6 +339,8 @@ struct ath10k_vif { ++ u8 force_sgi; ++ bool use_cts_prot; ++ int num_legacy_stations; +++ int txpower; +++ struct wmi_wmm_params_all_arg wmm_params; ++ }; ++ ++ struct ath10k_vif_iter { ++@@ -276,20 +348,38 @@ struct ath10k_vif_iter { ++ struct ath10k_vif *arvif; ++ }; ++ +++/* used for crash-dump storage, protected by data-lock */ +++struct ath10k_fw_crash_data { +++ bool crashed_since_read; +++ +++ uuid_le uuid; +++ struct timespec timestamp; +++ __le32 registers[REG_DUMP_COUNT_QCA988X]; +++}; +++ ++ struct ath10k_debug { ++ struct dentry *debugfs_phy; ++ ++- struct ath10k_target_stats target_stats; ++- u32 wmi_service_bitmap[WMI_SERVICE_BM_SIZE]; ++- ++- struct completion event_stats_compl; +++ struct ath10k_fw_stats fw_stats; +++ struct completion fw_stats_complete; +++ bool fw_stats_done; ++ ++ unsigned long htt_stats_mask; ++ struct delayed_work htt_stats_dwork; ++ struct ath10k_dfs_stats dfs_stats; ++ struct ath_dfs_pool_stats dfs_pool_stats; ++ +++ /* protected by conf_mutex */ ++ u32 fw_dbglog_mask; +++ u32 fw_dbglog_level; +++ u32 pktlog_filter; +++ u32 reg_addr; +++ u32 nf_cal_period; +++ +++ u8 htt_max_amsdu; +++ u8 htt_max_ampdu; +++ +++ struct ath10k_fw_crash_data *fw_crash_data; ++ }; ++ ++ enum ath10k_state { ++@@ -312,13 +402,24 @@ enum ath10k_state { ++ * prevents completion timeouts and makes the driver more responsive to ++ * userspace commands. This is also prevents recursive recovery. */ ++ ATH10K_STATE_WEDGED, +++ +++ /* factory tests */ +++ ATH10K_STATE_UTF, +++}; +++ +++enum ath10k_firmware_mode { +++ /* the default mode, standard 802.11 functionality */ +++ ATH10K_FIRMWARE_MODE_NORMAL, +++ +++ /* factory tests etc */ +++ ATH10K_FIRMWARE_MODE_UTF, ++ }; ++ ++ enum ath10k_fw_features { ++ /* wmi_mgmt_rx_hdr contains extra RSSI information */ ++ ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX = 0, ++ ++- /* firmware from 10X branch */ +++ /* Firmware from 10X branch. Deprecated, don't use in new code. */ ++ ATH10K_FW_FEATURE_WMI_10X = 1, ++ ++ /* firmware support tx frame management over WMI, otherwise it's HTT */ ++@@ -327,6 +428,18 @@ enum ath10k_fw_features { ++ /* Firmware does not support P2P */ ++ ATH10K_FW_FEATURE_NO_P2P = 3, ++ +++ /* Firmware 10.2 feature bit. The ATH10K_FW_FEATURE_WMI_10X feature +++ * bit is required to be set as well. Deprecated, don't use in new +++ * code. +++ */ +++ ATH10K_FW_FEATURE_WMI_10_2 = 4, +++ +++ /* Some firmware revisions lack proper multi-interface client powersave +++ * implementation. Enabling PS could result in connection drops, +++ * traffic stalls, etc. +++ */ +++ ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT = 5, +++ ++ /* keep last */ ++ ATH10K_FW_FEATURE_COUNT, ++ }; ++@@ -334,15 +447,64 @@ enum ath10k_fw_features { ++ enum ath10k_dev_flags { ++ /* Indicates that ath10k device is during CAC phase of DFS */ ++ ATH10K_CAC_RUNNING, ++- ATH10K_FLAG_FIRST_BOOT_DONE, +++ ATH10K_FLAG_CORE_REGISTERED, +++ +++ /* Device has crashed and needs to restart. This indicates any pending +++ * waiters should immediately cancel instead of waiting for a time out. +++ */ +++ ATH10K_FLAG_CRASH_FLUSH, +++}; +++ +++enum ath10k_cal_mode { +++ ATH10K_CAL_MODE_FILE, +++ ATH10K_CAL_MODE_OTP, +++ ATH10K_CAL_MODE_DT, +++}; +++ +++static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode) +++{ +++ switch (mode) { +++ case ATH10K_CAL_MODE_FILE: +++ return "file"; +++ case ATH10K_CAL_MODE_OTP: +++ return "otp"; +++ case ATH10K_CAL_MODE_DT: +++ return "dt"; +++ } +++ +++ return "unknown"; +++} +++ +++enum ath10k_scan_state { +++ ATH10K_SCAN_IDLE, +++ ATH10K_SCAN_STARTING, +++ ATH10K_SCAN_RUNNING, +++ ATH10K_SCAN_ABORTING, ++ }; ++ +++static inline const char *ath10k_scan_state_str(enum ath10k_scan_state state) +++{ +++ switch (state) { +++ case ATH10K_SCAN_IDLE: +++ return "idle"; +++ case ATH10K_SCAN_STARTING: +++ return "starting"; +++ case ATH10K_SCAN_RUNNING: +++ return "running"; +++ case ATH10K_SCAN_ABORTING: +++ return "aborting"; +++ } +++ +++ return "unknown"; +++} +++ ++ struct ath10k { ++ struct ath_common ath_common; ++ struct ieee80211_hw *hw; ++ struct device *dev; ++ u8 mac_addr[ETH_ALEN]; ++ +++ enum ath10k_hw_rev hw_rev; ++ u32 chip_id; ++ u32 target_version; ++ u8 fw_version_major; ++@@ -358,18 +520,16 @@ struct ath10k { ++ ++ DECLARE_BITMAP(fw_features, ATH10K_FW_FEATURE_COUNT); ++ ++- struct targetdef *targetdef; ++- struct hostdef *hostdef; ++- ++ bool p2p; ++ ++ struct { ++- void *priv; +++ enum ath10k_bus bus; ++ const struct ath10k_hif_ops *ops; ++ } hif; ++ ++ struct completion target_suspend; ++ +++ const struct ath10k_hw_regs *regs; ++ struct ath10k_bmi bmi; ++ struct ath10k_wmi wmi; ++ struct ath10k_htc htc; ++@@ -379,12 +539,15 @@ struct ath10k { ++ u32 id; ++ const char *name; ++ u32 patch_load_addr; +++ int uart_pin; ++ ++ struct ath10k_hw_params_fw { ++ const char *dir; ++ const char *fw; ++ const char *otp; ++ const char *board; +++ size_t board_size; +++ size_t board_ext_size; ++ } fw; ++ } hw_params; ++ ++@@ -400,16 +563,18 @@ struct ath10k { ++ const void *firmware_data; ++ size_t firmware_len; ++ +++ const struct firmware *cal_file; +++ ++ int fw_api; +++ enum ath10k_cal_mode cal_mode; ++ ++ struct { ++ struct completion started; ++ struct completion completed; ++ struct completion on_channel; ++- struct timer_list timeout; +++ struct delayed_work timeout; +++ enum ath10k_scan_state state; ++ bool is_roc; ++- bool in_progress; ++- bool aborting; ++ int vdev_id; ++ int roc_freq; ++ } scan; ++@@ -427,8 +592,7 @@ struct ath10k { ++ /* current operating channel definition */ ++ struct cfg80211_chan_def chandef; ++ ++- int free_vdev_map; ++- bool promisc; +++ unsigned long long free_vdev_map; ++ bool monitor; ++ int monitor_vdev_id; ++ bool monitor_started; ++@@ -440,7 +604,12 @@ struct ath10k { ++ bool radar_enabled; ++ int num_started_vdevs; ++ ++- struct wmi_pdev_set_wmm_params_arg wmm_params; +++ /* Protected by conf-mutex */ +++ u8 supp_tx_chainmask; +++ u8 supp_rx_chainmask; +++ u8 cfg_tx_chainmask; +++ u8 cfg_rx_chainmask; +++ ++ struct completion install_key_done; ++ ++ struct completion vdev_setup_done; ++@@ -457,8 +626,13 @@ struct ath10k { ++ struct list_head peers; ++ wait_queue_head_t peer_mapping_wq; ++ ++- /* number of created peers; protected by data_lock */ +++ /* protected by conf_mutex */ ++ int num_peers; +++ int num_stations; +++ +++ int max_num_peers; +++ int max_num_stations; +++ int max_num_vdevs; ++ ++ struct work_struct offchan_tx_work; ++ struct sk_buff_head offchan_tx_queue; ++@@ -470,6 +644,7 @@ struct ath10k { ++ ++ enum ath10k_state state; ++ +++ struct work_struct register_work; ++ struct work_struct restart_work; ++ ++ /* cycle count is reported twice for each visited channel during scan. ++@@ -483,13 +658,46 @@ struct ath10k { ++ #ifdef CPTCFG_ATH10K_DEBUGFS ++ struct ath10k_debug debug; ++ #endif +++ +++ struct { +++ /* relay(fs) channel for spectral scan */ +++ struct rchan *rfs_chan_spec_scan; +++ +++ /* spectral_mode and spec_config are protected by conf_mutex */ +++ enum ath10k_spectral_mode mode; +++ struct ath10k_spec_scan config; +++ } spectral; +++ +++ struct { +++ /* protected by conf_mutex */ +++ const struct firmware *utf; +++ DECLARE_BITMAP(orig_fw_features, ATH10K_FW_FEATURE_COUNT); +++ enum ath10k_fw_wmi_op_version orig_wmi_op_version; +++ +++ /* protected by data_lock */ +++ bool utf_monitor; +++ } testmode; +++ +++ struct { +++ /* protected by data_lock */ +++ u32 fw_crash_counter; +++ u32 fw_warm_reset_counter; +++ u32 fw_cold_reset_counter; +++ } stats; +++ +++ struct ath10k_thermal thermal; +++ +++ /* must be last */ +++ u8 drv_priv[0] __aligned(sizeof(void *)); ++ }; ++ ++-struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, +++struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, +++ enum ath10k_bus bus, +++ enum ath10k_hw_rev hw_rev, ++ const struct ath10k_hif_ops *hif_ops); ++ void ath10k_core_destroy(struct ath10k *ar); ++ ++-int ath10k_core_start(struct ath10k *ar); +++int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode); ++ int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt); ++ void ath10k_core_stop(struct ath10k *ar); ++ int ath10k_core_register(struct ath10k *ar, u32 chip_id); ++--- a/drivers/net/wireless/ath/ath10k/debug.c +++++ b/drivers/net/wireless/ath/ath10k/debug.c ++@@ -17,107 +17,176 @@ ++ ++ #include ++ #include +++#include +++#include ++ ++ #include "core.h" ++ #include "debug.h" +++#include "hif.h" +++#include "wmi-ops.h" ++ ++ /* ms */ ++ #define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000 ++ ++-static int ath10k_printk(const char *level, const char *fmt, ...) ++-{ ++- struct va_format vaf; ++- va_list args; ++- int rtn; +++#define ATH10K_FW_CRASH_DUMP_VERSION 1 ++ ++- va_start(args, fmt); +++/** +++ * enum ath10k_fw_crash_dump_type - types of data in the dump file +++ * @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format +++ */ +++enum ath10k_fw_crash_dump_type { +++ ATH10K_FW_CRASH_DUMP_REGISTERS = 0, ++ ++- vaf.fmt = fmt; ++- vaf.va = &args; +++ ATH10K_FW_CRASH_DUMP_MAX, +++}; ++ ++- rtn = printk("%sath10k: %pV", level, &vaf); +++struct ath10k_tlv_dump_data { +++ /* see ath10k_fw_crash_dump_type above */ +++ __le32 type; ++ ++- va_end(args); +++ /* in bytes */ +++ __le32 tlv_len; ++ ++- return rtn; ++-} +++ /* pad to 32-bit boundaries as needed */ +++ u8 tlv_data[]; +++} __packed; +++ +++struct ath10k_dump_file_data { +++ /* dump file information */ +++ +++ /* "ATH10K-FW-DUMP" */ +++ char df_magic[16]; +++ +++ __le32 len; +++ +++ /* file dump version */ +++ __le32 version; +++ +++ /* some info we can get from ath10k struct that might help */ +++ +++ u8 uuid[16]; +++ +++ __le32 chip_id; +++ +++ /* 0 for now, in place for later hardware */ +++ __le32 bus_type; +++ +++ __le32 target_version; +++ __le32 fw_version_major; +++ __le32 fw_version_minor; +++ __le32 fw_version_release; +++ __le32 fw_version_build; +++ __le32 phy_capability; +++ __le32 hw_min_tx_power; +++ __le32 hw_max_tx_power; +++ __le32 ht_cap_info; +++ __le32 vht_cap_info; +++ __le32 num_rf_chains; +++ +++ /* firmware version string */ +++ char fw_ver[ETHTOOL_FWVERS_LEN]; +++ +++ /* Kernel related information */ +++ +++ /* time-of-day stamp */ +++ __le64 tv_sec; +++ +++ /* time-of-day stamp, nano-seconds */ +++ __le64 tv_nsec; +++ +++ /* LINUX_VERSION_CODE */ +++ __le32 kernel_ver_code; +++ +++ /* VERMAGIC_STRING */ +++ char kernel_ver[64]; ++ ++-int ath10k_info(const char *fmt, ...) +++ /* room for growth w/out changing binary format */ +++ u8 unused[128]; +++ +++ /* struct ath10k_tlv_dump_data + more */ +++ u8 data[0]; +++} __packed; +++ +++void ath10k_info(struct ath10k *ar, const char *fmt, ...) ++ { ++ struct va_format vaf = { ++ .fmt = fmt, ++ }; ++ va_list args; ++- int ret; ++ ++ va_start(args, fmt); ++ vaf.va = &args; ++- ret = ath10k_printk(KERN_INFO, "%pV", &vaf); ++- trace_ath10k_log_info(&vaf); +++ dev_info(ar->dev, "%pV", &vaf); +++ trace_ath10k_log_info(ar, &vaf); ++ va_end(args); ++- ++- return ret; ++ } ++ EXPORT_SYMBOL(ath10k_info); ++ ++-int ath10k_err(const char *fmt, ...) +++void ath10k_print_driver_info(struct ath10k *ar) +++{ +++ ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d cal %s max_sta %d\n", +++ ar->hw_params.name, +++ ar->target_version, +++ ar->chip_id, +++ ar->hw->wiphy->fw_version, +++ ar->fw_api, +++ ar->htt.target_version_major, +++ ar->htt.target_version_minor, +++ ar->wmi.op_version, +++ ath10k_cal_mode_str(ar->cal_mode), +++ ar->max_num_stations); +++ ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n", +++ config_enabled(CPTCFG_ATH10K_DEBUG), +++ config_enabled(CPTCFG_ATH10K_DEBUGFS), +++ config_enabled(CPTCFG_ATH10K_TRACING), +++ config_enabled(CPTCFG_ATH10K_DFS_CERTIFIED), +++ config_enabled(CPTCFG_NL80211_TESTMODE)); +++} +++EXPORT_SYMBOL(ath10k_print_driver_info); +++ +++void ath10k_err(struct ath10k *ar, const char *fmt, ...) ++ { ++ struct va_format vaf = { ++ .fmt = fmt, ++ }; ++ va_list args; ++- int ret; ++ ++ va_start(args, fmt); ++ vaf.va = &args; ++- ret = ath10k_printk(KERN_ERR, "%pV", &vaf); ++- trace_ath10k_log_err(&vaf); +++ dev_err(ar->dev, "%pV", &vaf); +++ trace_ath10k_log_err(ar, &vaf); ++ va_end(args); ++- ++- return ret; ++ } ++ EXPORT_SYMBOL(ath10k_err); ++ ++-int ath10k_warn(const char *fmt, ...) +++void ath10k_warn(struct ath10k *ar, const char *fmt, ...) ++ { ++ struct va_format vaf = { ++ .fmt = fmt, ++ }; ++ va_list args; ++- int ret = 0; ++ ++ va_start(args, fmt); ++ vaf.va = &args; ++- ++- if (net_ratelimit()) ++- ret = ath10k_printk(KERN_WARNING, "%pV", &vaf); ++- ++- trace_ath10k_log_warn(&vaf); +++ dev_warn_ratelimited(ar->dev, "%pV", &vaf); +++ trace_ath10k_log_warn(ar, &vaf); ++ ++ va_end(args); ++- ++- return ret; ++ } ++ EXPORT_SYMBOL(ath10k_warn); ++ ++ #ifdef CPTCFG_ATH10K_DEBUGFS ++ ++-void ath10k_debug_read_service_map(struct ath10k *ar, ++- void *service_map, ++- size_t map_size) ++-{ ++- memcpy(ar->debug.wmi_service_bitmap, service_map, map_size); ++-} ++- ++ static ssize_t ath10k_read_wmi_services(struct file *file, ++ char __user *user_buf, ++ size_t count, loff_t *ppos) ++ { ++ struct ath10k *ar = file->private_data; ++ char *buf; ++- unsigned int len = 0, buf_len = 1500; ++- const char *status; +++ unsigned int len = 0, buf_len = 4096; +++ const char *name; ++ ssize_t ret_cnt; +++ bool enabled; ++ int i; ++ ++ buf = kzalloc(buf_len, GFP_KERNEL); ++@@ -129,16 +198,25 @@ static ssize_t ath10k_read_wmi_services( ++ if (len > buf_len) ++ len = buf_len; ++ ++- for (i = 0; i < WMI_SERVICE_LAST; i++) { ++- if (WMI_SERVICE_IS_ENABLED(ar->debug.wmi_service_bitmap, i)) ++- status = "enabled"; ++- else ++- status = "disabled"; +++ spin_lock_bh(&ar->data_lock); +++ for (i = 0; i < WMI_SERVICE_MAX; i++) { +++ enabled = test_bit(i, ar->wmi.svc_map); +++ name = wmi_service_name(i); +++ +++ if (!name) { +++ if (enabled) +++ len += scnprintf(buf + len, buf_len - len, +++ "%-40s %s (bit %d)\n", +++ "unknown", "enabled", i); +++ +++ continue; +++ } ++ ++ len += scnprintf(buf + len, buf_len - len, ++- "0x%02x - %20s - %s\n", ++- i, wmi_service_name(i), status); +++ "%-40s %s\n", +++ name, enabled ? "enabled" : "-"); ++ } +++ spin_unlock_bh(&ar->data_lock); ++ ++ ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ ++@@ -155,169 +233,221 @@ static const struct file_operations fops ++ .llseek = default_llseek, ++ }; ++ ++-void ath10k_debug_read_target_stats(struct ath10k *ar, ++- struct wmi_stats_event *ev) +++static void ath10k_debug_fw_stats_pdevs_free(struct list_head *head) ++ { ++- u8 *tmp = ev->data; ++- struct ath10k_target_stats *stats; ++- int num_pdev_stats, num_vdev_stats, num_peer_stats; ++- struct wmi_pdev_stats_10x *ps; ++- int i; +++ struct ath10k_fw_stats_pdev *i, *tmp; ++ +++ list_for_each_entry_safe(i, tmp, head, list) { +++ list_del(&i->list); +++ kfree(i); +++ } +++} +++ +++static void ath10k_debug_fw_stats_vdevs_free(struct list_head *head) +++{ +++ struct ath10k_fw_stats_vdev *i, *tmp; +++ +++ list_for_each_entry_safe(i, tmp, head, list) { +++ list_del(&i->list); +++ kfree(i); +++ } +++} +++ +++static void ath10k_debug_fw_stats_peers_free(struct list_head *head) +++{ +++ struct ath10k_fw_stats_peer *i, *tmp; +++ +++ list_for_each_entry_safe(i, tmp, head, list) { +++ list_del(&i->list); +++ kfree(i); +++ } +++} +++ +++static void ath10k_debug_fw_stats_reset(struct ath10k *ar) +++{ ++ spin_lock_bh(&ar->data_lock); +++ ar->debug.fw_stats_done = false; +++ ath10k_debug_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs); +++ ath10k_debug_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs); +++ ath10k_debug_fw_stats_peers_free(&ar->debug.fw_stats.peers); +++ spin_unlock_bh(&ar->data_lock); +++} ++ ++- stats = &ar->debug.target_stats; +++static size_t ath10k_debug_fw_stats_num_peers(struct list_head *head) +++{ +++ struct ath10k_fw_stats_peer *i; +++ size_t num = 0; ++ ++- num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); /* 0 or 1 */ ++- num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); /* 0 or max vdevs */ ++- num_peer_stats = __le32_to_cpu(ev->num_peer_stats); /* 0 or max peers */ ++- ++- if (num_pdev_stats) { ++- ps = (struct wmi_pdev_stats_10x *)tmp; ++- ++- stats->ch_noise_floor = __le32_to_cpu(ps->chan_nf); ++- stats->tx_frame_count = __le32_to_cpu(ps->tx_frame_count); ++- stats->rx_frame_count = __le32_to_cpu(ps->rx_frame_count); ++- stats->rx_clear_count = __le32_to_cpu(ps->rx_clear_count); ++- stats->cycle_count = __le32_to_cpu(ps->cycle_count); ++- stats->phy_err_count = __le32_to_cpu(ps->phy_err_count); ++- stats->chan_tx_power = __le32_to_cpu(ps->chan_tx_pwr); ++- ++- stats->comp_queued = __le32_to_cpu(ps->wal.tx.comp_queued); ++- stats->comp_delivered = ++- __le32_to_cpu(ps->wal.tx.comp_delivered); ++- stats->msdu_enqued = __le32_to_cpu(ps->wal.tx.msdu_enqued); ++- stats->mpdu_enqued = __le32_to_cpu(ps->wal.tx.mpdu_enqued); ++- stats->wmm_drop = __le32_to_cpu(ps->wal.tx.wmm_drop); ++- stats->local_enqued = __le32_to_cpu(ps->wal.tx.local_enqued); ++- stats->local_freed = __le32_to_cpu(ps->wal.tx.local_freed); ++- stats->hw_queued = __le32_to_cpu(ps->wal.tx.hw_queued); ++- stats->hw_reaped = __le32_to_cpu(ps->wal.tx.hw_reaped); ++- stats->underrun = __le32_to_cpu(ps->wal.tx.underrun); ++- stats->tx_abort = __le32_to_cpu(ps->wal.tx.tx_abort); ++- stats->mpdus_requed = __le32_to_cpu(ps->wal.tx.mpdus_requed); ++- stats->tx_ko = __le32_to_cpu(ps->wal.tx.tx_ko); ++- stats->data_rc = __le32_to_cpu(ps->wal.tx.data_rc); ++- stats->self_triggers = __le32_to_cpu(ps->wal.tx.self_triggers); ++- stats->sw_retry_failure = ++- __le32_to_cpu(ps->wal.tx.sw_retry_failure); ++- stats->illgl_rate_phy_err = ++- __le32_to_cpu(ps->wal.tx.illgl_rate_phy_err); ++- stats->pdev_cont_xretry = ++- __le32_to_cpu(ps->wal.tx.pdev_cont_xretry); ++- stats->pdev_tx_timeout = ++- __le32_to_cpu(ps->wal.tx.pdev_tx_timeout); ++- stats->pdev_resets = __le32_to_cpu(ps->wal.tx.pdev_resets); ++- stats->phy_underrun = __le32_to_cpu(ps->wal.tx.phy_underrun); ++- stats->txop_ovf = __le32_to_cpu(ps->wal.tx.txop_ovf); ++- ++- stats->mid_ppdu_route_change = ++- __le32_to_cpu(ps->wal.rx.mid_ppdu_route_change); ++- stats->status_rcvd = __le32_to_cpu(ps->wal.rx.status_rcvd); ++- stats->r0_frags = __le32_to_cpu(ps->wal.rx.r0_frags); ++- stats->r1_frags = __le32_to_cpu(ps->wal.rx.r1_frags); ++- stats->r2_frags = __le32_to_cpu(ps->wal.rx.r2_frags); ++- stats->r3_frags = __le32_to_cpu(ps->wal.rx.r3_frags); ++- stats->htt_msdus = __le32_to_cpu(ps->wal.rx.htt_msdus); ++- stats->htt_mpdus = __le32_to_cpu(ps->wal.rx.htt_mpdus); ++- stats->loc_msdus = __le32_to_cpu(ps->wal.rx.loc_msdus); ++- stats->loc_mpdus = __le32_to_cpu(ps->wal.rx.loc_mpdus); ++- stats->oversize_amsdu = ++- __le32_to_cpu(ps->wal.rx.oversize_amsdu); ++- stats->phy_errs = __le32_to_cpu(ps->wal.rx.phy_errs); ++- stats->phy_err_drop = __le32_to_cpu(ps->wal.rx.phy_err_drop); ++- stats->mpdu_errs = __le32_to_cpu(ps->wal.rx.mpdu_errs); ++- ++- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ++- ar->fw_features)) { ++- stats->ack_rx_bad = __le32_to_cpu(ps->ack_rx_bad); ++- stats->rts_bad = __le32_to_cpu(ps->rts_bad); ++- stats->rts_good = __le32_to_cpu(ps->rts_good); ++- stats->fcs_bad = __le32_to_cpu(ps->fcs_bad); ++- stats->no_beacons = __le32_to_cpu(ps->no_beacons); ++- stats->mib_int_count = __le32_to_cpu(ps->mib_int_count); ++- tmp += sizeof(struct wmi_pdev_stats_10x); ++- } else { ++- tmp += sizeof(struct wmi_pdev_stats_old); ++- } +++ list_for_each_entry(i, head, list) +++ ++num; +++ +++ return num; +++} +++ +++static size_t ath10k_debug_fw_stats_num_vdevs(struct list_head *head) +++{ +++ struct ath10k_fw_stats_vdev *i; +++ size_t num = 0; +++ +++ list_for_each_entry(i, head, list) +++ ++num; +++ +++ return num; +++} +++ +++void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) +++{ +++ struct ath10k_fw_stats stats = {}; +++ bool is_start, is_started, is_end; +++ size_t num_peers; +++ size_t num_vdevs; +++ int ret; +++ +++ INIT_LIST_HEAD(&stats.pdevs); +++ INIT_LIST_HEAD(&stats.vdevs); +++ INIT_LIST_HEAD(&stats.peers); +++ +++ spin_lock_bh(&ar->data_lock); +++ ret = ath10k_wmi_pull_fw_stats(ar, skb, &stats); +++ if (ret) { +++ ath10k_warn(ar, "failed to pull fw stats: %d\n", ret); +++ goto unlock; ++ } ++ ++- /* 0 or max vdevs */ ++- /* Currently firmware does not support VDEV stats */ ++- if (num_vdev_stats) { ++- struct wmi_vdev_stats *vdev_stats; ++- ++- for (i = 0; i < num_vdev_stats; i++) { ++- vdev_stats = (struct wmi_vdev_stats *)tmp; ++- tmp += sizeof(struct wmi_vdev_stats); ++- } +++ /* Stat data may exceed htc-wmi buffer limit. In such case firmware +++ * splits the stats data and delivers it in a ping-pong fashion of +++ * request cmd-update event. +++ * +++ * However there is no explicit end-of-data. Instead start-of-data is +++ * used as an implicit one. This works as follows: +++ * a) discard stat update events until one with pdev stats is +++ * delivered - this skips session started at end of (b) +++ * b) consume stat update events until another one with pdev stats is +++ * delivered which is treated as end-of-data and is itself discarded +++ */ +++ +++ if (ar->debug.fw_stats_done) { +++ ath10k_warn(ar, "received unsolicited stats update event\n"); +++ goto free; ++ } ++ ++- if (num_peer_stats) { ++- struct wmi_peer_stats_10x *peer_stats; ++- struct ath10k_peer_stat *s; ++- ++- stats->peers = num_peer_stats; ++- ++- for (i = 0; i < num_peer_stats; i++) { ++- peer_stats = (struct wmi_peer_stats_10x *)tmp; ++- s = &stats->peer_stat[i]; ++- ++- memcpy(s->peer_macaddr, &peer_stats->peer_macaddr.addr, ++- ETH_ALEN); ++- s->peer_rssi = __le32_to_cpu(peer_stats->peer_rssi); ++- s->peer_tx_rate = ++- __le32_to_cpu(peer_stats->peer_tx_rate); ++- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ++- ar->fw_features)) { ++- s->peer_rx_rate = ++- __le32_to_cpu(peer_stats->peer_rx_rate); ++- tmp += sizeof(struct wmi_peer_stats_10x); ++- ++- } else { ++- tmp += sizeof(struct wmi_peer_stats_old); ++- } +++ num_peers = ath10k_debug_fw_stats_num_peers(&ar->debug.fw_stats.peers); +++ num_vdevs = ath10k_debug_fw_stats_num_vdevs(&ar->debug.fw_stats.vdevs); +++ is_start = (list_empty(&ar->debug.fw_stats.pdevs) && +++ !list_empty(&stats.pdevs)); +++ is_end = (!list_empty(&ar->debug.fw_stats.pdevs) && +++ !list_empty(&stats.pdevs)); +++ +++ if (is_start) +++ list_splice_tail_init(&stats.pdevs, &ar->debug.fw_stats.pdevs); +++ +++ if (is_end) +++ ar->debug.fw_stats_done = true; +++ +++ is_started = !list_empty(&ar->debug.fw_stats.pdevs); +++ +++ if (is_started && !is_end) { +++ if (num_peers >= ATH10K_MAX_NUM_PEER_IDS) { +++ /* Although this is unlikely impose a sane limit to +++ * prevent firmware from DoS-ing the host. +++ */ +++ ath10k_warn(ar, "dropping fw peer stats\n"); +++ goto free; ++ } +++ +++ if (num_vdevs >= BITS_PER_LONG) { +++ ath10k_warn(ar, "dropping fw vdev stats\n"); +++ goto free; +++ } +++ +++ list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers); +++ list_splice_tail_init(&stats.vdevs, &ar->debug.fw_stats.vdevs); ++ } ++ +++ complete(&ar->debug.fw_stats_complete); +++ +++free: +++ /* In some cases lists have been spliced and cleared. Free up +++ * resources if that is not the case. +++ */ +++ ath10k_debug_fw_stats_pdevs_free(&stats.pdevs); +++ ath10k_debug_fw_stats_vdevs_free(&stats.vdevs); +++ ath10k_debug_fw_stats_peers_free(&stats.peers); +++ +++unlock: ++ spin_unlock_bh(&ar->data_lock); ++- complete(&ar->debug.event_stats_compl); ++ } ++ ++-static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf, ++- size_t count, loff_t *ppos) +++static int ath10k_debug_fw_stats_request(struct ath10k *ar) ++ { ++- struct ath10k *ar = file->private_data; ++- struct ath10k_target_stats *fw_stats; ++- char *buf = NULL; ++- unsigned int len = 0, buf_len = 8000; ++- ssize_t ret_cnt = 0; ++- long left; ++- int i; +++ unsigned long timeout; ++ int ret; ++ ++- fw_stats = &ar->debug.target_stats; +++ lockdep_assert_held(&ar->conf_mutex); ++ ++- mutex_lock(&ar->conf_mutex); +++ timeout = jiffies + msecs_to_jiffies(1*HZ); ++ ++- if (ar->state != ATH10K_STATE_ON) ++- goto exit; +++ ath10k_debug_fw_stats_reset(ar); ++ ++- buf = kzalloc(buf_len, GFP_KERNEL); ++- if (!buf) ++- goto exit; +++ for (;;) { +++ if (time_after(jiffies, timeout)) +++ return -ETIMEDOUT; ++ ++- ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT); ++- if (ret) { ++- ath10k_warn("could not request stats (%d)\n", ret); ++- goto exit; +++ reinit_completion(&ar->debug.fw_stats_complete); +++ +++ ret = ath10k_wmi_request_stats(ar, +++ WMI_STAT_PDEV | +++ WMI_STAT_VDEV | +++ WMI_STAT_PEER); +++ if (ret) { +++ ath10k_warn(ar, "could not request stats (%d)\n", ret); +++ return ret; +++ } +++ +++ ret = wait_for_completion_timeout(&ar->debug.fw_stats_complete, +++ 1*HZ); +++ if (ret == 0) +++ return -ETIMEDOUT; +++ +++ spin_lock_bh(&ar->data_lock); +++ if (ar->debug.fw_stats_done) { +++ spin_unlock_bh(&ar->data_lock); +++ break; +++ } +++ spin_unlock_bh(&ar->data_lock); ++ } ++ ++- left = wait_for_completion_timeout(&ar->debug.event_stats_compl, 1*HZ); ++- if (left <= 0) ++- goto exit; +++ return 0; +++} +++ +++/* FIXME: How to calculate the buffer size sanely? */ +++#define ATH10K_FW_STATS_BUF_SIZE (1024*1024) +++ +++static void ath10k_fw_stats_fill(struct ath10k *ar, +++ struct ath10k_fw_stats *fw_stats, +++ char *buf) +++{ +++ unsigned int len = 0; +++ unsigned int buf_len = ATH10K_FW_STATS_BUF_SIZE; +++ const struct ath10k_fw_stats_pdev *pdev; +++ const struct ath10k_fw_stats_vdev *vdev; +++ const struct ath10k_fw_stats_peer *peer; +++ size_t num_peers; +++ size_t num_vdevs; +++ int i; ++ ++ spin_lock_bh(&ar->data_lock); +++ +++ pdev = list_first_entry_or_null(&fw_stats->pdevs, +++ struct ath10k_fw_stats_pdev, list); +++ if (!pdev) { +++ ath10k_warn(ar, "failed to get pdev stats\n"); +++ goto unlock; +++ } +++ +++ num_peers = ath10k_debug_fw_stats_num_peers(&fw_stats->peers); +++ num_vdevs = ath10k_debug_fw_stats_num_vdevs(&fw_stats->vdevs); +++ ++ len += scnprintf(buf + len, buf_len - len, "\n"); ++ len += scnprintf(buf + len, buf_len - len, "%30s\n", ++ "ath10k PDEV stats"); ++@@ -325,29 +455,29 @@ static ssize_t ath10k_read_fw_stats(stru ++ "================="); ++ ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "Channel noise floor", fw_stats->ch_noise_floor); +++ "Channel noise floor", pdev->ch_noise_floor); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++- "Channel TX power", fw_stats->chan_tx_power); +++ "Channel TX power", pdev->chan_tx_power); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++- "TX frame count", fw_stats->tx_frame_count); +++ "TX frame count", pdev->tx_frame_count); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++- "RX frame count", fw_stats->rx_frame_count); +++ "RX frame count", pdev->rx_frame_count); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++- "RX clear count", fw_stats->rx_clear_count); +++ "RX clear count", pdev->rx_clear_count); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++- "Cycle count", fw_stats->cycle_count); +++ "Cycle count", pdev->cycle_count); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++- "PHY error count", fw_stats->phy_err_count); +++ "PHY error count", pdev->phy_err_count); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++- "RTS bad count", fw_stats->rts_bad); +++ "RTS bad count", pdev->rts_bad); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++- "RTS good count", fw_stats->rts_good); +++ "RTS good count", pdev->rts_good); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++- "FCS bad count", fw_stats->fcs_bad); +++ "FCS bad count", pdev->fcs_bad); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++- "No beacon count", fw_stats->no_beacons); +++ "No beacon count", pdev->no_beacons); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++- "MIB int count", fw_stats->mib_int_count); +++ "MIB int count", pdev->mib_int_count); ++ ++ len += scnprintf(buf + len, buf_len - len, "\n"); ++ len += scnprintf(buf + len, buf_len - len, "%30s\n", ++@@ -356,51 +486,51 @@ static ssize_t ath10k_read_fw_stats(stru ++ "================="); ++ ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "HTT cookies queued", fw_stats->comp_queued); +++ "HTT cookies queued", pdev->comp_queued); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "HTT cookies disp.", fw_stats->comp_delivered); +++ "HTT cookies disp.", pdev->comp_delivered); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "MSDU queued", fw_stats->msdu_enqued); +++ "MSDU queued", pdev->msdu_enqued); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "MPDU queued", fw_stats->mpdu_enqued); +++ "MPDU queued", pdev->mpdu_enqued); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "MSDUs dropped", fw_stats->wmm_drop); +++ "MSDUs dropped", pdev->wmm_drop); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "Local enqued", fw_stats->local_enqued); +++ "Local enqued", pdev->local_enqued); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "Local freed", fw_stats->local_freed); +++ "Local freed", pdev->local_freed); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "HW queued", fw_stats->hw_queued); +++ "HW queued", pdev->hw_queued); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "PPDUs reaped", fw_stats->hw_reaped); +++ "PPDUs reaped", pdev->hw_reaped); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "Num underruns", fw_stats->underrun); +++ "Num underruns", pdev->underrun); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "PPDUs cleaned", fw_stats->tx_abort); +++ "PPDUs cleaned", pdev->tx_abort); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "MPDUs requed", fw_stats->mpdus_requed); +++ "MPDUs requed", pdev->mpdus_requed); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "Excessive retries", fw_stats->tx_ko); +++ "Excessive retries", pdev->tx_ko); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "HW rate", fw_stats->data_rc); +++ "HW rate", pdev->data_rc); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "Sched self tiggers", fw_stats->self_triggers); +++ "Sched self tiggers", pdev->self_triggers); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++ "Dropped due to SW retries", ++- fw_stats->sw_retry_failure); +++ pdev->sw_retry_failure); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++ "Illegal rate phy errors", ++- fw_stats->illgl_rate_phy_err); +++ pdev->illgl_rate_phy_err); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "Pdev continous xretry", fw_stats->pdev_cont_xretry); +++ "Pdev continous xretry", pdev->pdev_cont_xretry); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "TX timeout", fw_stats->pdev_tx_timeout); +++ "TX timeout", pdev->pdev_tx_timeout); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "PDEV resets", fw_stats->pdev_resets); +++ "PDEV resets", pdev->pdev_resets); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "PHY underrun", fw_stats->phy_underrun); +++ "PHY underrun", pdev->phy_underrun); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "MPDU is more than txop limit", fw_stats->txop_ovf); +++ "MPDU is more than txop limit", pdev->txop_ovf); ++ ++ len += scnprintf(buf + len, buf_len - len, "\n"); ++ len += scnprintf(buf + len, buf_len - len, "%30s\n", ++@@ -410,84 +540,254 @@ static ssize_t ath10k_read_fw_stats(stru ++ ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++ "Mid PPDU route change", ++- fw_stats->mid_ppdu_route_change); +++ pdev->mid_ppdu_route_change); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "Tot. number of statuses", fw_stats->status_rcvd); +++ "Tot. number of statuses", pdev->status_rcvd); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "Extra frags on rings 0", fw_stats->r0_frags); +++ "Extra frags on rings 0", pdev->r0_frags); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "Extra frags on rings 1", fw_stats->r1_frags); +++ "Extra frags on rings 1", pdev->r1_frags); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "Extra frags on rings 2", fw_stats->r2_frags); +++ "Extra frags on rings 2", pdev->r2_frags); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "Extra frags on rings 3", fw_stats->r3_frags); +++ "Extra frags on rings 3", pdev->r3_frags); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "MSDUs delivered to HTT", fw_stats->htt_msdus); +++ "MSDUs delivered to HTT", pdev->htt_msdus); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "MPDUs delivered to HTT", fw_stats->htt_mpdus); +++ "MPDUs delivered to HTT", pdev->htt_mpdus); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "MSDUs delivered to stack", fw_stats->loc_msdus); +++ "MSDUs delivered to stack", pdev->loc_msdus); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "MPDUs delivered to stack", fw_stats->loc_mpdus); +++ "MPDUs delivered to stack", pdev->loc_mpdus); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "Oversized AMSUs", fw_stats->oversize_amsdu); +++ "Oversized AMSUs", pdev->oversize_amsdu); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "PHY errors", fw_stats->phy_errs); +++ "PHY errors", pdev->phy_errs); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "PHY errors drops", fw_stats->phy_err_drop); +++ "PHY errors drops", pdev->phy_err_drop); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++- "MPDU errors (FCS, MIC, ENC)", fw_stats->mpdu_errs); +++ "MPDU errors (FCS, MIC, ENC)", pdev->mpdu_errs); +++ +++ len += scnprintf(buf + len, buf_len - len, "\n"); +++ len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n", +++ "ath10k VDEV stats", num_vdevs); +++ len += scnprintf(buf + len, buf_len - len, "%30s\n\n", +++ "================="); +++ +++ list_for_each_entry(vdev, &fw_stats->vdevs, list) { +++ len += scnprintf(buf + len, buf_len - len, "%30s %u\n", +++ "vdev id", vdev->vdev_id); +++ len += scnprintf(buf + len, buf_len - len, "%30s %u\n", +++ "beacon snr", vdev->beacon_snr); +++ len += scnprintf(buf + len, buf_len - len, "%30s %u\n", +++ "data snr", vdev->data_snr); +++ len += scnprintf(buf + len, buf_len - len, "%30s %u\n", +++ "num rx frames", vdev->num_rx_frames); +++ len += scnprintf(buf + len, buf_len - len, "%30s %u\n", +++ "num rts fail", vdev->num_rts_fail); +++ len += scnprintf(buf + len, buf_len - len, "%30s %u\n", +++ "num rts success", vdev->num_rts_success); +++ len += scnprintf(buf + len, buf_len - len, "%30s %u\n", +++ "num rx err", vdev->num_rx_err); +++ len += scnprintf(buf + len, buf_len - len, "%30s %u\n", +++ "num rx discard", vdev->num_rx_discard); +++ len += scnprintf(buf + len, buf_len - len, "%30s %u\n", +++ "num tx not acked", vdev->num_tx_not_acked); +++ +++ for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames); i++) +++ len += scnprintf(buf + len, buf_len - len, +++ "%25s [%02d] %u\n", +++ "num tx frames", i, +++ vdev->num_tx_frames[i]); +++ +++ for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames_retries); i++) +++ len += scnprintf(buf + len, buf_len - len, +++ "%25s [%02d] %u\n", +++ "num tx frames retries", i, +++ vdev->num_tx_frames_retries[i]); +++ +++ for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames_failures); i++) +++ len += scnprintf(buf + len, buf_len - len, +++ "%25s [%02d] %u\n", +++ "num tx frames failures", i, +++ vdev->num_tx_frames_failures[i]); +++ +++ for (i = 0 ; i < ARRAY_SIZE(vdev->tx_rate_history); i++) +++ len += scnprintf(buf + len, buf_len - len, +++ "%25s [%02d] 0x%08x\n", +++ "tx rate history", i, +++ vdev->tx_rate_history[i]); +++ +++ for (i = 0 ; i < ARRAY_SIZE(vdev->beacon_rssi_history); i++) +++ len += scnprintf(buf + len, buf_len - len, +++ "%25s [%02d] %u\n", +++ "beacon rssi history", i, +++ vdev->beacon_rssi_history[i]); +++ +++ len += scnprintf(buf + len, buf_len - len, "\n"); +++ } ++ ++ len += scnprintf(buf + len, buf_len - len, "\n"); ++- len += scnprintf(buf + len, buf_len - len, "%30s (%d)\n", ++- "ath10k PEER stats", fw_stats->peers); +++ len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n", +++ "ath10k PEER stats", num_peers); ++ len += scnprintf(buf + len, buf_len - len, "%30s\n\n", ++ "================="); ++ ++- for (i = 0; i < fw_stats->peers; i++) { +++ list_for_each_entry(peer, &fw_stats->peers, list) { ++ len += scnprintf(buf + len, buf_len - len, "%30s %pM\n", ++- "Peer MAC address", ++- fw_stats->peer_stat[i].peer_macaddr); +++ "Peer MAC address", peer->peer_macaddr); ++ len += scnprintf(buf + len, buf_len - len, "%30s %u\n", ++- "Peer RSSI", fw_stats->peer_stat[i].peer_rssi); +++ "Peer RSSI", peer->peer_rssi); ++ len += scnprintf(buf + len, buf_len - len, "%30s %u\n", ++- "Peer TX rate", ++- fw_stats->peer_stat[i].peer_tx_rate); +++ "Peer TX rate", peer->peer_tx_rate); ++ len += scnprintf(buf + len, buf_len - len, "%30s %u\n", ++- "Peer RX rate", ++- fw_stats->peer_stat[i].peer_rx_rate); +++ "Peer RX rate", peer->peer_rx_rate); ++ len += scnprintf(buf + len, buf_len - len, "\n"); ++ } +++ +++unlock: ++ spin_unlock_bh(&ar->data_lock); ++ ++- if (len > buf_len) ++- len = buf_len; +++ if (len >= buf_len) +++ buf[len - 1] = 0; +++ else +++ buf[len] = 0; +++} ++ ++- ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); +++static int ath10k_fw_stats_open(struct inode *inode, struct file *file) +++{ +++ struct ath10k *ar = inode->i_private; +++ void *buf = NULL; +++ int ret; +++ +++ mutex_lock(&ar->conf_mutex); +++ +++ if (ar->state != ATH10K_STATE_ON) { +++ ret = -ENETDOWN; +++ goto err_unlock; +++ } +++ +++ buf = vmalloc(ATH10K_FW_STATS_BUF_SIZE); +++ if (!buf) { +++ ret = -ENOMEM; +++ goto err_unlock; +++ } +++ +++ ret = ath10k_debug_fw_stats_request(ar); +++ if (ret) { +++ ath10k_warn(ar, "failed to request fw stats: %d\n", ret); +++ goto err_free; +++ } +++ +++ ath10k_fw_stats_fill(ar, &ar->debug.fw_stats, buf); +++ file->private_data = buf; ++ ++-exit: ++ mutex_unlock(&ar->conf_mutex); ++- kfree(buf); ++- return ret_cnt; +++ return 0; +++ +++err_free: +++ vfree(buf); +++ +++err_unlock: +++ mutex_unlock(&ar->conf_mutex); +++ return ret; +++} +++ +++static int ath10k_fw_stats_release(struct inode *inode, struct file *file) +++{ +++ vfree(file->private_data); +++ +++ return 0; +++} +++ +++static ssize_t ath10k_fw_stats_read(struct file *file, char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ const char *buf = file->private_data; +++ unsigned int len = strlen(buf); +++ +++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ } ++ ++ static const struct file_operations fops_fw_stats = { ++- .read = ath10k_read_fw_stats, +++ .open = ath10k_fw_stats_open, +++ .release = ath10k_fw_stats_release, +++ .read = ath10k_fw_stats_read, +++ .owner = THIS_MODULE, +++ .llseek = default_llseek, +++}; +++ +++static ssize_t ath10k_debug_fw_reset_stats_read(struct file *file, +++ char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ath10k *ar = file->private_data; +++ int ret, len, buf_len; +++ char *buf; +++ +++ buf_len = 500; +++ buf = kmalloc(buf_len, GFP_KERNEL); +++ if (!buf) +++ return -ENOMEM; +++ +++ spin_lock_bh(&ar->data_lock); +++ +++ len = 0; +++ len += scnprintf(buf + len, buf_len - len, +++ "fw_crash_counter\t\t%d\n", ar->stats.fw_crash_counter); +++ len += scnprintf(buf + len, buf_len - len, +++ "fw_warm_reset_counter\t\t%d\n", +++ ar->stats.fw_warm_reset_counter); +++ len += scnprintf(buf + len, buf_len - len, +++ "fw_cold_reset_counter\t\t%d\n", +++ ar->stats.fw_cold_reset_counter); +++ +++ spin_unlock_bh(&ar->data_lock); +++ +++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); +++ +++ kfree(buf); +++ +++ return ret; +++} +++ +++static const struct file_operations fops_fw_reset_stats = { ++ .open = simple_open, +++ .read = ath10k_debug_fw_reset_stats_read, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++ }; ++ +++/* This is a clean assert crash in firmware. */ +++static int ath10k_debug_fw_assert(struct ath10k *ar) +++{ +++ struct wmi_vdev_install_key_cmd *cmd; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd) + 16); +++ if (!skb) +++ return -ENOMEM; +++ +++ cmd = (struct wmi_vdev_install_key_cmd *)skb->data; +++ memset(cmd, 0, sizeof(*cmd)); +++ +++ /* big enough number so that firmware asserts */ +++ cmd->vdev_id = __cpu_to_le32(0x7ffe); +++ +++ return ath10k_wmi_cmd_send(ar, skb, +++ ar->wmi.cmd->vdev_install_key_cmdid); +++} +++ ++ static ssize_t ath10k_read_simulate_fw_crash(struct file *file, ++ char __user *user_buf, ++ size_t count, loff_t *ppos) ++ { ++- const char buf[] = "To simulate firmware crash write one of the" ++- " keywords to this file:\n `soft` - this will send" ++- " WMI_FORCE_FW_HANG_ASSERT to firmware if FW" ++- " supports that command.\n `hard` - this will send" ++- " to firmware command with illegal parameters" ++- " causing firmware crash.\n"; +++ const char buf[] = +++ "To simulate firmware crash write one of the keywords to this file:\n" +++ "`soft` - this will send WMI_FORCE_FW_HANG_ASSERT to firmware if FW supports that command.\n" +++ "`hard` - this will send to firmware command with illegal parameters causing firmware crash.\n" +++ "`assert` - this will send special illegal parameter to firmware to cause assert failure and crash.\n" +++ "`hw-restart` - this will simply queue hw restart without fw/hw actually crashing.\n"; ++ ++ return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); ++ } ++@@ -527,19 +827,30 @@ static ssize_t ath10k_write_simulate_fw_ ++ } ++ ++ if (!strcmp(buf, "soft")) { ++- ath10k_info("simulating soft firmware crash\n"); +++ ath10k_info(ar, "simulating soft firmware crash\n"); ++ ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0); ++ } else if (!strcmp(buf, "hard")) { ++- ath10k_info("simulating hard firmware crash\n"); ++- ret = ath10k_wmi_vdev_set_param(ar, TARGET_NUM_VDEVS + 1, ++- ar->wmi.vdev_param->rts_threshold, 0); +++ ath10k_info(ar, "simulating hard firmware crash\n"); +++ /* 0x7fff is vdev id, and it is always out of range for all +++ * firmware variants in order to force a firmware crash. +++ */ +++ ret = ath10k_wmi_vdev_set_param(ar, 0x7fff, +++ ar->wmi.vdev_param->rts_threshold, +++ 0); +++ } else if (!strcmp(buf, "assert")) { +++ ath10k_info(ar, "simulating firmware assert crash\n"); +++ ret = ath10k_debug_fw_assert(ar); +++ } else if (!strcmp(buf, "hw-restart")) { +++ ath10k_info(ar, "user requested hw restart\n"); +++ queue_work(ar->workqueue, &ar->restart_work); +++ ret = 0; ++ } else { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (ret) { ++- ath10k_warn("failed to simulate firmware crash: %d\n", ret); +++ ath10k_warn(ar, "failed to simulate firmware crash: %d\n", ret); ++ goto exit; ++ } ++ ++@@ -565,13 +876,375 @@ static ssize_t ath10k_read_chip_id(struc ++ unsigned int len; ++ char buf[50]; ++ ++- len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->chip_id); +++ len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->chip_id); +++ +++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); +++} +++ +++static const struct file_operations fops_chip_id = { +++ .read = ath10k_read_chip_id, +++ .open = simple_open, +++ .owner = THIS_MODULE, +++ .llseek = default_llseek, +++}; +++ +++struct ath10k_fw_crash_data * +++ath10k_debug_get_new_fw_crash_data(struct ath10k *ar) +++{ +++ struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data; +++ +++ lockdep_assert_held(&ar->data_lock); +++ +++ crash_data->crashed_since_read = true; +++ uuid_le_gen(&crash_data->uuid); +++ getnstimeofday(&crash_data->timestamp); +++ +++ return crash_data; +++} +++EXPORT_SYMBOL(ath10k_debug_get_new_fw_crash_data); +++ +++static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar) +++{ +++ struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data; +++ struct ath10k_dump_file_data *dump_data; +++ struct ath10k_tlv_dump_data *dump_tlv; +++ int hdr_len = sizeof(*dump_data); +++ unsigned int len, sofar = 0; +++ unsigned char *buf; +++ +++ len = hdr_len; +++ len += sizeof(*dump_tlv) + sizeof(crash_data->registers); +++ +++ sofar += hdr_len; +++ +++ /* This is going to get big when we start dumping FW RAM and such, +++ * so go ahead and use vmalloc. +++ */ +++ buf = vzalloc(len); +++ if (!buf) +++ return NULL; +++ +++ spin_lock_bh(&ar->data_lock); +++ +++ if (!crash_data->crashed_since_read) { +++ spin_unlock_bh(&ar->data_lock); +++ vfree(buf); +++ return NULL; +++ } +++ +++ dump_data = (struct ath10k_dump_file_data *)(buf); +++ strlcpy(dump_data->df_magic, "ATH10K-FW-DUMP", +++ sizeof(dump_data->df_magic)); +++ dump_data->len = cpu_to_le32(len); +++ +++ dump_data->version = cpu_to_le32(ATH10K_FW_CRASH_DUMP_VERSION); +++ +++ memcpy(dump_data->uuid, &crash_data->uuid, sizeof(dump_data->uuid)); +++ dump_data->chip_id = cpu_to_le32(ar->chip_id); +++ dump_data->bus_type = cpu_to_le32(0); +++ dump_data->target_version = cpu_to_le32(ar->target_version); +++ dump_data->fw_version_major = cpu_to_le32(ar->fw_version_major); +++ dump_data->fw_version_minor = cpu_to_le32(ar->fw_version_minor); +++ dump_data->fw_version_release = cpu_to_le32(ar->fw_version_release); +++ dump_data->fw_version_build = cpu_to_le32(ar->fw_version_build); +++ dump_data->phy_capability = cpu_to_le32(ar->phy_capability); +++ dump_data->hw_min_tx_power = cpu_to_le32(ar->hw_min_tx_power); +++ dump_data->hw_max_tx_power = cpu_to_le32(ar->hw_max_tx_power); +++ dump_data->ht_cap_info = cpu_to_le32(ar->ht_cap_info); +++ dump_data->vht_cap_info = cpu_to_le32(ar->vht_cap_info); +++ dump_data->num_rf_chains = cpu_to_le32(ar->num_rf_chains); +++ +++ strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version, +++ sizeof(dump_data->fw_ver)); +++ +++ dump_data->kernel_ver_code = 0; +++ strlcpy(dump_data->kernel_ver, init_utsname()->release, +++ sizeof(dump_data->kernel_ver)); +++ +++ dump_data->tv_sec = cpu_to_le64(crash_data->timestamp.tv_sec); +++ dump_data->tv_nsec = cpu_to_le64(crash_data->timestamp.tv_nsec); +++ +++ /* Gather crash-dump */ +++ dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar); +++ dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_REGISTERS); +++ dump_tlv->tlv_len = cpu_to_le32(sizeof(crash_data->registers)); +++ memcpy(dump_tlv->tlv_data, &crash_data->registers, +++ sizeof(crash_data->registers)); +++ sofar += sizeof(*dump_tlv) + sizeof(crash_data->registers); +++ +++ ar->debug.fw_crash_data->crashed_since_read = false; +++ +++ spin_unlock_bh(&ar->data_lock); +++ +++ return dump_data; +++} +++ +++static int ath10k_fw_crash_dump_open(struct inode *inode, struct file *file) +++{ +++ struct ath10k *ar = inode->i_private; +++ struct ath10k_dump_file_data *dump; +++ +++ dump = ath10k_build_dump_file(ar); +++ if (!dump) +++ return -ENODATA; +++ +++ file->private_data = dump; +++ +++ return 0; +++} +++ +++static ssize_t ath10k_fw_crash_dump_read(struct file *file, +++ char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ath10k_dump_file_data *dump_file = file->private_data; +++ +++ return simple_read_from_buffer(user_buf, count, ppos, +++ dump_file, +++ le32_to_cpu(dump_file->len)); +++} +++ +++static int ath10k_fw_crash_dump_release(struct inode *inode, +++ struct file *file) +++{ +++ vfree(file->private_data); +++ +++ return 0; +++} +++ +++static const struct file_operations fops_fw_crash_dump = { +++ .open = ath10k_fw_crash_dump_open, +++ .read = ath10k_fw_crash_dump_read, +++ .release = ath10k_fw_crash_dump_release, +++ .owner = THIS_MODULE, +++ .llseek = default_llseek, +++}; +++ +++static ssize_t ath10k_reg_addr_read(struct file *file, +++ char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ath10k *ar = file->private_data; +++ u8 buf[32]; +++ unsigned int len = 0; +++ u32 reg_addr; +++ +++ mutex_lock(&ar->conf_mutex); +++ reg_addr = ar->debug.reg_addr; +++ mutex_unlock(&ar->conf_mutex); +++ +++ len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n", reg_addr); +++ +++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); +++} +++ +++static ssize_t ath10k_reg_addr_write(struct file *file, +++ const char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ath10k *ar = file->private_data; +++ u32 reg_addr; +++ int ret; +++ +++ ret = kstrtou32_from_user(user_buf, count, 0, ®_addr); +++ if (ret) +++ return ret; +++ +++ if (!IS_ALIGNED(reg_addr, 4)) +++ return -EFAULT; +++ +++ mutex_lock(&ar->conf_mutex); +++ ar->debug.reg_addr = reg_addr; +++ mutex_unlock(&ar->conf_mutex); +++ +++ return count; +++} +++ +++static const struct file_operations fops_reg_addr = { +++ .read = ath10k_reg_addr_read, +++ .write = ath10k_reg_addr_write, +++ .open = simple_open, +++ .owner = THIS_MODULE, +++ .llseek = default_llseek, +++}; +++ +++static ssize_t ath10k_reg_value_read(struct file *file, +++ char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ath10k *ar = file->private_data; +++ u8 buf[48]; +++ unsigned int len; +++ u32 reg_addr, reg_val; +++ int ret; +++ +++ mutex_lock(&ar->conf_mutex); +++ +++ if (ar->state != ATH10K_STATE_ON && +++ ar->state != ATH10K_STATE_UTF) { +++ ret = -ENETDOWN; +++ goto exit; +++ } +++ +++ reg_addr = ar->debug.reg_addr; +++ +++ reg_val = ath10k_hif_read32(ar, reg_addr); +++ len = scnprintf(buf, sizeof(buf), "0x%08x:0x%08x\n", reg_addr, reg_val); +++ +++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); +++ +++exit: +++ mutex_unlock(&ar->conf_mutex); +++ +++ return ret; +++} +++ +++static ssize_t ath10k_reg_value_write(struct file *file, +++ const char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ath10k *ar = file->private_data; +++ u32 reg_addr, reg_val; +++ int ret; +++ +++ mutex_lock(&ar->conf_mutex); +++ +++ if (ar->state != ATH10K_STATE_ON && +++ ar->state != ATH10K_STATE_UTF) { +++ ret = -ENETDOWN; +++ goto exit; +++ } +++ +++ reg_addr = ar->debug.reg_addr; +++ +++ ret = kstrtou32_from_user(user_buf, count, 0, ®_val); +++ if (ret) +++ goto exit; +++ +++ ath10k_hif_write32(ar, reg_addr, reg_val); +++ +++ ret = count; +++ +++exit: +++ mutex_unlock(&ar->conf_mutex); +++ +++ return ret; +++} +++ +++static const struct file_operations fops_reg_value = { +++ .read = ath10k_reg_value_read, +++ .write = ath10k_reg_value_write, +++ .open = simple_open, +++ .owner = THIS_MODULE, +++ .llseek = default_llseek, +++}; +++ +++static ssize_t ath10k_mem_value_read(struct file *file, +++ char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ath10k *ar = file->private_data; +++ u8 *buf; +++ int ret; +++ +++ if (*ppos < 0) +++ return -EINVAL; +++ +++ if (!count) +++ return 0; +++ +++ mutex_lock(&ar->conf_mutex); +++ +++ buf = vmalloc(count); +++ if (!buf) { +++ ret = -ENOMEM; +++ goto exit; +++ } +++ +++ if (ar->state != ATH10K_STATE_ON && +++ ar->state != ATH10K_STATE_UTF) { +++ ret = -ENETDOWN; +++ goto exit; +++ } +++ +++ ret = ath10k_hif_diag_read(ar, *ppos, buf, count); +++ if (ret) { +++ ath10k_warn(ar, "failed to read address 0x%08x via diagnose window fnrom debugfs: %d\n", +++ (u32)(*ppos), ret); +++ goto exit; +++ } +++ +++ ret = copy_to_user(user_buf, buf, count); +++ if (ret) { +++ ret = -EFAULT; +++ goto exit; +++ } +++ +++ count -= ret; +++ *ppos += count; +++ ret = count; +++ +++exit: +++ vfree(buf); +++ mutex_unlock(&ar->conf_mutex); +++ +++ return ret; +++} +++ +++static ssize_t ath10k_mem_value_write(struct file *file, +++ const char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ath10k *ar = file->private_data; +++ u8 *buf; +++ int ret; +++ +++ if (*ppos < 0) +++ return -EINVAL; +++ +++ if (!count) +++ return 0; +++ +++ mutex_lock(&ar->conf_mutex); +++ +++ buf = vmalloc(count); +++ if (!buf) { +++ ret = -ENOMEM; +++ goto exit; +++ } +++ +++ if (ar->state != ATH10K_STATE_ON && +++ ar->state != ATH10K_STATE_UTF) { +++ ret = -ENETDOWN; +++ goto exit; +++ } +++ +++ ret = copy_from_user(buf, user_buf, count); +++ if (ret) { +++ ret = -EFAULT; +++ goto exit; +++ } +++ +++ ret = ath10k_hif_diag_write(ar, *ppos, buf, count); +++ if (ret) { +++ ath10k_warn(ar, "failed to write address 0x%08x via diagnose window from debugfs: %d\n", +++ (u32)(*ppos), ret); +++ goto exit; +++ } +++ +++ *ppos += count; +++ ret = count; ++ ++- return simple_read_from_buffer(user_buf, count, ppos, buf, len); +++exit: +++ vfree(buf); +++ mutex_unlock(&ar->conf_mutex); +++ +++ return ret; ++ } ++ ++-static const struct file_operations fops_chip_id = { ++- .read = ath10k_read_chip_id, +++static const struct file_operations fops_mem_value = { +++ .read = ath10k_mem_value_read, +++ .write = ath10k_mem_value_write, ++ .open = simple_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++@@ -596,7 +1269,7 @@ static int ath10k_debug_htt_stats_req(st ++ ret = ath10k_htt_h2t_stats_req(&ar->htt, ar->debug.htt_stats_mask, ++ cookie); ++ if (ret) { ++- ath10k_warn("failed to send htt stats request: %d\n", ret); +++ ath10k_warn(ar, "failed to send htt stats request: %d\n", ret); ++ return ret; ++ } ++ ++@@ -619,8 +1292,8 @@ static void ath10k_debug_htt_stats_dwork ++ } ++ ++ static ssize_t ath10k_read_htt_stats_mask(struct file *file, ++- char __user *user_buf, ++- size_t count, loff_t *ppos) +++ char __user *user_buf, +++ size_t count, loff_t *ppos) ++ { ++ struct ath10k *ar = file->private_data; ++ char buf[32]; ++@@ -632,8 +1305,8 @@ static ssize_t ath10k_read_htt_stats_mas ++ } ++ ++ static ssize_t ath10k_write_htt_stats_mask(struct file *file, ++- const char __user *user_buf, ++- size_t count, loff_t *ppos) +++ const char __user *user_buf, +++ size_t count, loff_t *ppos) ++ { ++ struct ath10k *ar = file->private_data; ++ unsigned long mask; ++@@ -671,16 +1344,82 @@ static const struct file_operations fops ++ .llseek = default_llseek, ++ }; ++ +++static ssize_t ath10k_read_htt_max_amsdu_ampdu(struct file *file, +++ char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ath10k *ar = file->private_data; +++ char buf[64]; +++ u8 amsdu = 3, ampdu = 64; +++ unsigned int len; +++ +++ mutex_lock(&ar->conf_mutex); +++ +++ if (ar->debug.htt_max_amsdu) +++ amsdu = ar->debug.htt_max_amsdu; +++ +++ if (ar->debug.htt_max_ampdu) +++ ampdu = ar->debug.htt_max_ampdu; +++ +++ mutex_unlock(&ar->conf_mutex); +++ +++ len = scnprintf(buf, sizeof(buf), "%u %u\n", amsdu, ampdu); +++ +++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); +++} +++ +++static ssize_t ath10k_write_htt_max_amsdu_ampdu(struct file *file, +++ const char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ath10k *ar = file->private_data; +++ int res; +++ char buf[64]; +++ unsigned int amsdu, ampdu; +++ +++ simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); +++ +++ /* make sure that buf is null terminated */ +++ buf[sizeof(buf) - 1] = 0; +++ +++ res = sscanf(buf, "%u %u", &amsdu, &du); +++ +++ if (res != 2) +++ return -EINVAL; +++ +++ mutex_lock(&ar->conf_mutex); +++ +++ res = ath10k_htt_h2t_aggr_cfg_msg(&ar->htt, ampdu, amsdu); +++ if (res) +++ goto out; +++ +++ res = count; +++ ar->debug.htt_max_amsdu = amsdu; +++ ar->debug.htt_max_ampdu = ampdu; +++ +++out: +++ mutex_unlock(&ar->conf_mutex); +++ return res; +++} +++ +++static const struct file_operations fops_htt_max_amsdu_ampdu = { +++ .read = ath10k_read_htt_max_amsdu_ampdu, +++ .write = ath10k_write_htt_max_amsdu_ampdu, +++ .open = simple_open, +++ .owner = THIS_MODULE, +++ .llseek = default_llseek, +++}; +++ ++ static ssize_t ath10k_read_fw_dbglog(struct file *file, ++- char __user *user_buf, ++- size_t count, loff_t *ppos) +++ char __user *user_buf, +++ size_t count, loff_t *ppos) ++ { ++ struct ath10k *ar = file->private_data; ++ unsigned int len; ++- char buf[32]; +++ char buf[64]; ++ ++- len = scnprintf(buf, sizeof(buf), "0x%08x\n", ++- ar->debug.fw_dbglog_mask); +++ len = scnprintf(buf, sizeof(buf), "0x%08x %u\n", +++ ar->debug.fw_dbglog_mask, ar->debug.fw_dbglog_level); ++ ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ } ++@@ -690,21 +1429,34 @@ static ssize_t ath10k_write_fw_dbglog(st ++ size_t count, loff_t *ppos) ++ { ++ struct ath10k *ar = file->private_data; ++- unsigned long mask; ++ int ret; +++ char buf[64]; +++ unsigned int log_level, mask; ++ ++- ret = kstrtoul_from_user(user_buf, count, 0, &mask); ++- if (ret) ++- return ret; +++ simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); +++ +++ /* make sure that buf is null terminated */ +++ buf[sizeof(buf) - 1] = 0; +++ +++ ret = sscanf(buf, "%x %u", &mask, &log_level); +++ +++ if (!ret) +++ return -EINVAL; +++ +++ if (ret == 1) +++ /* default if user did not specify */ +++ log_level = ATH10K_DBGLOG_LEVEL_WARN; ++ ++ mutex_lock(&ar->conf_mutex); ++ ++ ar->debug.fw_dbglog_mask = mask; +++ ar->debug.fw_dbglog_level = log_level; ++ ++ if (ar->state == ATH10K_STATE_ON) { ++- ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask); +++ ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask, +++ ar->debug.fw_dbglog_level); ++ if (ret) { ++- ath10k_warn("dbglog cfg failed from debugfs: %d\n", +++ ath10k_warn(ar, "dbglog cfg failed from debugfs: %d\n", ++ ret); ++ goto exit; ++ } ++@@ -718,6 +1470,166 @@ exit: ++ return ret; ++ } ++ +++/* TODO: Would be nice to always support ethtool stats, would need to +++ * move the stats storage out of ath10k_debug, or always have ath10k_debug +++ * struct available.. +++ */ +++ +++/* This generally cooresponds to the debugfs fw_stats file */ +++static const char ath10k_gstrings_stats[][ETH_GSTRING_LEN] = { +++ "tx_pkts_nic", +++ "tx_bytes_nic", +++ "rx_pkts_nic", +++ "rx_bytes_nic", +++ "d_noise_floor", +++ "d_cycle_count", +++ "d_phy_error", +++ "d_rts_bad", +++ "d_rts_good", +++ "d_tx_power", /* in .5 dbM I think */ +++ "d_rx_crc_err", /* fcs_bad */ +++ "d_no_beacon", +++ "d_tx_mpdus_queued", +++ "d_tx_msdu_queued", +++ "d_tx_msdu_dropped", +++ "d_local_enqued", +++ "d_local_freed", +++ "d_tx_ppdu_hw_queued", +++ "d_tx_ppdu_reaped", +++ "d_tx_fifo_underrun", +++ "d_tx_ppdu_abort", +++ "d_tx_mpdu_requed", +++ "d_tx_excessive_retries", +++ "d_tx_hw_rate", +++ "d_tx_dropped_sw_retries", +++ "d_tx_illegal_rate", +++ "d_tx_continuous_xretries", +++ "d_tx_timeout", +++ "d_tx_mpdu_txop_limit", +++ "d_pdev_resets", +++ "d_rx_mid_ppdu_route_change", +++ "d_rx_status", +++ "d_rx_extra_frags_ring0", +++ "d_rx_extra_frags_ring1", +++ "d_rx_extra_frags_ring2", +++ "d_rx_extra_frags_ring3", +++ "d_rx_msdu_htt", +++ "d_rx_mpdu_htt", +++ "d_rx_msdu_stack", +++ "d_rx_mpdu_stack", +++ "d_rx_phy_err", +++ "d_rx_phy_err_drops", +++ "d_rx_mpdu_errors", /* FCS, MIC, ENC */ +++ "d_fw_crash_count", +++ "d_fw_warm_reset_count", +++ "d_fw_cold_reset_count", +++}; +++ +++#define ATH10K_SSTATS_LEN ARRAY_SIZE(ath10k_gstrings_stats) +++ +++void ath10k_debug_get_et_strings(struct ieee80211_hw *hw, +++ struct ieee80211_vif *vif, +++ u32 sset, u8 *data) +++{ +++ if (sset == ETH_SS_STATS) +++ memcpy(data, *ath10k_gstrings_stats, +++ sizeof(ath10k_gstrings_stats)); +++} +++ +++int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw, +++ struct ieee80211_vif *vif, int sset) +++{ +++ if (sset == ETH_SS_STATS) +++ return ATH10K_SSTATS_LEN; +++ +++ return 0; +++} +++ +++void ath10k_debug_get_et_stats(struct ieee80211_hw *hw, +++ struct ieee80211_vif *vif, +++ struct ethtool_stats *stats, u64 *data) +++{ +++ struct ath10k *ar = hw->priv; +++ static const struct ath10k_fw_stats_pdev zero_stats = {}; +++ const struct ath10k_fw_stats_pdev *pdev_stats; +++ int i = 0, ret; +++ +++ mutex_lock(&ar->conf_mutex); +++ +++ if (ar->state == ATH10K_STATE_ON) { +++ ret = ath10k_debug_fw_stats_request(ar); +++ if (ret) { +++ /* just print a warning and try to use older results */ +++ ath10k_warn(ar, +++ "failed to get fw stats for ethtool: %d\n", +++ ret); +++ } +++ } +++ +++ pdev_stats = list_first_entry_or_null(&ar->debug.fw_stats.pdevs, +++ struct ath10k_fw_stats_pdev, +++ list); +++ if (!pdev_stats) { +++ /* no results available so just return zeroes */ +++ pdev_stats = &zero_stats; +++ } +++ +++ spin_lock_bh(&ar->data_lock); +++ +++ data[i++] = pdev_stats->hw_reaped; /* ppdu reaped */ +++ data[i++] = 0; /* tx bytes */ +++ data[i++] = pdev_stats->htt_mpdus; +++ data[i++] = 0; /* rx bytes */ +++ data[i++] = pdev_stats->ch_noise_floor; +++ data[i++] = pdev_stats->cycle_count; +++ data[i++] = pdev_stats->phy_err_count; +++ data[i++] = pdev_stats->rts_bad; +++ data[i++] = pdev_stats->rts_good; +++ data[i++] = pdev_stats->chan_tx_power; +++ data[i++] = pdev_stats->fcs_bad; +++ data[i++] = pdev_stats->no_beacons; +++ data[i++] = pdev_stats->mpdu_enqued; +++ data[i++] = pdev_stats->msdu_enqued; +++ data[i++] = pdev_stats->wmm_drop; +++ data[i++] = pdev_stats->local_enqued; +++ data[i++] = pdev_stats->local_freed; +++ data[i++] = pdev_stats->hw_queued; +++ data[i++] = pdev_stats->hw_reaped; +++ data[i++] = pdev_stats->underrun; +++ data[i++] = pdev_stats->tx_abort; +++ data[i++] = pdev_stats->mpdus_requed; +++ data[i++] = pdev_stats->tx_ko; +++ data[i++] = pdev_stats->data_rc; +++ data[i++] = pdev_stats->sw_retry_failure; +++ data[i++] = pdev_stats->illgl_rate_phy_err; +++ data[i++] = pdev_stats->pdev_cont_xretry; +++ data[i++] = pdev_stats->pdev_tx_timeout; +++ data[i++] = pdev_stats->txop_ovf; +++ data[i++] = pdev_stats->pdev_resets; +++ data[i++] = pdev_stats->mid_ppdu_route_change; +++ data[i++] = pdev_stats->status_rcvd; +++ data[i++] = pdev_stats->r0_frags; +++ data[i++] = pdev_stats->r1_frags; +++ data[i++] = pdev_stats->r2_frags; +++ data[i++] = pdev_stats->r3_frags; +++ data[i++] = pdev_stats->htt_msdus; +++ data[i++] = pdev_stats->htt_mpdus; +++ data[i++] = pdev_stats->loc_msdus; +++ data[i++] = pdev_stats->loc_mpdus; +++ data[i++] = pdev_stats->phy_errs; +++ data[i++] = pdev_stats->phy_err_drop; +++ data[i++] = pdev_stats->mpdu_errs; +++ data[i++] = ar->stats.fw_crash_counter; +++ data[i++] = ar->stats.fw_warm_reset_counter; +++ data[i++] = ar->stats.fw_cold_reset_counter; +++ +++ spin_unlock_bh(&ar->data_lock); +++ +++ mutex_unlock(&ar->conf_mutex); +++ +++ WARN_ON(i != ATH10K_SSTATS_LEN); +++} +++ ++ static const struct file_operations fops_fw_dbglog = { ++ .read = ath10k_read_fw_dbglog, ++ .write = ath10k_write_fw_dbglog, ++@@ -726,6 +1638,151 @@ static const struct file_operations fops ++ .llseek = default_llseek, ++ }; ++ +++static int ath10k_debug_cal_data_open(struct inode *inode, struct file *file) +++{ +++ struct ath10k *ar = inode->i_private; +++ void *buf; +++ u32 hi_addr; +++ __le32 addr; +++ int ret; +++ +++ mutex_lock(&ar->conf_mutex); +++ +++ if (ar->state != ATH10K_STATE_ON && +++ ar->state != ATH10K_STATE_UTF) { +++ ret = -ENETDOWN; +++ goto err; +++ } +++ +++ buf = vmalloc(QCA988X_CAL_DATA_LEN); +++ if (!buf) { +++ ret = -ENOMEM; +++ goto err; +++ } +++ +++ hi_addr = host_interest_item_address(HI_ITEM(hi_board_data)); +++ +++ ret = ath10k_hif_diag_read(ar, hi_addr, &addr, sizeof(addr)); +++ if (ret) { +++ ath10k_warn(ar, "failed to read hi_board_data address: %d\n", ret); +++ goto err_vfree; +++ } +++ +++ ret = ath10k_hif_diag_read(ar, le32_to_cpu(addr), buf, +++ QCA988X_CAL_DATA_LEN); +++ if (ret) { +++ ath10k_warn(ar, "failed to read calibration data: %d\n", ret); +++ goto err_vfree; +++ } +++ +++ file->private_data = buf; +++ +++ mutex_unlock(&ar->conf_mutex); +++ +++ return 0; +++ +++err_vfree: +++ vfree(buf); +++ +++err: +++ mutex_unlock(&ar->conf_mutex); +++ +++ return ret; +++} +++ +++static ssize_t ath10k_debug_cal_data_read(struct file *file, +++ char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ void *buf = file->private_data; +++ +++ return simple_read_from_buffer(user_buf, count, ppos, +++ buf, QCA988X_CAL_DATA_LEN); +++} +++ +++static int ath10k_debug_cal_data_release(struct inode *inode, +++ struct file *file) +++{ +++ vfree(file->private_data); +++ +++ return 0; +++} +++ +++static const struct file_operations fops_cal_data = { +++ .open = ath10k_debug_cal_data_open, +++ .read = ath10k_debug_cal_data_read, +++ .release = ath10k_debug_cal_data_release, +++ .owner = THIS_MODULE, +++ .llseek = default_llseek, +++}; +++ +++static ssize_t ath10k_read_nf_cal_period(struct file *file, +++ char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ath10k *ar = file->private_data; +++ unsigned int len; +++ char buf[32]; +++ +++ len = scnprintf(buf, sizeof(buf), "%d\n", +++ ar->debug.nf_cal_period); +++ +++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); +++} +++ +++static ssize_t ath10k_write_nf_cal_period(struct file *file, +++ const char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ath10k *ar = file->private_data; +++ unsigned long period; +++ int ret; +++ +++ ret = kstrtoul_from_user(user_buf, count, 0, &period); +++ if (ret) +++ return ret; +++ +++ if (period > WMI_PDEV_PARAM_CAL_PERIOD_MAX) +++ return -EINVAL; +++ +++ /* there's no way to switch back to the firmware default */ +++ if (period == 0) +++ return -EINVAL; +++ +++ mutex_lock(&ar->conf_mutex); +++ +++ ar->debug.nf_cal_period = period; +++ +++ if (ar->state != ATH10K_STATE_ON) { +++ /* firmware is not running, nothing else to do */ +++ ret = count; +++ goto exit; +++ } +++ +++ ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->cal_period, +++ ar->debug.nf_cal_period); +++ if (ret) { +++ ath10k_warn(ar, "cal period cfg failed from debugfs: %d\n", +++ ret); +++ goto exit; +++ } +++ +++ ret = count; +++ +++exit: +++ mutex_unlock(&ar->conf_mutex); +++ +++ return ret; +++} +++ +++static const struct file_operations fops_nf_cal_period = { +++ .read = ath10k_read_nf_cal_period, +++ .write = ath10k_write_nf_cal_period, +++ .open = simple_open, +++ .owner = THIS_MODULE, +++ .llseek = default_llseek, +++}; +++ ++ int ath10k_debug_start(struct ath10k *ar) ++ { ++ int ret; ++@@ -735,17 +1792,44 @@ int ath10k_debug_start(struct ath10k *ar ++ ret = ath10k_debug_htt_stats_req(ar); ++ if (ret) ++ /* continue normally anyway, this isn't serious */ ++- ath10k_warn("failed to start htt stats workqueue: %d\n", ret); +++ ath10k_warn(ar, "failed to start htt stats workqueue: %d\n", +++ ret); ++ ++ if (ar->debug.fw_dbglog_mask) { ++- ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask); +++ ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask, +++ ATH10K_DBGLOG_LEVEL_WARN); ++ if (ret) ++ /* not serious */ ++- ath10k_warn("failed to enable dbglog during start: %d", +++ ath10k_warn(ar, "failed to enable dbglog during start: %d", ++ ret); ++ } ++ ++- return 0; +++ if (ar->debug.pktlog_filter) { +++ ret = ath10k_wmi_pdev_pktlog_enable(ar, +++ ar->debug.pktlog_filter); +++ if (ret) +++ /* not serious */ +++ ath10k_warn(ar, +++ "failed to enable pktlog filter %x: %d\n", +++ ar->debug.pktlog_filter, ret); +++ } else { +++ ret = ath10k_wmi_pdev_pktlog_disable(ar); +++ if (ret) +++ /* not serious */ +++ ath10k_warn(ar, "failed to disable pktlog: %d\n", ret); +++ } +++ +++ if (ar->debug.nf_cal_period) { +++ ret = ath10k_wmi_pdev_set_param(ar, +++ ar->wmi.pdev_param->cal_period, +++ ar->debug.nf_cal_period); +++ if (ret) +++ /* not serious */ +++ ath10k_warn(ar, "cal period cfg failed from debug start: %d\n", +++ ret); +++ } +++ +++ return ret; ++ } ++ ++ void ath10k_debug_stop(struct ath10k *ar) ++@@ -757,6 +1841,11 @@ void ath10k_debug_stop(struct ath10k *ar ++ * warning from del_timer(). */ ++ if (ar->debug.htt_stats_mask != 0) ++ cancel_delayed_work(&ar->debug.htt_stats_dwork); +++ +++ ar->debug.htt_max_amsdu = 0; +++ ar->debug.htt_max_ampdu = 0; +++ +++ ath10k_wmi_pdev_pktlog_disable(ar); ++ } ++ ++ static ssize_t ath10k_write_simulate_radar(struct file *file, ++@@ -839,37 +1928,149 @@ static const struct file_operations fops ++ .llseek = default_llseek, ++ }; ++ +++static ssize_t ath10k_write_pktlog_filter(struct file *file, +++ const char __user *ubuf, +++ size_t count, loff_t *ppos) +++{ +++ struct ath10k *ar = file->private_data; +++ u32 filter; +++ int ret; +++ +++ if (kstrtouint_from_user(ubuf, count, 0, &filter)) +++ return -EINVAL; +++ +++ mutex_lock(&ar->conf_mutex); +++ +++ if (ar->state != ATH10K_STATE_ON) { +++ ar->debug.pktlog_filter = filter; +++ ret = count; +++ goto out; +++ } +++ +++ if (filter && (filter != ar->debug.pktlog_filter)) { +++ ret = ath10k_wmi_pdev_pktlog_enable(ar, filter); +++ if (ret) { +++ ath10k_warn(ar, "failed to enable pktlog filter %x: %d\n", +++ ar->debug.pktlog_filter, ret); +++ goto out; +++ } +++ } else { +++ ret = ath10k_wmi_pdev_pktlog_disable(ar); +++ if (ret) { +++ ath10k_warn(ar, "failed to disable pktlog: %d\n", ret); +++ goto out; +++ } +++ } +++ +++ ar->debug.pktlog_filter = filter; +++ ret = count; +++ +++out: +++ mutex_unlock(&ar->conf_mutex); +++ return ret; +++} +++ +++static ssize_t ath10k_read_pktlog_filter(struct file *file, char __user *ubuf, +++ size_t count, loff_t *ppos) +++{ +++ char buf[32]; +++ struct ath10k *ar = file->private_data; +++ int len = 0; +++ +++ mutex_lock(&ar->conf_mutex); +++ len = scnprintf(buf, sizeof(buf) - len, "%08x\n", +++ ar->debug.pktlog_filter); +++ mutex_unlock(&ar->conf_mutex); +++ +++ return simple_read_from_buffer(ubuf, count, ppos, buf, len); +++} +++ +++static const struct file_operations fops_pktlog_filter = { +++ .read = ath10k_read_pktlog_filter, +++ .write = ath10k_write_pktlog_filter, +++ .open = simple_open +++}; +++ ++ int ath10k_debug_create(struct ath10k *ar) ++ { +++ ar->debug.fw_crash_data = vzalloc(sizeof(*ar->debug.fw_crash_data)); +++ if (!ar->debug.fw_crash_data) +++ return -ENOMEM; +++ +++ INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs); +++ INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs); +++ INIT_LIST_HEAD(&ar->debug.fw_stats.peers); +++ +++ return 0; +++} +++ +++void ath10k_debug_destroy(struct ath10k *ar) +++{ +++ vfree(ar->debug.fw_crash_data); +++ ar->debug.fw_crash_data = NULL; +++ +++ ath10k_debug_fw_stats_reset(ar); +++} +++ +++int ath10k_debug_register(struct ath10k *ar) +++{ ++ ar->debug.debugfs_phy = debugfs_create_dir("ath10k", ++ ar->hw->wiphy->debugfsdir); +++ if (IS_ERR_OR_NULL(ar->debug.debugfs_phy)) { +++ if (IS_ERR(ar->debug.debugfs_phy)) +++ return PTR_ERR(ar->debug.debugfs_phy); ++ ++- if (!ar->debug.debugfs_phy) ++ return -ENOMEM; +++ } ++ ++ INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork, ++ ath10k_debug_htt_stats_dwork); ++ ++- init_completion(&ar->debug.event_stats_compl); +++ init_completion(&ar->debug.fw_stats_complete); ++ ++ debugfs_create_file("fw_stats", S_IRUSR, ar->debug.debugfs_phy, ar, ++ &fops_fw_stats); ++ +++ debugfs_create_file("fw_reset_stats", S_IRUSR, ar->debug.debugfs_phy, +++ ar, &fops_fw_reset_stats); +++ ++ debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar, ++ &fops_wmi_services); ++ ++ debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy, ++ ar, &fops_simulate_fw_crash); ++ +++ debugfs_create_file("fw_crash_dump", S_IRUSR, ar->debug.debugfs_phy, +++ ar, &fops_fw_crash_dump); +++ +++ debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR, +++ ar->debug.debugfs_phy, ar, &fops_reg_addr); +++ +++ debugfs_create_file("reg_value", S_IRUSR | S_IWUSR, +++ ar->debug.debugfs_phy, ar, &fops_reg_value); +++ +++ debugfs_create_file("mem_value", S_IRUSR | S_IWUSR, +++ ar->debug.debugfs_phy, ar, &fops_mem_value); +++ ++ debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy, ++ ar, &fops_chip_id); ++ ++ debugfs_create_file("htt_stats_mask", S_IRUSR, ar->debug.debugfs_phy, ++ ar, &fops_htt_stats_mask); ++ +++ debugfs_create_file("htt_max_amsdu_ampdu", S_IRUSR | S_IWUSR, +++ ar->debug.debugfs_phy, ar, +++ &fops_htt_max_amsdu_ampdu); +++ ++ debugfs_create_file("fw_dbglog", S_IRUSR, ar->debug.debugfs_phy, ++ ar, &fops_fw_dbglog); ++ +++ debugfs_create_file("cal_data", S_IRUSR, ar->debug.debugfs_phy, +++ ar, &fops_cal_data); +++ +++ debugfs_create_file("nf_cal_period", S_IRUSR | S_IWUSR, +++ ar->debug.debugfs_phy, ar, &fops_nf_cal_period); +++ ++ if (config_enabled(CPTCFG_ATH10K_DFS_CERTIFIED)) { ++ debugfs_create_file("dfs_simulate_radar", S_IWUSR, ++ ar->debug.debugfs_phy, ar, ++@@ -884,10 +2085,13 @@ int ath10k_debug_create(struct ath10k *a ++ &fops_dfs_stats); ++ } ++ +++ debugfs_create_file("pktlog_filter", S_IRUGO | S_IWUSR, +++ ar->debug.debugfs_phy, ar, &fops_pktlog_filter); +++ ++ return 0; ++ } ++ ++-void ath10k_debug_destroy(struct ath10k *ar) +++void ath10k_debug_unregister(struct ath10k *ar) ++ { ++ cancel_delayed_work_sync(&ar->debug.htt_stats_dwork); ++ } ++@@ -895,7 +2099,8 @@ void ath10k_debug_destroy(struct ath10k ++ #endif /* CPTCFG_ATH10K_DEBUGFS */ ++ ++ #ifdef CPTCFG_ATH10K_DEBUG ++-void ath10k_dbg(enum ath10k_debug_mask mask, const char *fmt, ...) +++void ath10k_dbg(struct ath10k *ar, enum ath10k_debug_mask mask, +++ const char *fmt, ...) ++ { ++ struct va_format vaf; ++ va_list args; ++@@ -906,27 +2111,43 @@ void ath10k_dbg(enum ath10k_debug_mask m ++ vaf.va = &args; ++ ++ if (ath10k_debug_mask & mask) ++- ath10k_printk(KERN_DEBUG, "%pV", &vaf); +++ dev_printk(KERN_DEBUG, ar->dev, "%pV", &vaf); ++ ++- trace_ath10k_log_dbg(mask, &vaf); +++ trace_ath10k_log_dbg(ar, mask, &vaf); ++ ++ va_end(args); ++ } ++ EXPORT_SYMBOL(ath10k_dbg); ++ ++-void ath10k_dbg_dump(enum ath10k_debug_mask mask, +++void ath10k_dbg_dump(struct ath10k *ar, +++ enum ath10k_debug_mask mask, ++ const char *msg, const char *prefix, ++ const void *buf, size_t len) ++ { +++ char linebuf[256]; +++ unsigned int linebuflen; +++ const void *ptr; +++ ++ if (ath10k_debug_mask & mask) { ++ if (msg) ++- ath10k_dbg(mask, "%s\n", msg); +++ ath10k_dbg(ar, mask, "%s\n", msg); ++ ++- print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len); +++ for (ptr = buf; (ptr - buf) < len; ptr += 16) { +++ linebuflen = 0; +++ linebuflen += scnprintf(linebuf + linebuflen, +++ sizeof(linebuf) - linebuflen, +++ "%s%08x: ", +++ (prefix ? prefix : ""), +++ (unsigned int)(ptr - buf)); +++ hex_dump_to_buffer(ptr, len - (ptr - buf), 16, 1, +++ linebuf + linebuflen, +++ sizeof(linebuf) - linebuflen, true); +++ dev_printk(KERN_DEBUG, ar->dev, "%s\n", linebuf); +++ } ++ } ++ ++ /* tracing code doesn't like null strings :/ */ ++- trace_ath10k_log_dbg_dump(msg ? msg : "", prefix ? prefix : "", +++ trace_ath10k_log_dbg_dump(ar, msg ? msg : "", prefix ? prefix : "", ++ buf, len); ++ } ++ EXPORT_SYMBOL(ath10k_dbg_dump); ++--- a/drivers/net/wireless/ath/ath10k/debug.h +++++ b/drivers/net/wireless/ath/ath10k/debug.h ++@@ -34,28 +34,55 @@ enum ath10k_debug_mask { ++ ATH10K_DBG_DATA = 0x00000200, ++ ATH10K_DBG_BMI = 0x00000400, ++ ATH10K_DBG_REGULATORY = 0x00000800, +++ ATH10K_DBG_TESTMODE = 0x00001000, +++ ATH10K_DBG_WMI_PRINT = 0x00002000, ++ ATH10K_DBG_ANY = 0xffffffff, ++ }; ++ +++enum ath10k_pktlog_filter { +++ ATH10K_PKTLOG_RX = 0x000000001, +++ ATH10K_PKTLOG_TX = 0x000000002, +++ ATH10K_PKTLOG_RCFIND = 0x000000004, +++ ATH10K_PKTLOG_RCUPDATE = 0x000000008, +++ ATH10K_PKTLOG_DBG_PRINT = 0x000000010, +++ ATH10K_PKTLOG_ANY = 0x00000001f, +++}; +++ +++enum ath10k_dbg_aggr_mode { +++ ATH10K_DBG_AGGR_MODE_AUTO, +++ ATH10K_DBG_AGGR_MODE_MANUAL, +++ ATH10K_DBG_AGGR_MODE_MAX, +++}; +++ ++ extern unsigned int ath10k_debug_mask; ++ ++-__printf(1, 2) int ath10k_info(const char *fmt, ...); ++-__printf(1, 2) int ath10k_err(const char *fmt, ...); ++-__printf(1, 2) int ath10k_warn(const char *fmt, ...); +++__printf(2, 3) void ath10k_info(struct ath10k *ar, const char *fmt, ...); +++__printf(2, 3) void ath10k_err(struct ath10k *ar, const char *fmt, ...); +++__printf(2, 3) void ath10k_warn(struct ath10k *ar, const char *fmt, ...); +++void ath10k_print_driver_info(struct ath10k *ar); ++ ++ #ifdef CPTCFG_ATH10K_DEBUGFS ++ int ath10k_debug_start(struct ath10k *ar); ++ void ath10k_debug_stop(struct ath10k *ar); ++ int ath10k_debug_create(struct ath10k *ar); ++ void ath10k_debug_destroy(struct ath10k *ar); ++-void ath10k_debug_read_service_map(struct ath10k *ar, ++- void *service_map, ++- size_t map_size); ++-void ath10k_debug_read_target_stats(struct ath10k *ar, ++- struct wmi_stats_event *ev); +++int ath10k_debug_register(struct ath10k *ar); +++void ath10k_debug_unregister(struct ath10k *ar); +++void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb); +++struct ath10k_fw_crash_data * +++ath10k_debug_get_new_fw_crash_data(struct ath10k *ar); ++ +++void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len); ++ #define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++) ++ +++void ath10k_debug_get_et_strings(struct ieee80211_hw *hw, +++ struct ieee80211_vif *vif, +++ u32 sset, u8 *data); +++int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw, +++ struct ieee80211_vif *vif, int sset); +++void ath10k_debug_get_et_stats(struct ieee80211_hw *hw, +++ struct ieee80211_vif *vif, +++ struct ethtool_stats *stats, u64 *data); ++ #else ++ static inline int ath10k_debug_start(struct ath10k *ar) ++ { ++@@ -75,36 +102,62 @@ static inline void ath10k_debug_destroy( ++ { ++ } ++ ++-static inline void ath10k_debug_read_service_map(struct ath10k *ar, ++- void *service_map, ++- size_t map_size) +++static inline int ath10k_debug_register(struct ath10k *ar) +++{ +++ return 0; +++} +++ +++static inline void ath10k_debug_unregister(struct ath10k *ar) ++ { ++ } ++ ++-static inline void ath10k_debug_read_target_stats(struct ath10k *ar, ++- struct wmi_stats_event *ev) +++static inline void ath10k_debug_fw_stats_process(struct ath10k *ar, +++ struct sk_buff *skb) ++ { ++ } ++ +++static inline void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, +++ int len) +++{ +++} +++ +++static inline struct ath10k_fw_crash_data * +++ath10k_debug_get_new_fw_crash_data(struct ath10k *ar) +++{ +++ return NULL; +++} +++ ++ #define ATH10K_DFS_STAT_INC(ar, c) do { } while (0) ++ +++#define ath10k_debug_get_et_strings NULL +++#define ath10k_debug_get_et_sset_count NULL +++#define ath10k_debug_get_et_stats NULL +++ ++ #endif /* CPTCFG_ATH10K_DEBUGFS */ +++#ifdef CPTCFG_MAC80211_DEBUGFS +++void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +++ struct ieee80211_sta *sta, struct dentry *dir); +++#endif /* CPTCFG_MAC80211_DEBUGFS */ ++ ++ #ifdef CPTCFG_ATH10K_DEBUG ++-__printf(2, 3) void ath10k_dbg(enum ath10k_debug_mask mask, +++__printf(3, 4) void ath10k_dbg(struct ath10k *ar, +++ enum ath10k_debug_mask mask, ++ const char *fmt, ...); ++-void ath10k_dbg_dump(enum ath10k_debug_mask mask, +++void ath10k_dbg_dump(struct ath10k *ar, +++ enum ath10k_debug_mask mask, ++ const char *msg, const char *prefix, ++ const void *buf, size_t len); ++ #else /* CPTCFG_ATH10K_DEBUG */ ++ ++-static inline int ath10k_dbg(enum ath10k_debug_mask dbg_mask, +++static inline int ath10k_dbg(struct ath10k *ar, +++ enum ath10k_debug_mask dbg_mask, ++ const char *fmt, ...) ++ { ++ return 0; ++ } ++ ++-static inline void ath10k_dbg_dump(enum ath10k_debug_mask mask, +++static inline void ath10k_dbg_dump(struct ath10k *ar, +++ enum ath10k_debug_mask mask, ++ const char *msg, const char *prefix, ++ const void *buf, size_t len) ++ { ++--- a/drivers/net/wireless/ath/ath10k/hif.h +++++ b/drivers/net/wireless/ath/ath10k/hif.h ++@@ -20,6 +20,7 @@ ++ ++ #include ++ #include "core.h" +++#include "debug.h" ++ ++ struct ath10k_hif_sg_item { ++ u16 transfer_id; ++@@ -31,11 +32,9 @@ struct ath10k_hif_sg_item { ++ ++ struct ath10k_hif_cb { ++ int (*tx_completion)(struct ath10k *ar, ++- struct sk_buff *wbuf, ++- unsigned transfer_id); +++ struct sk_buff *wbuf); ++ int (*rx_completion)(struct ath10k *ar, ++- struct sk_buff *wbuf, ++- u8 pipe_id); +++ struct sk_buff *wbuf); ++ }; ++ ++ struct ath10k_hif_ops { ++@@ -43,6 +42,12 @@ struct ath10k_hif_ops { ++ int (*tx_sg)(struct ath10k *ar, u8 pipe_id, ++ struct ath10k_hif_sg_item *items, int n_items); ++ +++ /* read firmware memory through the diagnose interface */ +++ int (*diag_read)(struct ath10k *ar, u32 address, void *buf, +++ size_t buf_len); +++ +++ int (*diag_write)(struct ath10k *ar, u32 address, const void *data, +++ int nbytes); ++ /* ++ * API to handle HIF-specific BMI message exchanges, this API is ++ * synchronous and only allowed to be called from a context that ++@@ -80,6 +85,10 @@ struct ath10k_hif_ops { ++ ++ u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id); ++ +++ u32 (*read32)(struct ath10k *ar, u32 address); +++ +++ void (*write32)(struct ath10k *ar, u32 address, u32 value); +++ ++ /* Power up the device and enter BMI transfer mode for FW download */ ++ int (*power_up)(struct ath10k *ar); ++ ++@@ -91,7 +100,6 @@ struct ath10k_hif_ops { ++ int (*resume)(struct ath10k *ar); ++ }; ++ ++- ++ static inline int ath10k_hif_tx_sg(struct ath10k *ar, u8 pipe_id, ++ struct ath10k_hif_sg_item *items, ++ int n_items) ++@@ -99,6 +107,21 @@ static inline int ath10k_hif_tx_sg(struc ++ return ar->hif.ops->tx_sg(ar, pipe_id, items, n_items); ++ } ++ +++static inline int ath10k_hif_diag_read(struct ath10k *ar, u32 address, void *buf, +++ size_t buf_len) +++{ +++ return ar->hif.ops->diag_read(ar, address, buf, buf_len); +++} +++ +++static inline int ath10k_hif_diag_write(struct ath10k *ar, u32 address, +++ const void *data, int nbytes) +++{ +++ if (!ar->hif.ops->diag_write) +++ return -EOPNOTSUPP; +++ +++ return ar->hif.ops->diag_write(ar, address, data, nbytes); +++} +++ ++ static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar, ++ void *request, u32 request_len, ++ void *response, u32 *response_len) ++@@ -178,4 +201,25 @@ static inline int ath10k_hif_resume(stru ++ return ar->hif.ops->resume(ar); ++ } ++ +++static inline u32 ath10k_hif_read32(struct ath10k *ar, u32 address) +++{ +++ if (!ar->hif.ops->read32) { +++ ath10k_warn(ar, "hif read32 not supported\n"); +++ return 0xdeaddead; +++ } +++ +++ return ar->hif.ops->read32(ar, address); +++} +++ +++static inline void ath10k_hif_write32(struct ath10k *ar, +++ u32 address, u32 data) +++{ +++ if (!ar->hif.ops->write32) { +++ ath10k_warn(ar, "hif write32 not supported\n"); +++ return; +++ } +++ +++ ar->hif.ops->write32(ar, address, data); +++} +++ ++ #endif /* _HIF_H_ */ ++--- a/drivers/net/wireless/ath/ath10k/htc.c +++++ b/drivers/net/wireless/ath/ath10k/htc.c ++@@ -45,10 +45,8 @@ static struct sk_buff *ath10k_htc_build_ ++ struct ath10k_skb_cb *skb_cb; ++ ++ skb = dev_alloc_skb(ATH10K_HTC_CONTROL_BUFFER_SIZE); ++- if (!skb) { ++- ath10k_warn("Unable to allocate ctrl skb\n"); +++ if (!skb) ++ return NULL; ++- } ++ ++ skb_reserve(skb, 20); /* FIXME: why 20 bytes? */ ++ WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb"); ++@@ -56,7 +54,7 @@ static struct sk_buff *ath10k_htc_build_ ++ skb_cb = ATH10K_SKB_CB(skb); ++ memset(skb_cb, 0, sizeof(*skb_cb)); ++ ++- ath10k_dbg(ATH10K_DBG_HTC, "%s: skb %p\n", __func__, skb); +++ ath10k_dbg(ar, ATH10K_DBG_HTC, "%s: skb %p\n", __func__, skb); ++ return skb; ++ } ++ ++@@ -72,13 +70,15 @@ static inline void ath10k_htc_restore_tx ++ static void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep, ++ struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_HTC, "%s: ep %d skb %p\n", __func__, +++ struct ath10k *ar = ep->htc->ar; +++ +++ ath10k_dbg(ar, ATH10K_DBG_HTC, "%s: ep %d skb %p\n", __func__, ++ ep->eid, skb); ++ ++ ath10k_htc_restore_tx_skb(ep->htc, skb); ++ ++ if (!ep->ep_ops.ep_tx_complete) { ++- ath10k_warn("no tx handler for eid %d\n", ep->eid); +++ ath10k_warn(ar, "no tx handler for eid %d\n", ep->eid); ++ dev_kfree_skb_any(skb); ++ return; ++ } ++@@ -89,12 +89,14 @@ static void ath10k_htc_notify_tx_complet ++ /* assumes tx_lock is held */ ++ static bool ath10k_htc_ep_need_credit_update(struct ath10k_htc_ep *ep) ++ { +++ struct ath10k *ar = ep->htc->ar; +++ ++ if (!ep->tx_credit_flow_enabled) ++ return false; ++ if (ep->tx_credits >= ep->tx_credits_per_max_message) ++ return false; ++ ++- ath10k_dbg(ATH10K_DBG_HTC, "HTC: endpoint %d needs credit update\n", +++ ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC: endpoint %d needs credit update\n", ++ ep->eid); ++ return true; ++ } ++@@ -123,6 +125,7 @@ int ath10k_htc_send(struct ath10k_htc *h ++ enum ath10k_htc_ep_id eid, ++ struct sk_buff *skb) ++ { +++ struct ath10k *ar = htc->ar; ++ struct ath10k_htc_ep *ep = &htc->endpoint[eid]; ++ struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb); ++ struct ath10k_hif_sg_item sg_item; ++@@ -134,18 +137,10 @@ int ath10k_htc_send(struct ath10k_htc *h ++ return -ECOMM; ++ ++ if (eid >= ATH10K_HTC_EP_COUNT) { ++- ath10k_warn("Invalid endpoint id: %d\n", eid); +++ ath10k_warn(ar, "Invalid endpoint id: %d\n", eid); ++ return -ENOENT; ++ } ++ ++- /* FIXME: This looks ugly, can we fix it? */ ++- spin_lock_bh(&htc->tx_lock); ++- if (htc->stopped) { ++- spin_unlock_bh(&htc->tx_lock); ++- return -ESHUTDOWN; ++- } ++- spin_unlock_bh(&htc->tx_lock); ++- ++ skb_push(skb, sizeof(struct ath10k_htc_hdr)); ++ ++ if (ep->tx_credit_flow_enabled) { ++@@ -157,7 +152,7 @@ int ath10k_htc_send(struct ath10k_htc *h ++ goto err_pull; ++ } ++ ep->tx_credits -= credits; ++- ath10k_dbg(ATH10K_DBG_HTC, +++ ath10k_dbg(ar, ATH10K_DBG_HTC, ++ "htc ep %d consumed %d credits (total %d)\n", ++ eid, credits, ep->tx_credits); ++ spin_unlock_bh(&htc->tx_lock); ++@@ -165,6 +160,7 @@ int ath10k_htc_send(struct ath10k_htc *h ++ ++ ath10k_htc_prepare_tx_skb(ep, skb); ++ +++ skb_cb->eid = eid; ++ skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE); ++ ret = dma_mapping_error(dev, skb_cb->paddr); ++ if (ret) ++@@ -188,7 +184,7 @@ err_credits: ++ if (ep->tx_credit_flow_enabled) { ++ spin_lock_bh(&htc->tx_lock); ++ ep->tx_credits += credits; ++- ath10k_dbg(ATH10K_DBG_HTC, +++ ath10k_dbg(ar, ATH10K_DBG_HTC, ++ "htc ep %d reverted %d credits back (total %d)\n", ++ eid, credits, ep->tx_credits); ++ spin_unlock_bh(&htc->tx_lock); ++@@ -202,15 +198,18 @@ err_pull: ++ } ++ ++ static int ath10k_htc_tx_completion_handler(struct ath10k *ar, ++- struct sk_buff *skb, ++- unsigned int eid) +++ struct sk_buff *skb) ++ { ++ struct ath10k_htc *htc = &ar->htc; ++- struct ath10k_htc_ep *ep = &htc->endpoint[eid]; +++ struct ath10k_skb_cb *skb_cb; +++ struct ath10k_htc_ep *ep; ++ ++ if (WARN_ON_ONCE(!skb)) ++ return 0; ++ +++ skb_cb = ATH10K_SKB_CB(skb); +++ ep = &htc->endpoint[skb_cb->eid]; +++ ++ ath10k_htc_notify_tx_completion(ep, skb); ++ /* the skb now belongs to the completion handler */ ++ ++@@ -227,11 +226,12 @@ ath10k_htc_process_credit_report(struct ++ int len, ++ enum ath10k_htc_ep_id eid) ++ { +++ struct ath10k *ar = htc->ar; ++ struct ath10k_htc_ep *ep; ++ int i, n_reports; ++ ++ if (len % sizeof(*report)) ++- ath10k_warn("Uneven credit report len %d", len); +++ ath10k_warn(ar, "Uneven credit report len %d", len); ++ ++ n_reports = len / sizeof(*report); ++ ++@@ -243,7 +243,7 @@ ath10k_htc_process_credit_report(struct ++ ep = &htc->endpoint[report->eid]; ++ ep->tx_credits += report->credits; ++ ++- ath10k_dbg(ATH10K_DBG_HTC, "htc ep %d got %d credits (total %d)\n", +++ ath10k_dbg(ar, ATH10K_DBG_HTC, "htc ep %d got %d credits (total %d)\n", ++ report->eid, report->credits, ep->tx_credits); ++ ++ if (ep->ep_ops.ep_tx_credits) { ++@@ -260,6 +260,7 @@ static int ath10k_htc_process_trailer(st ++ int length, ++ enum ath10k_htc_ep_id src_eid) ++ { +++ struct ath10k *ar = htc->ar; ++ int status = 0; ++ struct ath10k_htc_record *record; ++ u8 *orig_buffer; ++@@ -279,7 +280,7 @@ static int ath10k_htc_process_trailer(st ++ ++ if (record->hdr.len > length) { ++ /* no room left in buffer for record */ ++- ath10k_warn("Invalid record length: %d\n", +++ ath10k_warn(ar, "Invalid record length: %d\n", ++ record->hdr.len); ++ status = -EINVAL; ++ break; ++@@ -289,7 +290,7 @@ static int ath10k_htc_process_trailer(st ++ case ATH10K_HTC_RECORD_CREDITS: ++ len = sizeof(struct ath10k_htc_credit_report); ++ if (record->hdr.len < len) { ++- ath10k_warn("Credit report too long\n"); +++ ath10k_warn(ar, "Credit report too long\n"); ++ status = -EINVAL; ++ break; ++ } ++@@ -299,7 +300,7 @@ static int ath10k_htc_process_trailer(st ++ src_eid); ++ break; ++ default: ++- ath10k_warn("Unhandled record: id:%d length:%d\n", +++ ath10k_warn(ar, "Unhandled record: id:%d length:%d\n", ++ record->hdr.id, record->hdr.len); ++ break; ++ } ++@@ -313,15 +314,14 @@ static int ath10k_htc_process_trailer(st ++ } ++ ++ if (status) ++- ath10k_dbg_dump(ATH10K_DBG_HTC, "htc rx bad trailer", "", +++ ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc rx bad trailer", "", ++ orig_buffer, orig_length); ++ ++ return status; ++ } ++ ++ static int ath10k_htc_rx_completion_handler(struct ath10k *ar, ++- struct sk_buff *skb, ++- u8 pipe_id) +++ struct sk_buff *skb) ++ { ++ int status = 0; ++ struct ath10k_htc *htc = &ar->htc; ++@@ -339,8 +339,8 @@ static int ath10k_htc_rx_completion_hand ++ eid = hdr->eid; ++ ++ if (eid >= ATH10K_HTC_EP_COUNT) { ++- ath10k_warn("HTC Rx: invalid eid %d\n", eid); ++- ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad header", "", +++ ath10k_warn(ar, "HTC Rx: invalid eid %d\n", eid); +++ ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad header", "", ++ hdr, sizeof(*hdr)); ++ status = -EINVAL; ++ goto out; ++@@ -360,19 +360,19 @@ static int ath10k_htc_rx_completion_hand ++ payload_len = __le16_to_cpu(hdr->len); ++ ++ if (payload_len + sizeof(*hdr) > ATH10K_HTC_MAX_LEN) { ++- ath10k_warn("HTC rx frame too long, len: %zu\n", +++ ath10k_warn(ar, "HTC rx frame too long, len: %zu\n", ++ payload_len + sizeof(*hdr)); ++- ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad rx pkt len", "", +++ ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len", "", ++ hdr, sizeof(*hdr)); ++ status = -EINVAL; ++ goto out; ++ } ++ ++ if (skb->len < payload_len) { ++- ath10k_dbg(ATH10K_DBG_HTC, +++ ath10k_dbg(ar, ATH10K_DBG_HTC, ++ "HTC Rx: insufficient length, got %d, expected %d\n", ++ skb->len, payload_len); ++- ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad rx pkt len", +++ ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len", ++ "", hdr, sizeof(*hdr)); ++ status = -EINVAL; ++ goto out; ++@@ -388,7 +388,7 @@ static int ath10k_htc_rx_completion_hand ++ ++ if ((trailer_len < min_len) || ++ (trailer_len > payload_len)) { ++- ath10k_warn("Invalid trailer length: %d\n", +++ ath10k_warn(ar, "Invalid trailer length: %d\n", ++ trailer_len); ++ status = -EPROTO; ++ goto out; ++@@ -421,7 +421,7 @@ static int ath10k_htc_rx_completion_hand ++ * this is a fatal error, target should not be ++ * sending unsolicited messages on the ep 0 ++ */ ++- ath10k_warn("HTC rx ctrl still processing\n"); +++ ath10k_warn(ar, "HTC rx ctrl still processing\n"); ++ status = -EINVAL; ++ complete(&htc->ctl_resp); ++ goto out; ++@@ -442,7 +442,7 @@ static int ath10k_htc_rx_completion_hand ++ goto out; ++ } ++ ++- ath10k_dbg(ATH10K_DBG_HTC, "htc rx completion ep %d skb %p\n", +++ ath10k_dbg(ar, ATH10K_DBG_HTC, "htc rx completion ep %d skb %p\n", ++ eid, skb); ++ ep->ep_ops.ep_rx_complete(ar, skb); ++ ++@@ -459,7 +459,7 @@ static void ath10k_htc_control_rx_comple ++ { ++ /* This is unexpected. FW is not supposed to send regular rx on this ++ * endpoint. */ ++- ath10k_warn("unexpected htc rx\n"); +++ ath10k_warn(ar, "unexpected htc rx\n"); ++ kfree_skb(skb); ++ } ++ ++@@ -546,7 +546,8 @@ static u8 ath10k_htc_get_credit_allocati ++ ++ int ath10k_htc_wait_target(struct ath10k_htc *htc) ++ { ++- int status = 0; +++ struct ath10k *ar = htc->ar; +++ int i, status = 0; ++ struct ath10k_htc_svc_conn_req conn_req; ++ struct ath10k_htc_svc_conn_resp conn_resp; ++ struct ath10k_htc_msg *msg; ++@@ -556,16 +557,32 @@ int ath10k_htc_wait_target(struct ath10k ++ ++ status = wait_for_completion_timeout(&htc->ctl_resp, ++ ATH10K_HTC_WAIT_TIMEOUT_HZ); ++- if (status <= 0) { +++ if (status == 0) { +++ /* Workaround: In some cases the PCI HIF doesn't +++ * receive interrupt for the control response message +++ * even if the buffer was completed. It is suspected +++ * iomap writes unmasking PCI CE irqs aren't propagated +++ * properly in KVM PCI-passthrough sometimes. +++ */ +++ ath10k_warn(ar, "failed to receive control response completion, polling..\n"); +++ +++ for (i = 0; i < CE_COUNT; i++) +++ ath10k_hif_send_complete_check(htc->ar, i, 1); +++ +++ status = wait_for_completion_timeout(&htc->ctl_resp, +++ ATH10K_HTC_WAIT_TIMEOUT_HZ); +++ ++ if (status == 0) ++ status = -ETIMEDOUT; +++ } ++ ++- ath10k_err("ctl_resp never came in (%d)\n", status); +++ if (status < 0) { +++ ath10k_err(ar, "ctl_resp never came in (%d)\n", status); ++ return status; ++ } ++ ++ if (htc->control_resp_len < sizeof(msg->hdr) + sizeof(msg->ready)) { ++- ath10k_err("Invalid HTC ready msg len:%d\n", +++ ath10k_err(ar, "Invalid HTC ready msg len:%d\n", ++ htc->control_resp_len); ++ return -ECOMM; ++ } ++@@ -576,21 +593,21 @@ int ath10k_htc_wait_target(struct ath10k ++ credit_size = __le16_to_cpu(msg->ready.credit_size); ++ ++ if (message_id != ATH10K_HTC_MSG_READY_ID) { ++- ath10k_err("Invalid HTC ready msg: 0x%x\n", message_id); +++ ath10k_err(ar, "Invalid HTC ready msg: 0x%x\n", message_id); ++ return -ECOMM; ++ } ++ ++ htc->total_transmit_credits = credit_count; ++ htc->target_credit_size = credit_size; ++ ++- ath10k_dbg(ATH10K_DBG_HTC, +++ ath10k_dbg(ar, ATH10K_DBG_HTC, ++ "Target ready! transmit resources: %d size:%d\n", ++ htc->total_transmit_credits, ++ htc->target_credit_size); ++ ++ if ((htc->total_transmit_credits == 0) || ++ (htc->target_credit_size == 0)) { ++- ath10k_err("Invalid credit size received\n"); +++ ath10k_err(ar, "Invalid credit size received\n"); ++ return -ECOMM; ++ } ++ ++@@ -607,7 +624,8 @@ int ath10k_htc_wait_target(struct ath10k ++ /* connect fake service */ ++ status = ath10k_htc_connect_service(htc, &conn_req, &conn_resp); ++ if (status) { ++- ath10k_err("could not connect to htc service (%d)\n", status); +++ ath10k_err(ar, "could not connect to htc service (%d)\n", +++ status); ++ return status; ++ } ++ ++@@ -618,6 +636,7 @@ int ath10k_htc_connect_service(struct at ++ struct ath10k_htc_svc_conn_req *conn_req, ++ struct ath10k_htc_svc_conn_resp *conn_resp) ++ { +++ struct ath10k *ar = htc->ar; ++ struct ath10k_htc_msg *msg; ++ struct ath10k_htc_conn_svc *req_msg; ++ struct ath10k_htc_conn_svc_response resp_msg_dummy; ++@@ -643,13 +662,13 @@ int ath10k_htc_connect_service(struct at ++ tx_alloc = ath10k_htc_get_credit_allocation(htc, ++ conn_req->service_id); ++ if (!tx_alloc) ++- ath10k_dbg(ATH10K_DBG_BOOT, +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, ++ "boot htc service %s does not allocate target credits\n", ++ htc_service_name(conn_req->service_id)); ++ ++ skb = ath10k_htc_build_tx_ctrl_skb(htc->ar); ++ if (!skb) { ++- ath10k_err("Failed to allocate HTC packet\n"); +++ ath10k_err(ar, "Failed to allocate HTC packet\n"); ++ return -ENOMEM; ++ } ++ ++@@ -684,11 +703,9 @@ int ath10k_htc_connect_service(struct at ++ /* wait for response */ ++ status = wait_for_completion_timeout(&htc->ctl_resp, ++ ATH10K_HTC_CONN_SVC_TIMEOUT_HZ); ++- if (status <= 0) { ++- if (status == 0) ++- status = -ETIMEDOUT; ++- ath10k_err("Service connect timeout: %d\n", status); ++- return status; +++ if (status == 0) { +++ ath10k_err(ar, "Service connect timeout: %d\n", status); +++ return -ETIMEDOUT; ++ } ++ ++ /* we controlled the buffer creation, it's aligned */ ++@@ -700,11 +717,11 @@ int ath10k_htc_connect_service(struct at ++ if ((message_id != ATH10K_HTC_MSG_CONNECT_SERVICE_RESP_ID) || ++ (htc->control_resp_len < sizeof(msg->hdr) + ++ sizeof(msg->connect_service_response))) { ++- ath10k_err("Invalid resp message ID 0x%x", message_id); +++ ath10k_err(ar, "Invalid resp message ID 0x%x", message_id); ++ return -EPROTO; ++ } ++ ++- ath10k_dbg(ATH10K_DBG_HTC, +++ ath10k_dbg(ar, ATH10K_DBG_HTC, ++ "HTC Service %s connect response: status: 0x%x, assigned ep: 0x%x\n", ++ htc_service_name(service_id), ++ resp_msg->status, resp_msg->eid); ++@@ -713,7 +730,7 @@ int ath10k_htc_connect_service(struct at ++ ++ /* check response status */ ++ if (resp_msg->status != ATH10K_HTC_CONN_SVC_STATUS_SUCCESS) { ++- ath10k_err("HTC Service %s connect request failed: 0x%x)\n", +++ ath10k_err(ar, "HTC Service %s connect request failed: 0x%x)\n", ++ htc_service_name(service_id), ++ resp_msg->status); ++ return -EPROTO; ++@@ -764,18 +781,18 @@ setup: ++ if (status) ++ return status; ++ ++- ath10k_dbg(ATH10K_DBG_BOOT, +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, ++ "boot htc service '%s' ul pipe %d dl pipe %d eid %d ready\n", ++ htc_service_name(ep->service_id), ep->ul_pipe_id, ++ ep->dl_pipe_id, ep->eid); ++ ++- ath10k_dbg(ATH10K_DBG_BOOT, +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, ++ "boot htc ep %d ul polled %d dl polled %d\n", ++ ep->eid, ep->ul_is_polled, ep->dl_is_polled); ++ ++ if (disable_credit_flow_ctrl && ep->tx_credit_flow_enabled) { ++ ep->tx_credit_flow_enabled = false; ++- ath10k_dbg(ATH10K_DBG_BOOT, +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, ++ "boot htc service '%s' eid %d TX flow control disabled\n", ++ htc_service_name(ep->service_id), assigned_eid); ++ } ++@@ -783,27 +800,26 @@ setup: ++ return status; ++ } ++ ++-struct sk_buff *ath10k_htc_alloc_skb(int size) +++struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size) ++ { ++ struct sk_buff *skb; ++ ++ skb = dev_alloc_skb(size + sizeof(struct ath10k_htc_hdr)); ++- if (!skb) { ++- ath10k_warn("could not allocate HTC tx skb\n"); +++ if (!skb) ++ return NULL; ++- } ++ ++ skb_reserve(skb, sizeof(struct ath10k_htc_hdr)); ++ ++ /* FW/HTC requires 4-byte aligned streams */ ++ if (!IS_ALIGNED((unsigned long)skb->data, 4)) ++- ath10k_warn("Unaligned HTC tx skb\n"); +++ ath10k_warn(ar, "Unaligned HTC tx skb\n"); ++ ++ return skb; ++ } ++ ++ int ath10k_htc_start(struct ath10k_htc *htc) ++ { +++ struct ath10k *ar = htc->ar; ++ struct sk_buff *skb; ++ int status = 0; ++ struct ath10k_htc_msg *msg; ++@@ -819,7 +835,7 @@ int ath10k_htc_start(struct ath10k_htc * ++ msg->hdr.message_id = ++ __cpu_to_le16(ATH10K_HTC_MSG_SETUP_COMPLETE_EX_ID); ++ ++- ath10k_dbg(ATH10K_DBG_HTC, "HTC is using TX credit flow control\n"); +++ ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC is using TX credit flow control\n"); ++ ++ status = ath10k_htc_send(htc, ATH10K_HTC_EP_0, skb); ++ if (status) { ++@@ -830,19 +846,6 @@ int ath10k_htc_start(struct ath10k_htc * ++ return 0; ++ } ++ ++-/* ++- * stop HTC communications, i.e. stop interrupt reception, and flush all ++- * queued buffers ++- */ ++-void ath10k_htc_stop(struct ath10k_htc *htc) ++-{ ++- spin_lock_bh(&htc->tx_lock); ++- htc->stopped = true; ++- spin_unlock_bh(&htc->tx_lock); ++- ++- ath10k_hif_stop(htc->ar); ++-} ++- ++ /* registered target arrival callback from the HIF layer */ ++ int ath10k_htc_init(struct ath10k *ar) ++ { ++@@ -852,7 +855,6 @@ int ath10k_htc_init(struct ath10k *ar) ++ ++ spin_lock_init(&htc->tx_lock); ++ ++- htc->stopped = false; ++ ath10k_htc_reset_endpoint_states(htc); ++ ++ /* setup HIF layer callbacks */ ++--- a/drivers/net/wireless/ath/ath10k/htc.h +++++ b/drivers/net/wireless/ath/ath10k/htc.h ++@@ -214,7 +214,6 @@ struct ath10k_htc_frame { ++ struct ath10k_htc_record trailer[0]; ++ } __packed __aligned(4); ++ ++- ++ /*******************/ ++ /* Host-side stuff */ ++ /*******************/ ++@@ -332,7 +331,7 @@ struct ath10k_htc { ++ struct ath10k *ar; ++ struct ath10k_htc_ep endpoint[ATH10K_HTC_EP_COUNT]; ++ ++- /* protects endpoint and stopped fields */ +++ /* protects endpoints */ ++ spinlock_t tx_lock; ++ ++ struct ath10k_htc_ops htc_ops; ++@@ -345,8 +344,6 @@ struct ath10k_htc { ++ int total_transmit_credits; ++ struct ath10k_htc_svc_tx_credits service_tx_alloc[ATH10K_HTC_EP_COUNT]; ++ int target_credit_size; ++- ++- bool stopped; ++ }; ++ ++ int ath10k_htc_init(struct ath10k *ar); ++@@ -357,7 +354,6 @@ int ath10k_htc_connect_service(struct at ++ struct ath10k_htc_svc_conn_resp *conn_resp); ++ int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid, ++ struct sk_buff *packet); ++-void ath10k_htc_stop(struct ath10k_htc *htc); ++-struct sk_buff *ath10k_htc_alloc_skb(int size); +++struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size); ++ ++ #endif ++--- a/drivers/net/wireless/ath/ath10k/htt.c +++++ b/drivers/net/wireless/ath/ath10k/htt.c ++@@ -22,7 +22,7 @@ ++ #include "core.h" ++ #include "debug.h" ++ ++-static int ath10k_htt_htc_attach(struct ath10k_htt *htt) +++int ath10k_htt_connect(struct ath10k_htt *htt) ++ { ++ struct ath10k_htc_svc_conn_req conn_req; ++ struct ath10k_htc_svc_conn_resp conn_resp; ++@@ -48,37 +48,11 @@ static int ath10k_htt_htc_attach(struct ++ return 0; ++ } ++ ++-int ath10k_htt_attach(struct ath10k *ar) +++int ath10k_htt_init(struct ath10k *ar) ++ { ++ struct ath10k_htt *htt = &ar->htt; ++- int ret; ++ ++ htt->ar = ar; ++- htt->max_throughput_mbps = 800; ++- ++- /* ++- * Connect to HTC service. ++- * This has to be done before calling ath10k_htt_rx_attach, ++- * since ath10k_htt_rx_attach involves sending a rx ring configure ++- * message to the target. ++- */ ++- ret = ath10k_htt_htc_attach(htt); ++- if (ret) { ++- ath10k_err("could not attach htt htc (%d)\n", ret); ++- goto err_htc_attach; ++- } ++- ++- ret = ath10k_htt_tx_attach(htt); ++- if (ret) { ++- ath10k_err("could not attach htt tx (%d)\n", ret); ++- goto err_htc_attach; ++- } ++- ++- ret = ath10k_htt_rx_attach(htt); ++- if (ret) { ++- ath10k_err("could not attach htt rx (%d)\n", ret); ++- goto err_rx_attach; ++- } ++ ++ /* ++ * Prefetch enough data to satisfy target ++@@ -93,23 +67,20 @@ int ath10k_htt_attach(struct ath10k *ar) ++ 2; /* ip4 dscp or ip6 priority */ ++ ++ return 0; ++- ++-err_rx_attach: ++- ath10k_htt_tx_detach(htt); ++-err_htc_attach: ++- return ret; ++ } ++ ++ #define HTT_TARGET_VERSION_TIMEOUT_HZ (3*HZ) ++ ++ static int ath10k_htt_verify_version(struct ath10k_htt *htt) ++ { ++- ath10k_dbg(ATH10K_DBG_BOOT, "htt target version %d.%d\n", +++ struct ath10k *ar = htt->ar; +++ +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt target version %d.%d\n", ++ htt->target_version_major, htt->target_version_minor); ++ ++ if (htt->target_version_major != 2 && ++ htt->target_version_major != 3) { ++- ath10k_err("unsupported htt major version %d. supported versions are 2 and 3\n", +++ ath10k_err(ar, "unsupported htt major version %d. supported versions are 2 and 3\n", ++ htt->target_version_major); ++ return -ENOTSUPP; ++ } ++@@ -117,8 +88,9 @@ static int ath10k_htt_verify_version(str ++ return 0; ++ } ++ ++-int ath10k_htt_attach_target(struct ath10k_htt *htt) +++int ath10k_htt_setup(struct ath10k_htt *htt) ++ { +++ struct ath10k *ar = htt->ar; ++ int status; ++ ++ init_completion(&htt->target_version_received); ++@@ -128,9 +100,9 @@ int ath10k_htt_attach_target(struct ath1 ++ return status; ++ ++ status = wait_for_completion_timeout(&htt->target_version_received, ++- HTT_TARGET_VERSION_TIMEOUT_HZ); ++- if (status <= 0) { ++- ath10k_warn("htt version request timed out\n"); +++ HTT_TARGET_VERSION_TIMEOUT_HZ); +++ if (status == 0) { +++ ath10k_warn(ar, "htt version request timed out\n"); ++ return -ETIMEDOUT; ++ } ++ ++@@ -140,9 +112,3 @@ int ath10k_htt_attach_target(struct ath1 ++ ++ return ath10k_htt_send_rx_ring_cfg_ll(htt); ++ } ++- ++-void ath10k_htt_detach(struct ath10k_htt *htt) ++-{ ++- ath10k_htt_rx_detach(htt); ++- ath10k_htt_tx_detach(htt); ++-} ++--- a/drivers/net/wireless/ath/ath10k/htt.h +++++ b/drivers/net/wireless/ath/ath10k/htt.h ++@@ -21,6 +21,7 @@ ++ #include ++ #include ++ #include +++#include ++ #include ++ ++ #include "htc.h" ++@@ -126,6 +127,7 @@ enum htt_data_tx_ext_tid { ++ * (HL hosts manage queues on the host ) ++ * more_in_batch: only for HL hosts. indicates if more packets are ++ * pending. this allows target to wait and aggregate +++ * freq: 0 means home channel of given vdev. intended for offchannel ++ */ ++ struct htt_data_tx_desc { ++ u8 flags0; /* %HTT_DATA_TX_DESC_FLAGS0_ */ ++@@ -133,7 +135,8 @@ struct htt_data_tx_desc { ++ __le16 len; ++ __le16 id; ++ __le32 frags_paddr; ++- __le32 peerid; +++ __le16 peerid; +++ __le16 freq; ++ u8 prefetch[0]; /* start of frame, for FW classification engine */ ++ } __packed; ++ ++@@ -156,6 +159,9 @@ enum htt_rx_ring_flags { ++ HTT_RX_RING_FLAGS_PHY_DATA_RX = 1 << 15 ++ }; ++ +++#define HTT_RX_RING_SIZE_MIN 128 +++#define HTT_RX_RING_SIZE_MAX 2048 +++ ++ struct htt_rx_ring_setup_ring { ++ __le32 fw_idx_shadow_reg_paddr; ++ __le32 rx_ring_base_paddr; ++@@ -240,16 +246,10 @@ struct htt_oob_sync_req { ++ __le16 rsvd0; ++ } __packed; ++ ++-#define HTT_AGGR_CONF_MAX_NUM_AMSDU_SUBFRAMES_MASK 0x1F ++-#define HTT_AGGR_CONF_MAX_NUM_AMSDU_SUBFRAMES_LSB 0 ++- ++ struct htt_aggr_conf { ++ u8 max_num_ampdu_subframes; ++- union { ++- /* dont use bitfields; undefined behaviour */ ++- u8 flags; /* see %HTT_AGGR_CONF_MAX_NUM_AMSDU_SUBFRAMES_ */ ++- u8 max_num_amsdu_subframes:5; ++- } __packed; +++ /* amsdu_subframes is limited by 0x1F mask */ +++ u8 max_num_amsdu_subframes; ++ } __packed; ++ ++ #define HTT_MGMT_FRM_HDR_DOWNLOAD_LEN 32 ++@@ -271,7 +271,6 @@ enum htt_mgmt_tx_status { ++ ++ /*=== target -> host messages ===============================================*/ ++ ++- ++ enum htt_t2h_msg_type { ++ HTT_T2H_MSG_TYPE_VERSION_CONF = 0x0, ++ HTT_T2H_MSG_TYPE_RX_IND = 0x1, ++@@ -288,7 +287,19 @@ enum htt_t2h_msg_type { ++ HTT_T2H_MSG_TYPE_RC_UPDATE_IND = 0xc, ++ HTT_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd, ++ HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION = 0xe, +++ HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND = 0xf, +++ HTT_T2H_MSG_TYPE_RX_PN_IND = 0x10, +++ HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND = 0x11, +++ HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND = 0x12, +++ /* 0x13 reservd */ +++ HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE = 0x14, +++ +++ /* FIXME: Do not depend on this event id. Numbering of this event id is +++ * broken across different firmware revisions and HTT version fails to +++ * indicate this. +++ */ ++ HTT_T2H_MSG_TYPE_TEST, +++ ++ /* keep this last */ ++ HTT_T2H_NUM_MSGS ++ }; ++@@ -657,6 +668,53 @@ struct htt_rx_fragment_indication { ++ #define HTT_RX_FRAG_IND_INFO1_FLUSH_SEQ_NUM_END_MASK 0x00000FC0 ++ #define HTT_RX_FRAG_IND_INFO1_FLUSH_SEQ_NUM_END_LSB 6 ++ +++struct htt_rx_pn_ind { +++ __le16 peer_id; +++ u8 tid; +++ u8 seqno_start; +++ u8 seqno_end; +++ u8 pn_ie_count; +++ u8 reserved; +++ u8 pn_ies[0]; +++} __packed; +++ +++struct htt_rx_offload_msdu { +++ __le16 msdu_len; +++ __le16 peer_id; +++ u8 vdev_id; +++ u8 tid; +++ u8 fw_desc; +++ u8 payload[0]; +++} __packed; +++ +++struct htt_rx_offload_ind { +++ u8 reserved; +++ __le16 msdu_count; +++} __packed; +++ +++struct htt_rx_in_ord_msdu_desc { +++ __le32 msdu_paddr; +++ __le16 msdu_len; +++ u8 fw_desc; +++ u8 reserved; +++} __packed; +++ +++struct htt_rx_in_ord_ind { +++ u8 info; +++ __le16 peer_id; +++ u8 vdev_id; +++ u8 reserved; +++ __le16 msdu_count; +++ struct htt_rx_in_ord_msdu_desc msdu_descs[0]; +++} __packed; +++ +++#define HTT_RX_IN_ORD_IND_INFO_TID_MASK 0x0000001f +++#define HTT_RX_IN_ORD_IND_INFO_TID_LSB 0 +++#define HTT_RX_IN_ORD_IND_INFO_OFFLOAD_MASK 0x00000020 +++#define HTT_RX_IN_ORD_IND_INFO_OFFLOAD_LSB 5 +++#define HTT_RX_IN_ORD_IND_INFO_FRAG_MASK 0x00000040 +++#define HTT_RX_IN_ORD_IND_INFO_FRAG_LSB 6 +++ ++ /* ++ * target -> host test message definition ++ * ++@@ -732,7 +790,7 @@ static inline u8 *htt_rx_test_get_chars( ++ */ ++ struct htt_pktlog_msg { ++ u8 pad[3]; ++- __le32 payload[1 /* or more */]; +++ u8 payload[0]; ++ } __packed; ++ ++ struct htt_dbg_stats_rx_reorder_stats { ++@@ -1038,6 +1096,7 @@ static inline struct htt_stats_conf_item ++ { ++ return (void *)item + sizeof(*item) + roundup(item->length, 4); ++ } +++ ++ /* ++ * host -> target FRAG DESCRIPTOR/MSDU_EXT DESC bank ++ * ++@@ -1151,10 +1210,12 @@ struct htt_resp { ++ struct htt_rx_test rx_test; ++ struct htt_pktlog_msg pktlog_msg; ++ struct htt_stats_conf stats_conf; +++ struct htt_rx_pn_ind rx_pn_ind; +++ struct htt_rx_offload_ind rx_offload_ind; +++ struct htt_rx_in_ord_ind rx_in_ord_ind; ++ }; ++ } __packed; ++ ++- ++ /*** host side structures follow ***/ ++ ++ struct htt_tx_done { ++@@ -1184,7 +1245,6 @@ struct ath10k_htt { ++ struct ath10k *ar; ++ enum ath10k_htc_ep_id eid; ++ ++- int max_throughput_mbps; ++ u8 target_version_major; ++ u8 target_version_minor; ++ struct completion target_version_received; ++@@ -1200,6 +1260,20 @@ struct ath10k_htt { ++ * filled. ++ */ ++ struct sk_buff **netbufs_ring; +++ +++ /* This is used only with firmware supporting IN_ORD_IND. +++ * +++ * With Full Rx Reorder the HTT Rx Ring is more of a temporary +++ * buffer ring from which buffer addresses are copied by the +++ * firmware to MAC Rx ring. Firmware then delivers IN_ORD_IND +++ * pointing to specific (re-ordered) buffers. +++ * +++ * FIXME: With kernel generic hashing functions there's a lot +++ * of hash collisions for sk_buffs. +++ */ +++ bool in_ord_rx; +++ DECLARE_HASHTABLE(skb_table, 4); +++ ++ /* ++ * Ring of buffer addresses - ++ * This ring holds the "physical" device address of the ++@@ -1254,12 +1328,11 @@ struct ath10k_htt { ++ ++ unsigned int prefetch_len; ++ ++- /* Protects access to %pending_tx, %used_msdu_ids */ +++ /* Protects access to pending_tx, num_pending_tx */ ++ spinlock_t tx_lock; ++ int max_num_pending_tx; ++ int num_pending_tx; ++- struct sk_buff **pending_tx; ++- unsigned long *used_msdu_ids; /* bitmap */ +++ struct idr pending_tx; ++ wait_queue_head_t empty_tx_wq; ++ struct dma_pool *tx_pool; ++ ++@@ -1273,6 +1346,7 @@ struct ath10k_htt { ++ struct tasklet_struct txrx_compl_task; ++ struct sk_buff_head tx_compl_q; ++ struct sk_buff_head rx_compl_q; +++ struct sk_buff_head rx_in_ord_compl_q; ++ ++ /* rx_status template */ ++ struct ieee80211_rx_status rx_status; ++@@ -1328,22 +1402,28 @@ struct htt_rx_desc { ++ #define HTT_LOG2_MAX_CACHE_LINE_SIZE 7 /* 2^7 = 128 */ ++ #define HTT_MAX_CACHE_LINE_SIZE_MASK ((1 << HTT_LOG2_MAX_CACHE_LINE_SIZE) - 1) ++ ++-int ath10k_htt_attach(struct ath10k *ar); ++-int ath10k_htt_attach_target(struct ath10k_htt *htt); ++-void ath10k_htt_detach(struct ath10k_htt *htt); ++- ++-int ath10k_htt_tx_attach(struct ath10k_htt *htt); ++-void ath10k_htt_tx_detach(struct ath10k_htt *htt); ++-int ath10k_htt_rx_attach(struct ath10k_htt *htt); ++-void ath10k_htt_rx_detach(struct ath10k_htt *htt); +++int ath10k_htt_connect(struct ath10k_htt *htt); +++int ath10k_htt_init(struct ath10k *ar); +++int ath10k_htt_setup(struct ath10k_htt *htt); +++ +++int ath10k_htt_tx_alloc(struct ath10k_htt *htt); +++void ath10k_htt_tx_free(struct ath10k_htt *htt); +++ +++int ath10k_htt_rx_alloc(struct ath10k_htt *htt); +++int ath10k_htt_rx_ring_refill(struct ath10k *ar); +++void ath10k_htt_rx_free(struct ath10k_htt *htt); +++ ++ void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb); ++ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb); ++ int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt); ++ int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie); ++ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt); +++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); ++-int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt); +++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 *); ++ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *); ++--- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++++ b/drivers/net/wireless/ath/ath10k/htt_rx.c ++@@ -21,118 +21,84 @@ ++ #include "txrx.h" ++ #include "debug.h" ++ #include "trace.h" +++#include "mac.h" ++ ++ #include ++ ++-/* slightly larger than one large A-MPDU */ ++-#define HTT_RX_RING_SIZE_MIN 128 ++- ++-/* roughly 20 ms @ 1 Gbps of 1500B MSDUs */ ++-#define HTT_RX_RING_SIZE_MAX 2048 ++- ++-#define HTT_RX_AVG_FRM_BYTES 1000 ++- ++-/* ms, very conservative */ ++-#define HTT_RX_HOST_LATENCY_MAX_MS 20 ++- ++-/* ms, conservative */ ++-#define HTT_RX_HOST_LATENCY_WORST_LIKELY_MS 10 +++#define HTT_RX_RING_SIZE HTT_RX_RING_SIZE_MAX +++#define HTT_RX_RING_FILL_LEVEL (((HTT_RX_RING_SIZE) / 2) - 1) ++ ++ /* when under memory pressure rx ring refill may fail and needs a retry */ ++ #define HTT_RX_RING_REFILL_RETRY_MS 50 ++ ++- ++ static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb); ++ static void ath10k_htt_txrx_compl_task(unsigned long ptr); ++ ++-static int ath10k_htt_rx_ring_size(struct ath10k_htt *htt) ++-{ ++- int size; ++- ++- /* ++- * It is expected that the host CPU will typically be able to ++- * service the rx indication from one A-MPDU before the rx ++- * indication from the subsequent A-MPDU happens, roughly 1-2 ms ++- * later. However, the rx ring should be sized very conservatively, ++- * to accomodate the worst reasonable delay before the host CPU ++- * services a rx indication interrupt. ++- * ++- * The rx ring need not be kept full of empty buffers. In theory, ++- * the htt host SW can dynamically track the low-water mark in the ++- * rx ring, and dynamically adjust the level to which the rx ring ++- * is filled with empty buffers, to dynamically meet the desired ++- * low-water mark. ++- * ++- * In contrast, it's difficult to resize the rx ring itself, once ++- * it's in use. Thus, the ring itself should be sized very ++- * conservatively, while the degree to which the ring is filled ++- * with empty buffers should be sized moderately conservatively. ++- */ ++- ++- /* 1e6 bps/mbps / 1e3 ms per sec = 1000 */ ++- size = ++- htt->max_throughput_mbps + ++- 1000 / ++- (8 * HTT_RX_AVG_FRM_BYTES) * HTT_RX_HOST_LATENCY_MAX_MS; ++- ++- if (size < HTT_RX_RING_SIZE_MIN) ++- size = HTT_RX_RING_SIZE_MIN; ++- ++- if (size > HTT_RX_RING_SIZE_MAX) ++- size = HTT_RX_RING_SIZE_MAX; ++- ++- size = roundup_pow_of_two(size); ++- ++- return size; ++-} ++- ++-static int ath10k_htt_rx_ring_fill_level(struct ath10k_htt *htt) +++static struct sk_buff * +++ath10k_htt_rx_find_skb_paddr(struct ath10k *ar, u32 paddr) ++ { ++- int size; +++ struct ath10k_skb_rxcb *rxcb; ++ ++- /* 1e6 bps/mbps / 1e3 ms per sec = 1000 */ ++- size = ++- htt->max_throughput_mbps * ++- 1000 / ++- (8 * HTT_RX_AVG_FRM_BYTES) * HTT_RX_HOST_LATENCY_WORST_LIKELY_MS; ++- ++- /* ++- * Make sure the fill level is at least 1 less than the ring size. ++- * Leaving 1 element empty allows the SW to easily distinguish ++- * between a full ring vs. an empty ring. ++- */ ++- if (size >= htt->rx_ring.size) ++- size = htt->rx_ring.size - 1; +++ hash_for_each_possible(ar->htt.rx_ring.skb_table, rxcb, hlist, paddr) +++ if (rxcb->paddr == paddr) +++ return ATH10K_RXCB_SKB(rxcb); ++ ++- return size; +++ WARN_ON_ONCE(1); +++ return NULL; ++ } ++ ++ static void ath10k_htt_rx_ring_free(struct ath10k_htt *htt) ++ { ++ struct sk_buff *skb; ++- struct ath10k_skb_cb *cb; +++ struct ath10k_skb_rxcb *rxcb; +++ struct hlist_node *n; ++ int i; ++ ++- for (i = 0; i < htt->rx_ring.fill_cnt; i++) { ++- skb = htt->rx_ring.netbufs_ring[i]; ++- cb = ATH10K_SKB_CB(skb); ++- dma_unmap_single(htt->ar->dev, cb->paddr, ++- skb->len + skb_tailroom(skb), ++- DMA_FROM_DEVICE); ++- dev_kfree_skb_any(skb); +++ if (htt->rx_ring.in_ord_rx) { +++ hash_for_each_safe(htt->rx_ring.skb_table, i, n, rxcb, hlist) { +++ skb = ATH10K_RXCB_SKB(rxcb); +++ dma_unmap_single(htt->ar->dev, rxcb->paddr, +++ skb->len + skb_tailroom(skb), +++ DMA_FROM_DEVICE); +++ hash_del(&rxcb->hlist); +++ dev_kfree_skb_any(skb); +++ } +++ } else { +++ for (i = 0; i < htt->rx_ring.size; i++) { +++ skb = htt->rx_ring.netbufs_ring[i]; +++ if (!skb) +++ continue; +++ +++ rxcb = ATH10K_SKB_RXCB(skb); +++ dma_unmap_single(htt->ar->dev, rxcb->paddr, +++ skb->len + skb_tailroom(skb), +++ DMA_FROM_DEVICE); +++ dev_kfree_skb_any(skb); +++ } ++ } ++ ++ htt->rx_ring.fill_cnt = 0; +++ hash_init(htt->rx_ring.skb_table); +++ memset(htt->rx_ring.netbufs_ring, 0, +++ htt->rx_ring.size * sizeof(htt->rx_ring.netbufs_ring[0])); ++ } ++ ++ static int __ath10k_htt_rx_ring_fill_n(struct ath10k_htt *htt, int num) ++ { ++ struct htt_rx_desc *rx_desc; +++ struct ath10k_skb_rxcb *rxcb; ++ struct sk_buff *skb; ++ dma_addr_t paddr; ++ int ret = 0, idx; ++ ++- idx = __le32_to_cpu(*(htt->rx_ring.alloc_idx.vaddr)); +++ /* The Full Rx Reorder firmware has no way of telling the host +++ * implicitly when it copied HTT Rx Ring buffers to MAC Rx Ring. +++ * To keep things simple make sure ring is always half empty. This +++ * guarantees there'll be no replenishment overruns possible. +++ */ +++ BUILD_BUG_ON(HTT_RX_RING_FILL_LEVEL >= HTT_RX_RING_SIZE / 2); +++ +++ idx = __le32_to_cpu(*htt->rx_ring.alloc_idx.vaddr); ++ while (num > 0) { ++ skb = dev_alloc_skb(HTT_RX_BUF_SIZE + HTT_RX_DESC_ALIGN); ++ if (!skb) { ++@@ -159,18 +125,30 @@ static int __ath10k_htt_rx_ring_fill_n(s ++ goto fail; ++ } ++ ++- ATH10K_SKB_CB(skb)->paddr = paddr; +++ rxcb = ATH10K_SKB_RXCB(skb); +++ rxcb->paddr = paddr; ++ htt->rx_ring.netbufs_ring[idx] = skb; ++ htt->rx_ring.paddrs_ring[idx] = __cpu_to_le32(paddr); ++ htt->rx_ring.fill_cnt++; ++ +++ if (htt->rx_ring.in_ord_rx) { +++ hash_add(htt->rx_ring.skb_table, +++ &ATH10K_SKB_RXCB(skb)->hlist, +++ (u32)paddr); +++ } +++ ++ num--; ++ idx++; ++ idx &= htt->rx_ring.size_mask; ++ } ++ ++ fail: ++- *(htt->rx_ring.alloc_idx.vaddr) = __cpu_to_le32(idx); +++ /* +++ * Make sure the rx buffer is updated before available buffer +++ * index to avoid any potential rx ring corruption. +++ */ +++ mb(); +++ *htt->rx_ring.alloc_idx.vaddr = __cpu_to_le32(idx); ++ return ret; ++ } ++ ++@@ -198,7 +176,7 @@ static void ath10k_htt_rx_msdu_buff_repl ++ * automatically balances load wrt to CPU power. ++ * ++ * This probably comes at a cost of lower maximum throughput but ++- * improves the avarage and stability. */ +++ * improves the average and stability. */ ++ spin_lock_bh(&htt->rx_ring.lock); ++ num_deficit = htt->rx_ring.fill_level - htt->rx_ring.fill_cnt; ++ num_to_fill = min(ATH10K_HTT_MAX_NUM_REFILL, num_deficit); ++@@ -222,32 +200,37 @@ static void ath10k_htt_rx_msdu_buff_repl ++ static void ath10k_htt_rx_ring_refill_retry(unsigned long arg) ++ { ++ struct ath10k_htt *htt = (struct ath10k_htt *)arg; +++ ++ ath10k_htt_rx_msdu_buff_replenish(htt); ++ } ++ ++-void ath10k_htt_rx_detach(struct ath10k_htt *htt) +++int ath10k_htt_rx_ring_refill(struct ath10k *ar) ++ { ++- int sw_rd_idx = htt->rx_ring.sw_rd_idx.msdu_payld; +++ struct ath10k_htt *htt = &ar->htt; +++ int ret; +++ +++ spin_lock_bh(&htt->rx_ring.lock); +++ ret = ath10k_htt_rx_ring_fill_n(htt, (htt->rx_ring.fill_level - +++ htt->rx_ring.fill_cnt)); +++ spin_unlock_bh(&htt->rx_ring.lock); +++ +++ if (ret) +++ ath10k_htt_rx_ring_free(htt); +++ +++ return ret; +++} ++ +++void ath10k_htt_rx_free(struct ath10k_htt *htt) +++{ ++ del_timer_sync(&htt->rx_ring.refill_retry_timer); ++ tasklet_kill(&htt->rx_replenish_task); ++ tasklet_kill(&htt->txrx_compl_task); ++ ++ skb_queue_purge(&htt->tx_compl_q); ++ skb_queue_purge(&htt->rx_compl_q); +++ skb_queue_purge(&htt->rx_in_ord_compl_q); ++ ++- while (sw_rd_idx != __le32_to_cpu(*(htt->rx_ring.alloc_idx.vaddr))) { ++- struct sk_buff *skb = ++- htt->rx_ring.netbufs_ring[sw_rd_idx]; ++- struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb); ++- ++- dma_unmap_single(htt->ar->dev, cb->paddr, ++- skb->len + skb_tailroom(skb), ++- DMA_FROM_DEVICE); ++- dev_kfree_skb_any(htt->rx_ring.netbufs_ring[sw_rd_idx]); ++- sw_rd_idx++; ++- sw_rd_idx &= htt->rx_ring.size_mask; ++- } +++ ath10k_htt_rx_ring_free(htt); ++ ++ dma_free_coherent(htt->ar->dev, ++ (htt->rx_ring.size * ++@@ -265,66 +248,59 @@ void ath10k_htt_rx_detach(struct ath10k_ ++ ++ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt) ++ { +++ struct ath10k *ar = htt->ar; ++ int idx; ++ struct sk_buff *msdu; ++ ++ lockdep_assert_held(&htt->rx_ring.lock); ++ ++ if (htt->rx_ring.fill_cnt == 0) { ++- ath10k_warn("tried to pop sk_buff from an empty rx ring\n"); +++ ath10k_warn(ar, "tried to pop sk_buff from an empty rx ring\n"); ++ return NULL; ++ } ++ ++ idx = htt->rx_ring.sw_rd_idx.msdu_payld; ++ msdu = htt->rx_ring.netbufs_ring[idx]; +++ htt->rx_ring.netbufs_ring[idx] = NULL; +++ htt->rx_ring.paddrs_ring[idx] = 0; ++ ++ idx++; ++ idx &= htt->rx_ring.size_mask; ++ htt->rx_ring.sw_rd_idx.msdu_payld = idx; ++ htt->rx_ring.fill_cnt--; ++ ++- return msdu; ++-} ++- ++-static void ath10k_htt_rx_free_msdu_chain(struct sk_buff *skb) ++-{ ++- struct sk_buff *next; +++ dma_unmap_single(htt->ar->dev, +++ ATH10K_SKB_RXCB(msdu)->paddr, +++ msdu->len + skb_tailroom(msdu), +++ DMA_FROM_DEVICE); +++ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx netbuf pop: ", +++ msdu->data, msdu->len + skb_tailroom(msdu)); ++ ++- while (skb) { ++- next = skb->next; ++- dev_kfree_skb_any(skb); ++- skb = next; ++- } +++ return msdu; ++ } ++ ++ /* return: < 0 fatal error, 0 - non chained msdu, 1 chained msdu */ ++ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, ++ u8 **fw_desc, int *fw_desc_len, ++- struct sk_buff **head_msdu, ++- struct sk_buff **tail_msdu) +++ struct sk_buff_head *amsdu) ++ { +++ struct ath10k *ar = htt->ar; ++ int msdu_len, msdu_chaining = 0; ++ struct sk_buff *msdu; ++ struct htt_rx_desc *rx_desc; ++ ++ lockdep_assert_held(&htt->rx_ring.lock); ++ ++- if (htt->rx_confused) { ++- ath10k_warn("htt is confused. refusing rx\n"); ++- return -1; ++- } ++- ++- msdu = *head_msdu = ath10k_htt_rx_netbuf_pop(htt); ++- while (msdu) { +++ for (;;) { ++ int last_msdu, msdu_len_invalid, msdu_chained; ++ ++- dma_unmap_single(htt->ar->dev, ++- ATH10K_SKB_CB(msdu)->paddr, ++- msdu->len + skb_tailroom(msdu), ++- DMA_FROM_DEVICE); +++ msdu = ath10k_htt_rx_netbuf_pop(htt); +++ if (!msdu) { +++ __skb_queue_purge(amsdu); +++ return -ENOENT; +++ } ++ ++- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx pop: ", ++- msdu->data, msdu->len + skb_tailroom(msdu)); +++ __skb_queue_tail(amsdu, msdu); ++ ++ rx_desc = (struct htt_rx_desc *)msdu->data; ++ ++@@ -343,12 +319,8 @@ static int ath10k_htt_rx_amsdu_pop(struc ++ */ ++ if (!(__le32_to_cpu(rx_desc->attention.flags) ++ & RX_ATTENTION_FLAGS_MSDU_DONE)) { ++- ath10k_htt_rx_free_msdu_chain(*head_msdu); ++- *head_msdu = NULL; ++- msdu = NULL; ++- ath10k_err("htt rx stopped. cannot recover\n"); ++- htt->rx_confused = true; ++- break; +++ __skb_queue_purge(amsdu); +++ return -EIO; ++ } ++ ++ /* ++@@ -399,7 +371,6 @@ static int ath10k_htt_rx_amsdu_pop(struc ++ msdu_len = MS(__le32_to_cpu(rx_desc->msdu_start.info0), ++ RX_MSDU_START_INFO0_MSDU_LENGTH); ++ msdu_chained = rx_desc->frag_info.ring2_more_count; ++- msdu_chaining = msdu_chained; ++ ++ if (msdu_len_invalid) ++ msdu_len = 0; ++@@ -408,42 +379,32 @@ static int ath10k_htt_rx_amsdu_pop(struc ++ skb_put(msdu, min(msdu_len, HTT_RX_MSDU_SIZE)); ++ msdu_len -= msdu->len; ++ ++- /* FIXME: Do chained buffers include htt_rx_desc or not? */ +++ /* Note: Chained buffers do not contain rx descriptor */ ++ while (msdu_chained--) { ++- struct sk_buff *next = ath10k_htt_rx_netbuf_pop(htt); ++- ++- dma_unmap_single(htt->ar->dev, ++- ATH10K_SKB_CB(next)->paddr, ++- next->len + skb_tailroom(next), ++- DMA_FROM_DEVICE); ++- ++- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, ++- "htt rx chained: ", next->data, ++- next->len + skb_tailroom(next)); ++- ++- skb_trim(next, 0); ++- skb_put(next, min(msdu_len, HTT_RX_BUF_SIZE)); ++- msdu_len -= next->len; +++ msdu = ath10k_htt_rx_netbuf_pop(htt); +++ if (!msdu) { +++ __skb_queue_purge(amsdu); +++ return -ENOENT; +++ } ++ ++- msdu->next = next; ++- msdu = next; +++ __skb_queue_tail(amsdu, msdu); +++ skb_trim(msdu, 0); +++ skb_put(msdu, min(msdu_len, HTT_RX_BUF_SIZE)); +++ msdu_len -= msdu->len; +++ msdu_chaining = 1; ++ } ++ ++ last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) & ++ RX_MSDU_END_INFO0_LAST_MSDU; ++ ++- if (last_msdu) { ++- msdu->next = NULL; +++ trace_ath10k_htt_rx_desc(ar, &rx_desc->attention, +++ sizeof(*rx_desc) - sizeof(u32)); +++ +++ if (last_msdu) ++ break; ++- } else { ++- struct sk_buff *next = ath10k_htt_rx_netbuf_pop(htt); ++- msdu->next = next; ++- msdu = next; ++- } ++ } ++- *tail_msdu = msdu; ++ ++- if (*head_msdu == NULL) +++ if (skb_queue_empty(amsdu)) ++ msdu_chaining = -1; ++ ++ /* ++@@ -465,43 +426,117 @@ static int ath10k_htt_rx_amsdu_pop(struc ++ static void ath10k_htt_rx_replenish_task(unsigned long ptr) ++ { ++ struct ath10k_htt *htt = (struct ath10k_htt *)ptr; +++ ++ ath10k_htt_rx_msdu_buff_replenish(htt); ++ } ++ ++-int ath10k_htt_rx_attach(struct ath10k_htt *htt) +++static struct sk_buff *ath10k_htt_rx_pop_paddr(struct ath10k_htt *htt, +++ u32 paddr) +++{ +++ struct ath10k *ar = htt->ar; +++ struct ath10k_skb_rxcb *rxcb; +++ struct sk_buff *msdu; +++ +++ lockdep_assert_held(&htt->rx_ring.lock); +++ +++ msdu = ath10k_htt_rx_find_skb_paddr(ar, paddr); +++ if (!msdu) +++ return NULL; +++ +++ rxcb = ATH10K_SKB_RXCB(msdu); +++ hash_del(&rxcb->hlist); +++ htt->rx_ring.fill_cnt--; +++ +++ dma_unmap_single(htt->ar->dev, rxcb->paddr, +++ msdu->len + skb_tailroom(msdu), +++ DMA_FROM_DEVICE); +++ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx netbuf pop: ", +++ msdu->data, msdu->len + skb_tailroom(msdu)); +++ +++ return msdu; +++} +++ +++static int ath10k_htt_rx_pop_paddr_list(struct ath10k_htt *htt, +++ struct htt_rx_in_ord_ind *ev, +++ struct sk_buff_head *list) ++ { +++ struct ath10k *ar = htt->ar; +++ struct htt_rx_in_ord_msdu_desc *msdu_desc = ev->msdu_descs; +++ struct htt_rx_desc *rxd; +++ struct sk_buff *msdu; +++ int msdu_count; +++ bool is_offload; +++ u32 paddr; +++ +++ lockdep_assert_held(&htt->rx_ring.lock); +++ +++ msdu_count = __le16_to_cpu(ev->msdu_count); +++ is_offload = !!(ev->info & HTT_RX_IN_ORD_IND_INFO_OFFLOAD_MASK); +++ +++ while (msdu_count--) { +++ paddr = __le32_to_cpu(msdu_desc->msdu_paddr); +++ +++ msdu = ath10k_htt_rx_pop_paddr(htt, paddr); +++ if (!msdu) { +++ __skb_queue_purge(list); +++ return -ENOENT; +++ } +++ +++ __skb_queue_tail(list, msdu); +++ +++ if (!is_offload) { +++ rxd = (void *)msdu->data; +++ +++ trace_ath10k_htt_rx_desc(ar, rxd, sizeof(*rxd)); +++ +++ skb_put(msdu, sizeof(*rxd)); +++ skb_pull(msdu, sizeof(*rxd)); +++ skb_put(msdu, __le16_to_cpu(msdu_desc->msdu_len)); +++ +++ if (!(__le32_to_cpu(rxd->attention.flags) & +++ RX_ATTENTION_FLAGS_MSDU_DONE)) { +++ ath10k_warn(htt->ar, "tried to pop an incomplete frame, oops!\n"); +++ return -EIO; +++ } +++ } +++ +++ msdu_desc++; +++ } +++ +++ return 0; +++} +++ +++int ath10k_htt_rx_alloc(struct ath10k_htt *htt) +++{ +++ struct ath10k *ar = htt->ar; ++ dma_addr_t paddr; ++ void *vaddr; +++ size_t size; ++ struct timer_list *timer = &htt->rx_ring.refill_retry_timer; ++ ++- htt->rx_ring.size = ath10k_htt_rx_ring_size(htt); ++- if (!is_power_of_2(htt->rx_ring.size)) { ++- ath10k_warn("htt rx ring size is not power of 2\n"); ++- return -EINVAL; ++- } +++ htt->rx_confused = false; ++ +++ /* XXX: The fill level could be changed during runtime in response to +++ * the host processing latency. Is this really worth it? +++ */ +++ htt->rx_ring.size = HTT_RX_RING_SIZE; ++ htt->rx_ring.size_mask = htt->rx_ring.size - 1; +++ htt->rx_ring.fill_level = HTT_RX_RING_FILL_LEVEL; ++ ++- /* ++- * Set the initial value for the level to which the rx ring ++- * should be filled, based on the max throughput and the ++- * worst likely latency for the host to fill the rx ring ++- * with new buffers. In theory, this fill level can be ++- * dynamically adjusted from the initial value set here, to ++- * reflect the actual host latency rather than a ++- * conservative assumption about the host latency. ++- */ ++- htt->rx_ring.fill_level = ath10k_htt_rx_ring_fill_level(htt); +++ if (!is_power_of_2(htt->rx_ring.size)) { +++ ath10k_warn(ar, "htt rx ring size is not power of 2\n"); +++ return -EINVAL; +++ } ++ ++ htt->rx_ring.netbufs_ring = ++- kmalloc(htt->rx_ring.size * sizeof(struct sk_buff *), +++ kzalloc(htt->rx_ring.size * sizeof(struct sk_buff *), ++ GFP_KERNEL); ++ if (!htt->rx_ring.netbufs_ring) ++ goto err_netbuf; ++ ++- vaddr = dma_alloc_coherent(htt->ar->dev, ++- (htt->rx_ring.size * sizeof(htt->rx_ring.paddrs_ring)), ++- &paddr, GFP_DMA); +++ size = htt->rx_ring.size * sizeof(htt->rx_ring.paddrs_ring); +++ +++ vaddr = dma_alloc_coherent(htt->ar->dev, size, &paddr, GFP_DMA); ++ if (!vaddr) ++ goto err_dma_ring; ++ ++@@ -516,7 +551,7 @@ int ath10k_htt_rx_attach(struct ath10k_h ++ ++ htt->rx_ring.alloc_idx.vaddr = vaddr; ++ htt->rx_ring.alloc_idx.paddr = paddr; ++- htt->rx_ring.sw_rd_idx.msdu_payld = 0; +++ htt->rx_ring.sw_rd_idx.msdu_payld = htt->rx_ring.size_mask; ++ *htt->rx_ring.alloc_idx.vaddr = 0; ++ ++ /* Initialize the Rx refill retry timer */ ++@@ -525,28 +560,23 @@ int ath10k_htt_rx_attach(struct ath10k_h ++ spin_lock_init(&htt->rx_ring.lock); ++ ++ htt->rx_ring.fill_cnt = 0; ++- if (__ath10k_htt_rx_ring_fill_n(htt, htt->rx_ring.fill_level)) ++- goto err_fill_ring; +++ htt->rx_ring.sw_rd_idx.msdu_payld = 0; +++ hash_init(htt->rx_ring.skb_table); ++ ++ tasklet_init(&htt->rx_replenish_task, ath10k_htt_rx_replenish_task, ++ (unsigned long)htt); ++ ++ skb_queue_head_init(&htt->tx_compl_q); ++ skb_queue_head_init(&htt->rx_compl_q); +++ skb_queue_head_init(&htt->rx_in_ord_compl_q); ++ ++ tasklet_init(&htt->txrx_compl_task, ath10k_htt_txrx_compl_task, ++ (unsigned long)htt); ++ ++- ath10k_dbg(ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n", +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n", ++ htt->rx_ring.size, htt->rx_ring.fill_level); ++ return 0; ++ ++-err_fill_ring: ++- ath10k_htt_rx_ring_free(htt); ++- dma_free_coherent(htt->ar->dev, ++- sizeof(*htt->rx_ring.alloc_idx.vaddr), ++- htt->rx_ring.alloc_idx.vaddr, ++- htt->rx_ring.alloc_idx.paddr); ++ err_dma_idx: ++ dma_free_coherent(htt->ar->dev, ++ (htt->rx_ring.size * ++@@ -559,73 +589,54 @@ err_netbuf: ++ return -ENOMEM; ++ } ++ ++-static int ath10k_htt_rx_crypto_param_len(enum htt_rx_mpdu_encrypt_type type) +++static int ath10k_htt_rx_crypto_param_len(struct ath10k *ar, +++ enum htt_rx_mpdu_encrypt_type type) ++ { ++ switch (type) { +++ case HTT_RX_MPDU_ENCRYPT_NONE: +++ return 0; ++ case HTT_RX_MPDU_ENCRYPT_WEP40: ++ case HTT_RX_MPDU_ENCRYPT_WEP104: ++- return 4; +++ return IEEE80211_WEP_IV_LEN; ++ case HTT_RX_MPDU_ENCRYPT_TKIP_WITHOUT_MIC: ++- case HTT_RX_MPDU_ENCRYPT_WEP128: /* not tested */ ++ case HTT_RX_MPDU_ENCRYPT_TKIP_WPA: ++- case HTT_RX_MPDU_ENCRYPT_WAPI: /* not tested */ +++ return IEEE80211_TKIP_IV_LEN; ++ case HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2: ++- return 8; ++- case HTT_RX_MPDU_ENCRYPT_NONE: ++- return 0; +++ return IEEE80211_CCMP_HDR_LEN; +++ case HTT_RX_MPDU_ENCRYPT_WEP128: +++ case HTT_RX_MPDU_ENCRYPT_WAPI: +++ break; ++ } ++ ++- ath10k_warn("unknown encryption type %d\n", type); +++ ath10k_warn(ar, "unsupported encryption type %d\n", type); ++ return 0; ++ } ++ ++-static int ath10k_htt_rx_crypto_tail_len(enum htt_rx_mpdu_encrypt_type type) +++#define MICHAEL_MIC_LEN 8 +++ +++static int ath10k_htt_rx_crypto_tail_len(struct ath10k *ar, +++ enum htt_rx_mpdu_encrypt_type type) ++ { ++ switch (type) { ++ case HTT_RX_MPDU_ENCRYPT_NONE: +++ return 0; ++ case HTT_RX_MPDU_ENCRYPT_WEP40: ++ case HTT_RX_MPDU_ENCRYPT_WEP104: ++- case HTT_RX_MPDU_ENCRYPT_WEP128: ++- case HTT_RX_MPDU_ENCRYPT_WAPI: ++- return 0; +++ return IEEE80211_WEP_ICV_LEN; ++ case HTT_RX_MPDU_ENCRYPT_TKIP_WITHOUT_MIC: ++ case HTT_RX_MPDU_ENCRYPT_TKIP_WPA: ++- return 4; +++ return IEEE80211_TKIP_ICV_LEN; ++ case HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2: ++- return 8; +++ return IEEE80211_CCMP_MIC_LEN; +++ case HTT_RX_MPDU_ENCRYPT_WEP128: +++ case HTT_RX_MPDU_ENCRYPT_WAPI: +++ break; ++ } ++ ++- ath10k_warn("unknown encryption type %d\n", type); +++ ath10k_warn(ar, "unsupported encryption type %d\n", type); ++ return 0; ++ } ++ ++-/* Applies for first msdu in chain, before altering it. */ ++-static struct ieee80211_hdr *ath10k_htt_rx_skb_get_hdr(struct sk_buff *skb) ++-{ ++- struct htt_rx_desc *rxd; ++- enum rx_msdu_decap_format fmt; ++- ++- rxd = (void *)skb->data - sizeof(*rxd); ++- fmt = MS(__le32_to_cpu(rxd->msdu_start.info1), ++- RX_MSDU_START_INFO1_DECAP_FORMAT); ++- ++- if (fmt == RX_MSDU_DECAP_RAW) ++- return (void *)skb->data; ++- else ++- return (void *)skb->data - RX_HTT_HDR_STATUS_LEN; ++-} ++- ++-/* This function only applies for first msdu in an msdu chain */ ++-static bool ath10k_htt_rx_hdr_is_amsdu(struct ieee80211_hdr *hdr) ++-{ ++- if (ieee80211_is_data_qos(hdr->frame_control)) { ++- u8 *qc = ieee80211_get_qos_ctl(hdr); ++- if (qc[0] & 0x80) ++- return true; ++- } ++- return false; ++-} ++- ++ struct rfc1042_hdr { ++ u8 llc_dsap; ++ u8 llc_ssap; ++@@ -660,23 +671,34 @@ static const u8 rx_legacy_rate_idx[] = { ++ }; ++ ++ static void ath10k_htt_rx_h_rates(struct ath10k *ar, ++- enum ieee80211_band band, ++- u8 info0, u32 info1, u32 info2, ++- struct ieee80211_rx_status *status) +++ struct ieee80211_rx_status *status, +++ struct htt_rx_desc *rxd) ++ { +++ enum ieee80211_band band; ++ u8 cck, rate, rate_idx, bw, sgi, mcs, nss; ++ u8 preamble = 0; +++ u32 info1, info2, info3; ++ ++- /* Check if valid fields */ ++- if (!(info0 & HTT_RX_INDICATION_INFO0_START_VALID)) +++ /* Band value can't be set as undefined but freq can be 0 - use that to +++ * determine whether band is provided. +++ * +++ * FIXME: Perhaps this can go away if CCK rate reporting is a little +++ * reworked? +++ */ +++ if (!status->freq) ++ return; ++ ++- preamble = MS(info1, HTT_RX_INDICATION_INFO1_PREAMBLE_TYPE); +++ band = status->band; +++ info1 = __le32_to_cpu(rxd->ppdu_start.info1); +++ info2 = __le32_to_cpu(rxd->ppdu_start.info2); +++ info3 = __le32_to_cpu(rxd->ppdu_start.info3); +++ +++ preamble = MS(info1, RX_PPDU_START_INFO1_PREAMBLE_TYPE); ++ ++ switch (preamble) { ++ case HTT_RX_LEGACY: ++- cck = info0 & HTT_RX_INDICATION_INFO0_LEGACY_RATE_CCK; ++- rate = MS(info0, HTT_RX_INDICATION_INFO0_LEGACY_RATE); +++ cck = info1 & RX_PPDU_START_INFO1_L_SIG_RATE_SELECT; +++ rate = MS(info1, RX_PPDU_START_INFO1_L_SIG_RATE); ++ rate_idx = 0; ++ ++ if (rate < 0x08 || rate > 0x0F) ++@@ -703,11 +725,11 @@ static void ath10k_htt_rx_h_rates(struct ++ break; ++ case HTT_RX_HT: ++ case HTT_RX_HT_WITH_TXBF: ++- /* HT-SIG - Table 20-11 in info1 and info2 */ ++- mcs = info1 & 0x1F; +++ /* HT-SIG - Table 20-11 in info2 and info3 */ +++ mcs = info2 & 0x1F; ++ nss = mcs >> 3; ++- bw = (info1 >> 7) & 1; ++- sgi = (info2 >> 7) & 1; +++ bw = (info2 >> 7) & 1; +++ sgi = (info3 >> 7) & 1; ++ ++ status->rate_idx = mcs; ++ status->flag |= RX_FLAG_HT; ++@@ -718,12 +740,12 @@ static void ath10k_htt_rx_h_rates(struct ++ break; ++ case HTT_RX_VHT: ++ case HTT_RX_VHT_WITH_TXBF: ++- /* VHT-SIG-A1 in info 1, VHT-SIG-A2 in info2 +++ /* VHT-SIG-A1 in info2, VHT-SIG-A2 in info3 ++ TODO check this */ ++- mcs = (info2 >> 4) & 0x0F; ++- nss = ((info1 >> 10) & 0x07) + 1; ++- bw = info1 & 3; ++- sgi = info2 & 1; +++ mcs = (info3 >> 4) & 0x0F; +++ nss = ((info2 >> 10) & 0x07) + 1; +++ bw = info2 & 3; +++ sgi = info3 & 1; ++ ++ status->rate_idx = mcs; ++ status->vht_nss = nss; ++@@ -751,28 +773,6 @@ static void ath10k_htt_rx_h_rates(struct ++ } ++ } ++ ++-static void ath10k_htt_rx_h_protected(struct ath10k_htt *htt, ++- struct ieee80211_rx_status *rx_status, ++- struct sk_buff *skb, ++- enum htt_rx_mpdu_encrypt_type enctype) ++-{ ++- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; ++- ++- ++- if (enctype == HTT_RX_MPDU_ENCRYPT_NONE) { ++- rx_status->flag &= ~(RX_FLAG_DECRYPTED | ++- RX_FLAG_IV_STRIPPED | ++- RX_FLAG_MMIC_STRIPPED); ++- return; ++- } ++- ++- rx_status->flag |= RX_FLAG_DECRYPTED | ++- RX_FLAG_IV_STRIPPED | ++- RX_FLAG_MMIC_STRIPPED; ++- hdr->frame_control = __cpu_to_le16(__le16_to_cpu(hdr->frame_control) & ++- ~IEEE80211_FCTL_PROTECTED); ++-} ++- ++ static bool ath10k_htt_rx_h_channel(struct ath10k *ar, ++ struct ieee80211_rx_status *status) ++ { ++@@ -793,19 +793,121 @@ static bool ath10k_htt_rx_h_channel(stru ++ return true; ++ } ++ +++static void ath10k_htt_rx_h_signal(struct ath10k *ar, +++ struct ieee80211_rx_status *status, +++ struct htt_rx_desc *rxd) +++{ +++ /* FIXME: Get real NF */ +++ status->signal = ATH10K_DEFAULT_NOISE_FLOOR + +++ rxd->ppdu_start.rssi_comb; +++ status->flag &= ~RX_FLAG_NO_SIGNAL_VAL; +++} +++ +++static void ath10k_htt_rx_h_mactime(struct ath10k *ar, +++ struct ieee80211_rx_status *status, +++ struct htt_rx_desc *rxd) +++{ +++ /* FIXME: TSF is known only at the end of PPDU, in the last MPDU. This +++ * means all prior MSDUs in a PPDU are reported to mac80211 without the +++ * TSF. Is it worth holding frames until end of PPDU is known? +++ * +++ * FIXME: Can we get/compute 64bit TSF? +++ */ +++ status->mactime = __le32_to_cpu(rxd->ppdu_end.common.tsf_timestamp); +++ status->flag |= RX_FLAG_MACTIME_END; +++} +++ +++static void ath10k_htt_rx_h_ppdu(struct ath10k *ar, +++ struct sk_buff_head *amsdu, +++ struct ieee80211_rx_status *status) +++{ +++ struct sk_buff *first; +++ struct htt_rx_desc *rxd; +++ bool is_first_ppdu; +++ bool is_last_ppdu; +++ +++ if (skb_queue_empty(amsdu)) +++ return; +++ +++ first = skb_peek(amsdu); +++ rxd = (void *)first->data - sizeof(*rxd); +++ +++ is_first_ppdu = !!(rxd->attention.flags & +++ __cpu_to_le32(RX_ATTENTION_FLAGS_FIRST_MPDU)); +++ is_last_ppdu = !!(rxd->attention.flags & +++ __cpu_to_le32(RX_ATTENTION_FLAGS_LAST_MPDU)); +++ +++ if (is_first_ppdu) { +++ /* New PPDU starts so clear out the old per-PPDU status. */ +++ status->freq = 0; +++ status->rate_idx = 0; +++ status->vht_nss = 0; +++ status->vht_flag &= ~RX_VHT_FLAG_80MHZ; +++ status->flag &= ~(RX_FLAG_HT | +++ RX_FLAG_VHT | +++ RX_FLAG_SHORT_GI | +++ RX_FLAG_40MHZ | +++ RX_FLAG_MACTIME_END); +++ status->flag |= RX_FLAG_NO_SIGNAL_VAL; +++ +++ ath10k_htt_rx_h_signal(ar, status, rxd); +++ ath10k_htt_rx_h_channel(ar, status); +++ ath10k_htt_rx_h_rates(ar, status, rxd); +++ } +++ +++ if (is_last_ppdu) +++ ath10k_htt_rx_h_mactime(ar, status, rxd); +++} +++ +++static const char * const tid_to_ac[] = { +++ "BE", +++ "BK", +++ "BK", +++ "BE", +++ "VI", +++ "VI", +++ "VO", +++ "VO", +++}; +++ +++static char *ath10k_get_tid(struct ieee80211_hdr *hdr, char *out, size_t size) +++{ +++ u8 *qc; +++ int tid; +++ +++ if (!ieee80211_is_data_qos(hdr->frame_control)) +++ return ""; +++ +++ qc = ieee80211_get_qos_ctl(hdr); +++ tid = *qc & IEEE80211_QOS_CTL_TID_MASK; +++ if (tid < 8) +++ snprintf(out, size, "tid %d (%s)", tid, tid_to_ac[tid]); +++ else +++ snprintf(out, size, "tid %d", tid); +++ +++ return out; +++} +++ ++ static void ath10k_process_rx(struct ath10k *ar, ++ struct ieee80211_rx_status *rx_status, ++ struct sk_buff *skb) ++ { ++ struct ieee80211_rx_status *status; +++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; +++ char tid[32]; ++ ++ status = IEEE80211_SKB_RXCB(skb); ++ *status = *rx_status; ++ ++- ath10k_dbg(ATH10K_DBG_DATA, ++- "rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %imic-err %i\n", +++ ath10k_dbg(ar, ATH10K_DBG_DATA, +++ "rx skb %p len %u peer %pM %s %s sn %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", ++ skb, ++ skb->len, +++ ieee80211_get_SA(hdr), +++ ath10k_get_tid(hdr, tid, sizeof(tid)), +++ is_multicast_ether_addr(ieee80211_get_DA(hdr)) ? +++ "mcast" : "ucast", +++ (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4, ++ status->flag == 0 ? "legacy" : "", ++ status->flag & RX_FLAG_HT ? "ht" : "", ++ status->flag & RX_FLAG_VHT ? "vht" : "", ++@@ -817,9 +919,12 @@ static void ath10k_process_rx(struct ath ++ status->freq, ++ status->band, status->flag, ++ !!(status->flag & RX_FLAG_FAILED_FCS_CRC), ++- !!(status->flag & RX_FLAG_MMIC_ERROR)); ++- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ", +++ !!(status->flag & RX_FLAG_MMIC_ERROR), +++ !!(status->flag & RX_FLAG_AMSDU_MORE)); +++ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ", ++ skb->data, skb->len); +++ trace_ath10k_rx_hdr(ar, skb->data, skb->len); +++ trace_ath10k_rx_payload(ar, skb->data, skb->len); ++ ++ ieee80211_rx(ar->hw, skb); ++ } ++@@ -830,179 +935,263 @@ static int ath10k_htt_rx_nwifi_hdrlen(st ++ return round_up(ieee80211_hdrlen(hdr->frame_control), 4); ++ } ++ ++-static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt, ++- struct ieee80211_rx_status *rx_status, ++- struct sk_buff *skb_in) +++static void ath10k_htt_rx_h_undecap_raw(struct ath10k *ar, +++ struct sk_buff *msdu, +++ struct ieee80211_rx_status *status, +++ enum htt_rx_mpdu_encrypt_type enctype, +++ bool is_decrypted) ++ { +++ struct ieee80211_hdr *hdr; ++ struct htt_rx_desc *rxd; ++- struct sk_buff *skb = skb_in; ++- struct sk_buff *first; ++- enum rx_msdu_decap_format fmt; ++- enum htt_rx_mpdu_encrypt_type enctype; +++ size_t hdr_len; +++ size_t crypto_len; +++ bool is_first; +++ bool is_last; +++ +++ rxd = (void *)msdu->data - sizeof(*rxd); +++ is_first = !!(rxd->msdu_end.info0 & +++ __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU)); +++ is_last = !!(rxd->msdu_end.info0 & +++ __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU)); +++ +++ /* Delivered decapped frame: +++ * [802.11 header] +++ * [crypto param] <-- can be trimmed if !fcs_err && +++ * !decrypt_err && !peer_idx_invalid +++ * [amsdu header] <-- only if A-MSDU +++ * [rfc1042/llc] +++ * [payload] +++ * [FCS] <-- at end, needs to be trimmed +++ */ +++ +++ /* This probably shouldn't happen but warn just in case */ +++ if (unlikely(WARN_ON_ONCE(!is_first))) +++ return; +++ +++ /* This probably shouldn't happen but warn just in case */ +++ if (unlikely(WARN_ON_ONCE(!(is_first && is_last)))) +++ return; +++ +++ skb_trim(msdu, msdu->len - FCS_LEN); +++ +++ /* In most cases this will be true for sniffed frames. It makes sense +++ * to deliver them as-is without stripping the crypto param. This would +++ * also make sense for software based decryption (which is not +++ * implemented in ath10k). +++ * +++ * If there's no error then the frame is decrypted. At least that is +++ * the case for frames that come in via fragmented rx indication. +++ */ +++ if (!is_decrypted) +++ return; +++ +++ /* The payload is decrypted so strip crypto params. Start from tail +++ * since hdr is used to compute some stuff. +++ */ +++ +++ hdr = (void *)msdu->data; +++ +++ /* Tail */ +++ skb_trim(msdu, msdu->len - ath10k_htt_rx_crypto_tail_len(ar, enctype)); +++ +++ /* MMIC */ +++ if (!ieee80211_has_morefrags(hdr->frame_control) && +++ enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA) +++ skb_trim(msdu, msdu->len - 8); +++ +++ /* Head */ +++ hdr_len = ieee80211_hdrlen(hdr->frame_control); +++ crypto_len = ath10k_htt_rx_crypto_param_len(ar, enctype); +++ +++ memmove((void *)msdu->data + crypto_len, +++ (void *)msdu->data, hdr_len); +++ skb_pull(msdu, crypto_len); +++} +++ +++static void ath10k_htt_rx_h_undecap_nwifi(struct ath10k *ar, +++ struct sk_buff *msdu, +++ struct ieee80211_rx_status *status, +++ const u8 first_hdr[64]) +++{ ++ struct ieee80211_hdr *hdr; ++- u8 hdr_buf[64], addr[ETH_ALEN], *qos; ++- unsigned int hdr_len; +++ size_t hdr_len; +++ u8 da[ETH_ALEN]; +++ u8 sa[ETH_ALEN]; +++ +++ /* Delivered decapped frame: +++ * [nwifi 802.11 header] <-- replaced with 802.11 hdr +++ * [rfc1042/llc] +++ * +++ * Note: The nwifi header doesn't have QoS Control and is +++ * (always?) a 3addr frame. +++ * +++ * Note2: There's no A-MSDU subframe header. Even if it's part +++ * of an A-MSDU. +++ */ ++ ++- rxd = (void *)skb->data - sizeof(*rxd); ++- enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0), ++- RX_MPDU_START_INFO0_ENCRYPT_TYPE); +++ /* pull decapped header and copy SA & DA */ +++ hdr = (struct ieee80211_hdr *)msdu->data; +++ hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr); +++ ether_addr_copy(da, ieee80211_get_DA(hdr)); +++ ether_addr_copy(sa, ieee80211_get_SA(hdr)); +++ skb_pull(msdu, hdr_len); ++ ++- hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status; +++ /* push original 802.11 header */ +++ hdr = (struct ieee80211_hdr *)first_hdr; ++ hdr_len = ieee80211_hdrlen(hdr->frame_control); ++- memcpy(hdr_buf, hdr, hdr_len); ++- hdr = (struct ieee80211_hdr *)hdr_buf; +++ memcpy(skb_push(msdu, hdr_len), hdr, hdr_len); ++ ++- first = skb; ++- while (skb) { ++- void *decap_hdr; ++- int len; ++- ++- rxd = (void *)skb->data - sizeof(*rxd); ++- fmt = MS(__le32_to_cpu(rxd->msdu_start.info1), ++- RX_MSDU_START_INFO1_DECAP_FORMAT); ++- decap_hdr = (void *)rxd->rx_hdr_status; ++- ++- skb->ip_summed = ath10k_htt_rx_get_csum_state(skb); ++- ++- /* First frame in an A-MSDU chain has more decapped data. */ ++- if (skb == first) { ++- len = round_up(ieee80211_hdrlen(hdr->frame_control), 4); ++- len += round_up(ath10k_htt_rx_crypto_param_len(enctype), ++- 4); ++- decap_hdr += len; ++- } +++ /* original 802.11 header has a different DA and in +++ * case of 4addr it may also have different SA +++ */ +++ hdr = (struct ieee80211_hdr *)msdu->data; +++ ether_addr_copy(ieee80211_get_DA(hdr), da); +++ ether_addr_copy(ieee80211_get_SA(hdr), sa); +++} ++ ++- switch (fmt) { ++- case RX_MSDU_DECAP_RAW: ++- /* remove trailing FCS */ ++- skb_trim(skb, skb->len - FCS_LEN); ++- break; ++- case RX_MSDU_DECAP_NATIVE_WIFI: ++- /* pull decapped header and copy DA */ ++- hdr = (struct ieee80211_hdr *)skb->data; ++- hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr); ++- memcpy(addr, ieee80211_get_DA(hdr), ETH_ALEN); ++- skb_pull(skb, hdr_len); ++- ++- /* push original 802.11 header */ ++- hdr = (struct ieee80211_hdr *)hdr_buf; ++- hdr_len = ieee80211_hdrlen(hdr->frame_control); ++- memcpy(skb_push(skb, hdr_len), hdr, hdr_len); ++- ++- /* original A-MSDU header has the bit set but we're ++- * not including A-MSDU subframe header */ ++- hdr = (struct ieee80211_hdr *)skb->data; ++- qos = ieee80211_get_qos_ctl(hdr); ++- qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; +++static void *ath10k_htt_rx_h_find_rfc1042(struct ath10k *ar, +++ struct sk_buff *msdu, +++ enum htt_rx_mpdu_encrypt_type enctype) +++{ +++ struct ieee80211_hdr *hdr; +++ struct htt_rx_desc *rxd; +++ size_t hdr_len, crypto_len; +++ void *rfc1042; +++ bool is_first, is_last, is_amsdu; ++ ++- /* original 802.11 header has a different DA */ ++- memcpy(ieee80211_get_DA(hdr), addr, ETH_ALEN); ++- break; ++- case RX_MSDU_DECAP_ETHERNET2_DIX: ++- /* strip ethernet header and insert decapped 802.11 ++- * header, amsdu subframe header and rfc1042 header */ ++- ++- len = 0; ++- len += sizeof(struct rfc1042_hdr); ++- len += sizeof(struct amsdu_subframe_hdr); ++- ++- skb_pull(skb, sizeof(struct ethhdr)); ++- memcpy(skb_push(skb, len), decap_hdr, len); ++- memcpy(skb_push(skb, hdr_len), hdr, hdr_len); ++- break; ++- case RX_MSDU_DECAP_8023_SNAP_LLC: ++- /* insert decapped 802.11 header making a singly ++- * A-MSDU */ ++- memcpy(skb_push(skb, hdr_len), hdr, hdr_len); ++- break; ++- } +++ rxd = (void *)msdu->data - sizeof(*rxd); +++ hdr = (void *)rxd->rx_hdr_status; ++ ++- skb_in = skb; ++- ath10k_htt_rx_h_protected(htt, rx_status, skb_in, enctype); ++- skb = skb->next; ++- skb_in->next = NULL; +++ is_first = !!(rxd->msdu_end.info0 & +++ __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU)); +++ is_last = !!(rxd->msdu_end.info0 & +++ __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU)); +++ is_amsdu = !(is_first && is_last); ++ ++- if (skb) ++- rx_status->flag |= RX_FLAG_AMSDU_MORE; ++- else ++- rx_status->flag &= ~RX_FLAG_AMSDU_MORE; +++ rfc1042 = hdr; +++ +++ if (is_first) { +++ hdr_len = ieee80211_hdrlen(hdr->frame_control); +++ crypto_len = ath10k_htt_rx_crypto_param_len(ar, enctype); ++ ++- ath10k_process_rx(htt->ar, rx_status, skb_in); +++ rfc1042 += round_up(hdr_len, 4) + +++ round_up(crypto_len, 4); ++ } ++ ++- /* FIXME: It might be nice to re-assemble the A-MSDU when there's a ++- * monitor interface active for sniffing purposes. */ +++ if (is_amsdu) +++ rfc1042 += sizeof(struct amsdu_subframe_hdr); +++ +++ return rfc1042; ++ } ++ ++-static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, ++- struct ieee80211_rx_status *rx_status, ++- struct sk_buff *skb) +++static void ath10k_htt_rx_h_undecap_eth(struct ath10k *ar, +++ struct sk_buff *msdu, +++ struct ieee80211_rx_status *status, +++ const u8 first_hdr[64], +++ enum htt_rx_mpdu_encrypt_type enctype) ++ { ++- struct htt_rx_desc *rxd; ++ struct ieee80211_hdr *hdr; ++- enum rx_msdu_decap_format fmt; ++- enum htt_rx_mpdu_encrypt_type enctype; ++- int hdr_len; +++ struct ethhdr *eth; +++ size_t hdr_len; ++ void *rfc1042; +++ u8 da[ETH_ALEN]; +++ u8 sa[ETH_ALEN]; ++ ++- /* This shouldn't happen. If it does than it may be a FW bug. */ ++- if (skb->next) { ++- ath10k_warn("htt rx received chained non A-MSDU frame\n"); ++- ath10k_htt_rx_free_msdu_chain(skb->next); ++- skb->next = NULL; ++- } +++ /* Delivered decapped frame: +++ * [eth header] <-- replaced with 802.11 hdr & rfc1042/llc +++ * [payload] +++ */ ++ ++- rxd = (void *)skb->data - sizeof(*rxd); ++- fmt = MS(__le32_to_cpu(rxd->msdu_start.info1), ++- RX_MSDU_START_INFO1_DECAP_FORMAT); ++- enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0), ++- RX_MPDU_START_INFO0_ENCRYPT_TYPE); ++- hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status; +++ rfc1042 = ath10k_htt_rx_h_find_rfc1042(ar, msdu, enctype); +++ if (WARN_ON_ONCE(!rfc1042)) +++ return; +++ +++ /* pull decapped header and copy SA & DA */ +++ eth = (struct ethhdr *)msdu->data; +++ ether_addr_copy(da, eth->h_dest); +++ ether_addr_copy(sa, eth->h_source); +++ skb_pull(msdu, sizeof(struct ethhdr)); +++ +++ /* push rfc1042/llc/snap */ +++ memcpy(skb_push(msdu, sizeof(struct rfc1042_hdr)), rfc1042, +++ sizeof(struct rfc1042_hdr)); +++ +++ /* push original 802.11 header */ +++ hdr = (struct ieee80211_hdr *)first_hdr; ++ hdr_len = ieee80211_hdrlen(hdr->frame_control); +++ memcpy(skb_push(msdu, hdr_len), hdr, hdr_len); +++ +++ /* original 802.11 header has a different DA and in +++ * case of 4addr it may also have different SA +++ */ +++ hdr = (struct ieee80211_hdr *)msdu->data; +++ ether_addr_copy(ieee80211_get_DA(hdr), da); +++ ether_addr_copy(ieee80211_get_SA(hdr), sa); +++} +++ +++static void ath10k_htt_rx_h_undecap_snap(struct ath10k *ar, +++ struct sk_buff *msdu, +++ struct ieee80211_rx_status *status, +++ const u8 first_hdr[64]) +++{ +++ struct ieee80211_hdr *hdr; +++ size_t hdr_len; +++ +++ /* Delivered decapped frame: +++ * [amsdu header] <-- replaced with 802.11 hdr +++ * [rfc1042/llc] +++ * [payload] +++ */ +++ +++ skb_pull(msdu, sizeof(struct amsdu_subframe_hdr)); +++ +++ hdr = (struct ieee80211_hdr *)first_hdr; +++ hdr_len = ieee80211_hdrlen(hdr->frame_control); +++ memcpy(skb_push(msdu, hdr_len), hdr, hdr_len); +++} +++ +++static void ath10k_htt_rx_h_undecap(struct ath10k *ar, +++ struct sk_buff *msdu, +++ struct ieee80211_rx_status *status, +++ u8 first_hdr[64], +++ enum htt_rx_mpdu_encrypt_type enctype, +++ bool is_decrypted) +++{ +++ struct htt_rx_desc *rxd; +++ enum rx_msdu_decap_format decap; +++ struct ieee80211_hdr *hdr; +++ +++ /* First msdu's decapped header: +++ * [802.11 header] <-- padded to 4 bytes long +++ * [crypto param] <-- padded to 4 bytes long +++ * [amsdu header] <-- only if A-MSDU +++ * [rfc1042/llc] +++ * +++ * Other (2nd, 3rd, ..) msdu's decapped header: +++ * [amsdu header] <-- only if A-MSDU +++ * [rfc1042/llc] +++ */ ++ ++- skb->ip_summed = ath10k_htt_rx_get_csum_state(skb); +++ rxd = (void *)msdu->data - sizeof(*rxd); +++ hdr = (void *)rxd->rx_hdr_status; +++ decap = MS(__le32_to_cpu(rxd->msdu_start.info1), +++ RX_MSDU_START_INFO1_DECAP_FORMAT); ++ ++- switch (fmt) { +++ switch (decap) { ++ case RX_MSDU_DECAP_RAW: ++- /* remove trailing FCS */ ++- skb_trim(skb, skb->len - FCS_LEN); +++ ath10k_htt_rx_h_undecap_raw(ar, msdu, status, enctype, +++ is_decrypted); ++ break; ++ case RX_MSDU_DECAP_NATIVE_WIFI: ++- /* Pull decapped header */ ++- hdr = (struct ieee80211_hdr *)skb->data; ++- hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr); ++- skb_pull(skb, hdr_len); ++- ++- /* Push original header */ ++- hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status; ++- hdr_len = ieee80211_hdrlen(hdr->frame_control); ++- memcpy(skb_push(skb, hdr_len), hdr, hdr_len); +++ ath10k_htt_rx_h_undecap_nwifi(ar, msdu, status, first_hdr); ++ break; ++ case RX_MSDU_DECAP_ETHERNET2_DIX: ++- /* strip ethernet header and insert decapped 802.11 header and ++- * rfc1042 header */ ++- ++- rfc1042 = hdr; ++- rfc1042 += roundup(hdr_len, 4); ++- rfc1042 += roundup(ath10k_htt_rx_crypto_param_len(enctype), 4); ++- ++- skb_pull(skb, sizeof(struct ethhdr)); ++- memcpy(skb_push(skb, sizeof(struct rfc1042_hdr)), ++- rfc1042, sizeof(struct rfc1042_hdr)); ++- memcpy(skb_push(skb, hdr_len), hdr, hdr_len); +++ ath10k_htt_rx_h_undecap_eth(ar, msdu, status, first_hdr, enctype); ++ break; ++ case RX_MSDU_DECAP_8023_SNAP_LLC: ++- /* remove A-MSDU subframe header and insert ++- * decapped 802.11 header. rfc1042 header is already there */ ++- ++- skb_pull(skb, sizeof(struct amsdu_subframe_hdr)); ++- memcpy(skb_push(skb, hdr_len), hdr, hdr_len); +++ ath10k_htt_rx_h_undecap_snap(ar, msdu, status, first_hdr); ++ break; ++ } ++- ++- ath10k_htt_rx_h_protected(htt, rx_status, skb, enctype); ++- ++- ath10k_process_rx(htt->ar, rx_status, skb); ++ } ++ ++ static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb) ++@@ -1036,10 +1225,128 @@ static int ath10k_htt_rx_get_csum_state( ++ return CHECKSUM_UNNECESSARY; ++ } ++ ++-static int ath10k_unchain_msdu(struct sk_buff *msdu_head) +++static void ath10k_htt_rx_h_csum_offload(struct sk_buff *msdu) +++{ +++ msdu->ip_summed = ath10k_htt_rx_get_csum_state(msdu); +++} +++ +++static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, +++ struct sk_buff_head *amsdu, +++ struct ieee80211_rx_status *status) +++{ +++ struct sk_buff *first; +++ struct sk_buff *last; +++ struct sk_buff *msdu; +++ struct htt_rx_desc *rxd; +++ struct ieee80211_hdr *hdr; +++ enum htt_rx_mpdu_encrypt_type enctype; +++ u8 first_hdr[64]; +++ u8 *qos; +++ size_t hdr_len; +++ bool has_fcs_err; +++ bool has_crypto_err; +++ bool has_tkip_err; +++ bool has_peer_idx_invalid; +++ bool is_decrypted; +++ u32 attention; +++ +++ if (skb_queue_empty(amsdu)) +++ return; +++ +++ first = skb_peek(amsdu); +++ rxd = (void *)first->data - sizeof(*rxd); +++ +++ enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0), +++ RX_MPDU_START_INFO0_ENCRYPT_TYPE); +++ +++ /* First MSDU's Rx descriptor in an A-MSDU contains full 802.11 +++ * decapped header. It'll be used for undecapping of each MSDU. +++ */ +++ hdr = (void *)rxd->rx_hdr_status; +++ hdr_len = ieee80211_hdrlen(hdr->frame_control); +++ memcpy(first_hdr, hdr, hdr_len); +++ +++ /* Each A-MSDU subframe will use the original header as the base and be +++ * reported as a separate MSDU so strip the A-MSDU bit from QoS Ctl. +++ */ +++ hdr = (void *)first_hdr; +++ qos = ieee80211_get_qos_ctl(hdr); +++ qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; +++ +++ /* Some attention flags are valid only in the last MSDU. */ +++ last = skb_peek_tail(amsdu); +++ rxd = (void *)last->data - sizeof(*rxd); +++ attention = __le32_to_cpu(rxd->attention.flags); +++ +++ has_fcs_err = !!(attention & RX_ATTENTION_FLAGS_FCS_ERR); +++ has_crypto_err = !!(attention & RX_ATTENTION_FLAGS_DECRYPT_ERR); +++ has_tkip_err = !!(attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR); +++ has_peer_idx_invalid = !!(attention & RX_ATTENTION_FLAGS_PEER_IDX_INVALID); +++ +++ /* Note: If hardware captures an encrypted frame that it can't decrypt, +++ * e.g. due to fcs error, missing peer or invalid key data it will +++ * report the frame as raw. +++ */ +++ is_decrypted = (enctype != HTT_RX_MPDU_ENCRYPT_NONE && +++ !has_fcs_err && +++ !has_crypto_err && +++ !has_peer_idx_invalid); +++ +++ /* Clear per-MPDU flags while leaving per-PPDU flags intact. */ +++ status->flag &= ~(RX_FLAG_FAILED_FCS_CRC | +++ RX_FLAG_MMIC_ERROR | +++ RX_FLAG_DECRYPTED | +++ RX_FLAG_IV_STRIPPED | +++ RX_FLAG_MMIC_STRIPPED); +++ +++ if (has_fcs_err) +++ status->flag |= RX_FLAG_FAILED_FCS_CRC; +++ +++ if (has_tkip_err) +++ status->flag |= RX_FLAG_MMIC_ERROR; +++ +++ if (is_decrypted) +++ status->flag |= RX_FLAG_DECRYPTED | +++ RX_FLAG_IV_STRIPPED | +++ RX_FLAG_MMIC_STRIPPED; +++ +++ skb_queue_walk(amsdu, msdu) { +++ ath10k_htt_rx_h_csum_offload(msdu); +++ ath10k_htt_rx_h_undecap(ar, msdu, status, first_hdr, enctype, +++ is_decrypted); +++ +++ /* Undecapping involves copying the original 802.11 header back +++ * to sk_buff. If frame is protected and hardware has decrypted +++ * it then remove the protected bit. +++ */ +++ if (!is_decrypted) +++ continue; +++ +++ hdr = (void *)msdu->data; +++ hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED); +++ } +++} +++ +++static void ath10k_htt_rx_h_deliver(struct ath10k *ar, +++ struct sk_buff_head *amsdu, +++ struct ieee80211_rx_status *status) +++{ +++ struct sk_buff *msdu; +++ +++ while ((msdu = __skb_dequeue(amsdu))) { +++ /* Setup per-MSDU flags */ +++ if (skb_queue_empty(amsdu)) +++ status->flag &= ~RX_FLAG_AMSDU_MORE; +++ else +++ status->flag |= RX_FLAG_AMSDU_MORE; +++ +++ ath10k_process_rx(ar, status, msdu); +++ } +++} +++ +++static int ath10k_unchain_msdu(struct sk_buff_head *amsdu) ++ { ++- struct sk_buff *next = msdu_head->next; ++- struct sk_buff *to_free = next; +++ struct sk_buff *skb, *first; ++ int space; ++ int total_len = 0; ++ ++@@ -1050,110 +1357,142 @@ static int ath10k_unchain_msdu(struct sk ++ * skb? ++ */ ++ ++- msdu_head->next = NULL; +++ first = __skb_dequeue(amsdu); ++ ++ /* Allocate total length all at once. */ ++- while (next) { ++- total_len += next->len; ++- next = next->next; ++- } +++ skb_queue_walk(amsdu, skb) +++ total_len += skb->len; ++ ++- space = total_len - skb_tailroom(msdu_head); +++ space = total_len - skb_tailroom(first); ++ if ((space > 0) && ++- (pskb_expand_head(msdu_head, 0, space, GFP_ATOMIC) < 0)) { +++ (pskb_expand_head(first, 0, space, GFP_ATOMIC) < 0)) { ++ /* TODO: bump some rx-oom error stat */ ++ /* put it back together so we can free the ++ * whole list at once. ++ */ ++- msdu_head->next = to_free; +++ __skb_queue_head(amsdu, first); ++ return -1; ++ } ++ ++ /* Walk list again, copying contents into ++ * msdu_head ++ */ ++- next = to_free; ++- while (next) { ++- skb_copy_from_linear_data(next, skb_put(msdu_head, next->len), ++- next->len); ++- next = next->next; +++ while ((skb = __skb_dequeue(amsdu))) { +++ skb_copy_from_linear_data(skb, skb_put(first, skb->len), +++ skb->len); +++ dev_kfree_skb_any(skb); ++ } ++ ++- /* If here, we have consolidated skb. Free the ++- * fragments and pass the main skb on up the ++- * stack. ++- */ ++- ath10k_htt_rx_free_msdu_chain(to_free); +++ __skb_queue_head(amsdu, first); ++ return 0; ++ } ++ ++-static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt, ++- struct sk_buff *head, ++- enum htt_rx_mpdu_status status, ++- bool channel_set, ++- u32 attention) ++-{ ++- if (head->len == 0) { ++- ath10k_dbg(ATH10K_DBG_HTT, ++- "htt rx dropping due to zero-len\n"); ++- return false; ++- } +++static void ath10k_htt_rx_h_unchain(struct ath10k *ar, +++ struct sk_buff_head *amsdu, +++ bool chained) +++{ +++ struct sk_buff *first; +++ struct htt_rx_desc *rxd; +++ enum rx_msdu_decap_format decap; ++ ++- if (attention & RX_ATTENTION_FLAGS_DECRYPT_ERR) { ++- ath10k_dbg(ATH10K_DBG_HTT, ++- "htt rx dropping due to decrypt-err\n"); ++- return false; ++- } +++ first = skb_peek(amsdu); +++ rxd = (void *)first->data - sizeof(*rxd); +++ decap = MS(__le32_to_cpu(rxd->msdu_start.info1), +++ RX_MSDU_START_INFO1_DECAP_FORMAT); ++ ++- if (!channel_set) { ++- ath10k_warn("no channel configured; ignoring frame!\n"); ++- return false; +++ if (!chained) +++ return; +++ +++ /* FIXME: Current unchaining logic can only handle simple case of raw +++ * msdu chaining. If decapping is other than raw the chaining may be +++ * more complex and this isn't handled by the current code. Don't even +++ * try re-constructing such frames - it'll be pretty much garbage. +++ */ +++ if (decap != RX_MSDU_DECAP_RAW || +++ skb_queue_len(amsdu) != 1 + rxd->frag_info.ring2_more_count) { +++ __skb_queue_purge(amsdu); +++ return; ++ } ++ ++- /* Skip mgmt frames while we handle this in WMI */ ++- if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL || ++- attention & RX_ATTENTION_FLAGS_MGMT_TYPE) { ++- ath10k_dbg(ATH10K_DBG_HTT, "htt rx mgmt ctrl\n"); +++ ath10k_unchain_msdu(amsdu); +++} +++ +++static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar, +++ struct sk_buff_head *amsdu, +++ struct ieee80211_rx_status *rx_status) +++{ +++ struct sk_buff *msdu; +++ struct htt_rx_desc *rxd; +++ bool is_mgmt; +++ bool has_fcs_err; +++ +++ msdu = skb_peek(amsdu); +++ rxd = (void *)msdu->data - sizeof(*rxd); +++ +++ /* FIXME: It might be a good idea to do some fuzzy-testing to drop +++ * invalid/dangerous frames. +++ */ +++ +++ if (!rx_status->freq) { +++ ath10k_warn(ar, "no channel configured; ignoring frame(s)!\n"); ++ return false; ++ } ++ ++- if (status != HTT_RX_IND_MPDU_STATUS_OK && ++- status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR && ++- status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER && ++- !htt->ar->monitor_started) { ++- ath10k_dbg(ATH10K_DBG_HTT, ++- "htt rx ignoring frame w/ status %d\n", ++- status); +++ is_mgmt = !!(rxd->attention.flags & +++ __cpu_to_le32(RX_ATTENTION_FLAGS_MGMT_TYPE)); +++ has_fcs_err = !!(rxd->attention.flags & +++ __cpu_to_le32(RX_ATTENTION_FLAGS_FCS_ERR)); +++ +++ /* Management frames are handled via WMI events. The pros of such +++ * approach is that channel is explicitly provided in WMI events +++ * whereas HTT doesn't provide channel information for Rxed frames. +++ * +++ * However some firmware revisions don't report corrupted frames via +++ * WMI so don't drop them. +++ */ +++ if (is_mgmt && !has_fcs_err) { +++ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx mgmt ctrl\n"); ++ return false; ++ } ++ ++- if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) { ++- ath10k_dbg(ATH10K_DBG_HTT, ++- "htt rx CAC running\n"); +++ if (test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) { +++ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx cac running\n"); ++ return false; ++ } ++ ++ return true; ++ } ++ +++static void ath10k_htt_rx_h_filter(struct ath10k *ar, +++ struct sk_buff_head *amsdu, +++ struct ieee80211_rx_status *rx_status) +++{ +++ if (skb_queue_empty(amsdu)) +++ return; +++ +++ if (ath10k_htt_rx_amsdu_allowed(ar, amsdu, rx_status)) +++ return; +++ +++ __skb_queue_purge(amsdu); +++} +++ ++ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, ++ struct htt_rx_indication *rx) ++ { +++ struct ath10k *ar = htt->ar; ++ struct ieee80211_rx_status *rx_status = &htt->rx_status; ++ struct htt_rx_indication_mpdu_range *mpdu_ranges; ++- struct htt_rx_desc *rxd; ++- enum htt_rx_mpdu_status status; ++- struct ieee80211_hdr *hdr; +++ struct sk_buff_head amsdu; ++ int num_mpdu_ranges; ++- u32 attention; ++ int fw_desc_len; ++ u8 *fw_desc; ++- bool channel_set; ++- int i, j; ++- int ret; +++ int i, ret, mpdu_count = 0; ++ ++ lockdep_assert_held(&htt->rx_ring.lock); ++ +++ if (htt->rx_confused) +++ return; +++ ++ fw_desc_len = __le16_to_cpu(rx->prefix.fw_rx_desc_bytes); ++ fw_desc = (u8 *)&rx->fw_desc; ++ ++@@ -1161,201 +1500,82 @@ static void ath10k_htt_rx_handler(struct ++ HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES); ++ mpdu_ranges = htt_rx_ind_get_mpdu_ranges(rx); ++ ++- /* Fill this once, while this is per-ppdu */ ++- if (rx->ppdu.info0 & HTT_RX_INDICATION_INFO0_START_VALID) { ++- memset(rx_status, 0, sizeof(*rx_status)); ++- rx_status->signal = ATH10K_DEFAULT_NOISE_FLOOR + ++- rx->ppdu.combined_rssi; ++- } ++- ++- if (rx->ppdu.info0 & HTT_RX_INDICATION_INFO0_END_VALID) { ++- /* TSF available only in 32-bit */ ++- rx_status->mactime = __le32_to_cpu(rx->ppdu.tsf) & 0xffffffff; ++- rx_status->flag |= RX_FLAG_MACTIME_END; ++- } ++- ++- channel_set = ath10k_htt_rx_h_channel(htt->ar, rx_status); ++- ++- if (channel_set) { ++- ath10k_htt_rx_h_rates(htt->ar, rx_status->band, ++- rx->ppdu.info0, ++- __le32_to_cpu(rx->ppdu.info1), ++- __le32_to_cpu(rx->ppdu.info2), ++- rx_status); ++- } ++- ++- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ", +++ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ", ++ rx, sizeof(*rx) + ++ (sizeof(struct htt_rx_indication_mpdu_range) * ++ num_mpdu_ranges)); ++ ++- for (i = 0; i < num_mpdu_ranges; i++) { ++- status = mpdu_ranges[i].mpdu_range_status; ++- ++- for (j = 0; j < mpdu_ranges[i].mpdu_count; j++) { ++- struct sk_buff *msdu_head, *msdu_tail; +++ for (i = 0; i < num_mpdu_ranges; i++) +++ mpdu_count += mpdu_ranges[i].mpdu_count; ++ ++- msdu_head = NULL; ++- msdu_tail = NULL; ++- ret = ath10k_htt_rx_amsdu_pop(htt, ++- &fw_desc, ++- &fw_desc_len, ++- &msdu_head, ++- &msdu_tail); ++- ++- if (ret < 0) { ++- ath10k_warn("failed to pop amsdu from htt rx ring %d\n", ++- ret); ++- ath10k_htt_rx_free_msdu_chain(msdu_head); ++- continue; ++- } ++- ++- rxd = container_of((void *)msdu_head->data, ++- struct htt_rx_desc, ++- msdu_payload); ++- attention = __le32_to_cpu(rxd->attention.flags); ++- ++- if (!ath10k_htt_rx_amsdu_allowed(htt, msdu_head, ++- status, ++- channel_set, ++- attention)) { ++- ath10k_htt_rx_free_msdu_chain(msdu_head); ++- continue; ++- } ++- ++- if (ret > 0 && ++- ath10k_unchain_msdu(msdu_head) < 0) { ++- ath10k_htt_rx_free_msdu_chain(msdu_head); ++- continue; ++- } ++- ++- if (attention & RX_ATTENTION_FLAGS_FCS_ERR) ++- rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; ++- else ++- rx_status->flag &= ~RX_FLAG_FAILED_FCS_CRC; ++- ++- if (attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR) ++- rx_status->flag |= RX_FLAG_MMIC_ERROR; ++- else ++- rx_status->flag &= ~RX_FLAG_MMIC_ERROR; ++- ++- hdr = ath10k_htt_rx_skb_get_hdr(msdu_head); ++- ++- if (ath10k_htt_rx_hdr_is_amsdu(hdr)) ++- ath10k_htt_rx_amsdu(htt, rx_status, msdu_head); ++- else ++- ath10k_htt_rx_msdu(htt, rx_status, msdu_head); +++ while (mpdu_count--) { +++ __skb_queue_head_init(&amsdu); +++ ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, +++ &fw_desc_len, &amsdu); +++ if (ret < 0) { +++ ath10k_warn(ar, "rx ring became corrupted: %d\n", ret); +++ __skb_queue_purge(&amsdu); +++ /* FIXME: It's probably a good idea to reboot the +++ * device instead of leaving it inoperable. +++ */ +++ htt->rx_confused = true; +++ break; ++ } +++ +++ ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status); +++ ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0); +++ ath10k_htt_rx_h_filter(ar, &amsdu, rx_status); +++ ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status); +++ ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status); ++ } ++ ++ tasklet_schedule(&htt->rx_replenish_task); ++ } ++ ++ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, ++- struct htt_rx_fragment_indication *frag) +++ struct htt_rx_fragment_indication *frag) ++ { ++- struct sk_buff *msdu_head, *msdu_tail; ++- enum htt_rx_mpdu_encrypt_type enctype; ++- struct htt_rx_desc *rxd; ++- enum rx_msdu_decap_format fmt; +++ struct ath10k *ar = htt->ar; ++ struct ieee80211_rx_status *rx_status = &htt->rx_status; ++- struct ieee80211_hdr *hdr; +++ struct sk_buff_head amsdu; ++ int ret; ++- bool tkip_mic_err; ++- bool decrypt_err; ++ u8 *fw_desc; ++- int fw_desc_len, hdrlen, paramlen; ++- int trim; +++ int fw_desc_len; ++ ++ fw_desc_len = __le16_to_cpu(frag->fw_rx_desc_bytes); ++ fw_desc = (u8 *)frag->fw_msdu_rx_desc; ++ ++- msdu_head = NULL; ++- msdu_tail = NULL; +++ __skb_queue_head_init(&amsdu); ++ ++ spin_lock_bh(&htt->rx_ring.lock); ++ ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len, ++- &msdu_head, &msdu_tail); +++ &amsdu); ++ spin_unlock_bh(&htt->rx_ring.lock); ++ ++- ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n"); +++ tasklet_schedule(&htt->rx_replenish_task); +++ +++ ath10k_dbg(ar, ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n"); ++ ++ if (ret) { ++- ath10k_warn("failed to pop amsdu from httr rx ring for fragmented rx %d\n", +++ ath10k_warn(ar, "failed to pop amsdu from httr rx ring for fragmented rx %d\n", ++ ret); ++- ath10k_htt_rx_free_msdu_chain(msdu_head); +++ __skb_queue_purge(&amsdu); ++ return; ++ } ++ ++- /* FIXME: implement signal strength */ ++- ++- hdr = (struct ieee80211_hdr *)msdu_head->data; ++- rxd = (void *)msdu_head->data - sizeof(*rxd); ++- tkip_mic_err = !!(__le32_to_cpu(rxd->attention.flags) & ++- RX_ATTENTION_FLAGS_TKIP_MIC_ERR); ++- decrypt_err = !!(__le32_to_cpu(rxd->attention.flags) & ++- RX_ATTENTION_FLAGS_DECRYPT_ERR); ++- fmt = MS(__le32_to_cpu(rxd->msdu_start.info1), ++- RX_MSDU_START_INFO1_DECAP_FORMAT); ++- ++- if (fmt != RX_MSDU_DECAP_RAW) { ++- ath10k_warn("we dont support non-raw fragmented rx yet\n"); ++- dev_kfree_skb_any(msdu_head); ++- goto end; ++- } ++- ++- enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0), ++- RX_MPDU_START_INFO0_ENCRYPT_TYPE); ++- ath10k_htt_rx_h_protected(htt, rx_status, msdu_head, enctype); ++- msdu_head->ip_summed = ath10k_htt_rx_get_csum_state(msdu_head); ++- ++- if (tkip_mic_err) ++- ath10k_warn("tkip mic error\n"); ++- ++- if (decrypt_err) { ++- ath10k_warn("decryption err in fragmented rx\n"); ++- dev_kfree_skb_any(msdu_head); ++- goto end; ++- } ++- ++- if (enctype != HTT_RX_MPDU_ENCRYPT_NONE) { ++- hdrlen = ieee80211_hdrlen(hdr->frame_control); ++- paramlen = ath10k_htt_rx_crypto_param_len(enctype); ++- ++- /* It is more efficient to move the header than the payload */ ++- memmove((void *)msdu_head->data + paramlen, ++- (void *)msdu_head->data, ++- hdrlen); ++- skb_pull(msdu_head, paramlen); ++- hdr = (struct ieee80211_hdr *)msdu_head->data; ++- } ++- ++- /* remove trailing FCS */ ++- trim = 4; ++- ++- /* remove crypto trailer */ ++- trim += ath10k_htt_rx_crypto_tail_len(enctype); ++- ++- /* last fragment of TKIP frags has MIC */ ++- if (!ieee80211_has_morefrags(hdr->frame_control) && ++- enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA) ++- trim += 8; ++- ++- if (trim > msdu_head->len) { ++- ath10k_warn("htt rx fragment: trailer longer than the frame itself? drop\n"); ++- dev_kfree_skb_any(msdu_head); ++- goto end; +++ if (skb_queue_len(&amsdu) != 1) { +++ ath10k_warn(ar, "failed to pop frag amsdu: too many msdus\n"); +++ __skb_queue_purge(&amsdu); +++ return; ++ } ++ ++- skb_trim(msdu_head, msdu_head->len - trim); ++- ++- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ", ++- msdu_head->data, msdu_head->len); ++- ath10k_process_rx(htt->ar, rx_status, msdu_head); +++ ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status); +++ ath10k_htt_rx_h_filter(ar, &amsdu, rx_status); +++ ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status); +++ ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status); ++ ++-end: ++ if (fw_desc_len > 0) { ++- ath10k_dbg(ATH10K_DBG_HTT, +++ ath10k_dbg(ar, ATH10K_DBG_HTT, ++ "expecting more fragmented rx in one indication %d\n", ++ fw_desc_len); ++ } ++@@ -1385,12 +1605,12 @@ static void ath10k_htt_rx_frm_tx_compl(s ++ tx_done.discard = true; ++ break; ++ default: ++- ath10k_warn("unhandled tx completion status %d\n", status); +++ ath10k_warn(ar, "unhandled tx completion status %d\n", status); ++ tx_done.discard = true; ++ break; ++ } ++ ++- ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n", +++ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n", ++ resp->data_tx_completion.num_msdus); ++ ++ for (i = 0; i < resp->data_tx_completion.num_msdus; i++) { ++@@ -1400,6 +1620,274 @@ static void ath10k_htt_rx_frm_tx_compl(s ++ } ++ } ++ +++static void ath10k_htt_rx_addba(struct ath10k *ar, struct htt_resp *resp) +++{ +++ struct htt_rx_addba *ev = &resp->rx_addba; +++ struct ath10k_peer *peer; +++ struct ath10k_vif *arvif; +++ u16 info0, tid, peer_id; +++ +++ info0 = __le16_to_cpu(ev->info0); +++ tid = MS(info0, HTT_RX_BA_INFO0_TID); +++ peer_id = MS(info0, HTT_RX_BA_INFO0_PEER_ID); +++ +++ ath10k_dbg(ar, ATH10K_DBG_HTT, +++ "htt rx addba tid %hu peer_id %hu size %hhu\n", +++ tid, peer_id, ev->window_size); +++ +++ spin_lock_bh(&ar->data_lock); +++ peer = ath10k_peer_find_by_id(ar, peer_id); +++ if (!peer) { +++ ath10k_warn(ar, "received addba event for invalid peer_id: %hu\n", +++ peer_id); +++ spin_unlock_bh(&ar->data_lock); +++ return; +++ } +++ +++ arvif = ath10k_get_arvif(ar, peer->vdev_id); +++ if (!arvif) { +++ ath10k_warn(ar, "received addba event for invalid vdev_id: %u\n", +++ peer->vdev_id); +++ spin_unlock_bh(&ar->data_lock); +++ return; +++ } +++ +++ ath10k_dbg(ar, ATH10K_DBG_HTT, +++ "htt rx start rx ba session sta %pM tid %hu size %hhu\n", +++ peer->addr, tid, ev->window_size); +++ +++ ieee80211_start_rx_ba_session_offl(arvif->vif, peer->addr, tid); +++ spin_unlock_bh(&ar->data_lock); +++} +++ +++static void ath10k_htt_rx_delba(struct ath10k *ar, struct htt_resp *resp) +++{ +++ struct htt_rx_delba *ev = &resp->rx_delba; +++ struct ath10k_peer *peer; +++ struct ath10k_vif *arvif; +++ u16 info0, tid, peer_id; +++ +++ info0 = __le16_to_cpu(ev->info0); +++ tid = MS(info0, HTT_RX_BA_INFO0_TID); +++ peer_id = MS(info0, HTT_RX_BA_INFO0_PEER_ID); +++ +++ ath10k_dbg(ar, ATH10K_DBG_HTT, +++ "htt rx delba tid %hu peer_id %hu\n", +++ tid, peer_id); +++ +++ spin_lock_bh(&ar->data_lock); +++ peer = ath10k_peer_find_by_id(ar, peer_id); +++ if (!peer) { +++ ath10k_warn(ar, "received addba event for invalid peer_id: %hu\n", +++ peer_id); +++ spin_unlock_bh(&ar->data_lock); +++ return; +++ } +++ +++ arvif = ath10k_get_arvif(ar, peer->vdev_id); +++ if (!arvif) { +++ ath10k_warn(ar, "received addba event for invalid vdev_id: %u\n", +++ peer->vdev_id); +++ spin_unlock_bh(&ar->data_lock); +++ return; +++ } +++ +++ ath10k_dbg(ar, ATH10K_DBG_HTT, +++ "htt rx stop rx ba session sta %pM tid %hu\n", +++ peer->addr, tid); +++ +++ ieee80211_stop_rx_ba_session_offl(arvif->vif, peer->addr, tid); +++ spin_unlock_bh(&ar->data_lock); +++} +++ +++static int ath10k_htt_rx_extract_amsdu(struct sk_buff_head *list, +++ struct sk_buff_head *amsdu) +++{ +++ struct sk_buff *msdu; +++ struct htt_rx_desc *rxd; +++ +++ if (skb_queue_empty(list)) +++ return -ENOBUFS; +++ +++ if (WARN_ON(!skb_queue_empty(amsdu))) +++ return -EINVAL; +++ +++ while ((msdu = __skb_dequeue(list))) { +++ __skb_queue_tail(amsdu, msdu); +++ +++ rxd = (void *)msdu->data - sizeof(*rxd); +++ if (rxd->msdu_end.info0 & +++ __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU)) +++ break; +++ } +++ +++ msdu = skb_peek_tail(amsdu); +++ rxd = (void *)msdu->data - sizeof(*rxd); +++ if (!(rxd->msdu_end.info0 & +++ __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU))) { +++ skb_queue_splice_init(amsdu, list); +++ return -EAGAIN; +++ } +++ +++ return 0; +++} +++ +++static void ath10k_htt_rx_h_rx_offload_prot(struct ieee80211_rx_status *status, +++ struct sk_buff *skb) +++{ +++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; +++ +++ if (!ieee80211_has_protected(hdr->frame_control)) +++ return; +++ +++ /* Offloaded frames are already decrypted but firmware insists they are +++ * protected in the 802.11 header. Strip the flag. Otherwise mac80211 +++ * will drop the frame. +++ */ +++ +++ hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED); +++ status->flag |= RX_FLAG_DECRYPTED | +++ RX_FLAG_IV_STRIPPED | +++ RX_FLAG_MMIC_STRIPPED; +++} +++ +++static void ath10k_htt_rx_h_rx_offload(struct ath10k *ar, +++ struct sk_buff_head *list) +++{ +++ struct ath10k_htt *htt = &ar->htt; +++ struct ieee80211_rx_status *status = &htt->rx_status; +++ struct htt_rx_offload_msdu *rx; +++ struct sk_buff *msdu; +++ size_t offset; +++ +++ while ((msdu = __skb_dequeue(list))) { +++ /* Offloaded frames don't have Rx descriptor. Instead they have +++ * a short meta information header. +++ */ +++ +++ rx = (void *)msdu->data; +++ +++ skb_put(msdu, sizeof(*rx)); +++ skb_pull(msdu, sizeof(*rx)); +++ +++ if (skb_tailroom(msdu) < __le16_to_cpu(rx->msdu_len)) { +++ ath10k_warn(ar, "dropping frame: offloaded rx msdu is too long!\n"); +++ dev_kfree_skb_any(msdu); +++ continue; +++ } +++ +++ skb_put(msdu, __le16_to_cpu(rx->msdu_len)); +++ +++ /* Offloaded rx header length isn't multiple of 2 nor 4 so the +++ * actual payload is unaligned. Align the frame. Otherwise +++ * mac80211 complains. This shouldn't reduce performance much +++ * because these offloaded frames are rare. +++ */ +++ offset = 4 - ((unsigned long)msdu->data & 3); +++ skb_put(msdu, offset); +++ memmove(msdu->data + offset, msdu->data, msdu->len); +++ skb_pull(msdu, offset); +++ +++ /* FIXME: The frame is NWifi. Re-construct QoS Control +++ * if possible later. +++ */ +++ +++ memset(status, 0, sizeof(*status)); +++ status->flag |= RX_FLAG_NO_SIGNAL_VAL; +++ +++ ath10k_htt_rx_h_rx_offload_prot(status, msdu); +++ ath10k_htt_rx_h_channel(ar, status); +++ ath10k_process_rx(ar, status, msdu); +++ } +++} +++ +++static void ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb) +++{ +++ struct ath10k_htt *htt = &ar->htt; +++ struct htt_resp *resp = (void *)skb->data; +++ struct ieee80211_rx_status *status = &htt->rx_status; +++ struct sk_buff_head list; +++ struct sk_buff_head amsdu; +++ u16 peer_id; +++ u16 msdu_count; +++ u8 vdev_id; +++ u8 tid; +++ bool offload; +++ bool frag; +++ int ret; +++ +++ lockdep_assert_held(&htt->rx_ring.lock); +++ +++ if (htt->rx_confused) +++ return; +++ +++ skb_pull(skb, sizeof(resp->hdr)); +++ skb_pull(skb, sizeof(resp->rx_in_ord_ind)); +++ +++ peer_id = __le16_to_cpu(resp->rx_in_ord_ind.peer_id); +++ msdu_count = __le16_to_cpu(resp->rx_in_ord_ind.msdu_count); +++ vdev_id = resp->rx_in_ord_ind.vdev_id; +++ tid = SM(resp->rx_in_ord_ind.info, HTT_RX_IN_ORD_IND_INFO_TID); +++ offload = !!(resp->rx_in_ord_ind.info & +++ HTT_RX_IN_ORD_IND_INFO_OFFLOAD_MASK); +++ frag = !!(resp->rx_in_ord_ind.info & HTT_RX_IN_ORD_IND_INFO_FRAG_MASK); +++ +++ ath10k_dbg(ar, ATH10K_DBG_HTT, +++ "htt rx in ord vdev %i peer %i tid %i offload %i frag %i msdu count %i\n", +++ vdev_id, peer_id, tid, offload, frag, msdu_count); +++ +++ if (skb->len < msdu_count * sizeof(*resp->rx_in_ord_ind.msdu_descs)) { +++ ath10k_warn(ar, "dropping invalid in order rx indication\n"); +++ return; +++ } +++ +++ /* The event can deliver more than 1 A-MSDU. Each A-MSDU is later +++ * extracted and processed. +++ */ +++ __skb_queue_head_init(&list); +++ ret = ath10k_htt_rx_pop_paddr_list(htt, &resp->rx_in_ord_ind, &list); +++ if (ret < 0) { +++ ath10k_warn(ar, "failed to pop paddr list: %d\n", ret); +++ htt->rx_confused = true; +++ return; +++ } +++ +++ /* Offloaded frames are very different and need to be handled +++ * separately. +++ */ +++ if (offload) +++ ath10k_htt_rx_h_rx_offload(ar, &list); +++ +++ while (!skb_queue_empty(&list)) { +++ __skb_queue_head_init(&amsdu); +++ ret = ath10k_htt_rx_extract_amsdu(&list, &amsdu); +++ switch (ret) { +++ case 0: +++ /* Note: The in-order indication may report interleaved +++ * frames from different PPDUs meaning reported rx rate +++ * to mac80211 isn't accurate/reliable. It's still +++ * better to report something than nothing though. This +++ * should still give an idea about rx rate to the user. +++ */ +++ ath10k_htt_rx_h_ppdu(ar, &amsdu, status); +++ ath10k_htt_rx_h_filter(ar, &amsdu, status); +++ ath10k_htt_rx_h_mpdu(ar, &amsdu, status); +++ ath10k_htt_rx_h_deliver(ar, &amsdu, status); +++ break; +++ case -EAGAIN: +++ /* fall through */ +++ default: +++ /* Should not happen. */ +++ ath10k_warn(ar, "failed to extract amsdu: %d\n", ret); +++ htt->rx_confused = true; +++ __skb_queue_purge(&list); +++ return; +++ } +++ } +++ +++ tasklet_schedule(&htt->rx_replenish_task); +++} +++ ++ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) ++ { ++ struct ath10k_htt *htt = &ar->htt; ++@@ -1407,9 +1895,9 @@ void ath10k_htt_t2h_msg_handler(struct a ++ ++ /* confirm alignment */ ++ if (!IS_ALIGNED((unsigned long)skb->data, 4)) ++- ath10k_warn("unaligned htt message, expect trouble\n"); +++ ath10k_warn(ar, "unaligned htt message, expect trouble\n"); ++ ++- ath10k_dbg(ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n", +++ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n", ++ resp->hdr.msg_type); ++ switch (resp->hdr.msg_type) { ++ case HTT_T2H_MSG_TYPE_VERSION_CONF: { ++@@ -1473,7 +1961,7 @@ void ath10k_htt_t2h_msg_handler(struct a ++ struct ath10k *ar = htt->ar; ++ struct htt_security_indication *ev = &resp->security_indication; ++ ++- ath10k_dbg(ATH10K_DBG_HTT, +++ ath10k_dbg(ar, ATH10K_DBG_HTT, ++ "sec ind peer_id %d unicast %d type %d\n", ++ __le16_to_cpu(ev->peer_id), ++ !!(ev->flags & HTT_SECURITY_IS_UNICAST), ++@@ -1482,7 +1970,7 @@ void ath10k_htt_t2h_msg_handler(struct a ++ break; ++ } ++ case HTT_T2H_MSG_TYPE_RX_FRAG_IND: { ++- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt event: ", +++ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ", ++ skb->data, skb->len); ++ ath10k_htt_rx_frag_handler(htt, &resp->rx_frag_ind); ++ break; ++@@ -1491,16 +1979,55 @@ void ath10k_htt_t2h_msg_handler(struct a ++ /* FIX THIS */ ++ break; ++ case HTT_T2H_MSG_TYPE_STATS_CONF: ++- trace_ath10k_htt_stats(skb->data, skb->len); +++ trace_ath10k_htt_stats(ar, skb->data, skb->len); ++ break; ++ case HTT_T2H_MSG_TYPE_TX_INSPECT_IND: +++ /* Firmware can return tx frames if it's unable to fully +++ * process them and suspects host may be able to fix it. ath10k +++ * sends all tx frames as already inspected so this shouldn't +++ * happen unless fw has a bug. +++ */ +++ ath10k_warn(ar, "received an unexpected htt tx inspect event\n"); +++ break; ++ case HTT_T2H_MSG_TYPE_RX_ADDBA: +++ ath10k_htt_rx_addba(ar, resp); +++ break; ++ case HTT_T2H_MSG_TYPE_RX_DELBA: ++- case HTT_T2H_MSG_TYPE_RX_FLUSH: +++ ath10k_htt_rx_delba(ar, resp); +++ break; +++ case HTT_T2H_MSG_TYPE_PKTLOG: { +++ struct ath10k_pktlog_hdr *hdr = +++ (struct ath10k_pktlog_hdr *)resp->pktlog_msg.payload; +++ +++ trace_ath10k_htt_pktlog(ar, resp->pktlog_msg.payload, +++ sizeof(*hdr) + +++ __le16_to_cpu(hdr->size)); +++ break; +++ } +++ case HTT_T2H_MSG_TYPE_RX_FLUSH: { +++ /* Ignore this event because mac80211 takes care of Rx +++ * aggregation reordering. +++ */ +++ break; +++ } +++ case HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND: { +++ spin_lock_bh(&htt->rx_ring.lock); +++ __skb_queue_tail(&htt->rx_in_ord_compl_q, skb); +++ spin_unlock_bh(&htt->rx_ring.lock); +++ tasklet_schedule(&htt->txrx_compl_task); +++ return; +++ } +++ case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND: +++ /* FIXME: This WMI-TLV event is overlapping with 10.2 +++ * CHAN_CHANGE - both being 0xF. Neither is being used in +++ * practice so no immediate action is necessary. Nevertheless +++ * HTT may need an abstraction layer like WMI has one day. +++ */ +++ break; ++ default: ++- ath10k_dbg(ATH10K_DBG_HTT, "htt event (%d) not handled\n", ++- resp->hdr.msg_type); ++- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt event: ", +++ ath10k_warn(ar, "htt event (%d) not handled\n", +++ resp->hdr.msg_type); +++ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ", ++ skb->data, skb->len); ++ break; ++ }; ++@@ -1512,6 +2039,7 @@ void ath10k_htt_t2h_msg_handler(struct a ++ static void ath10k_htt_txrx_compl_task(unsigned long ptr) ++ { ++ struct ath10k_htt *htt = (struct ath10k_htt *)ptr; +++ struct ath10k *ar = htt->ar; ++ struct htt_resp *resp; ++ struct sk_buff *skb; ++ ++@@ -1528,5 +2056,10 @@ static void ath10k_htt_txrx_compl_task(u ++ ath10k_htt_rx_handler(htt, &resp->rx_ind); ++ dev_kfree_skb_any(skb); ++ } +++ +++ while ((skb = __skb_dequeue(&htt->rx_in_ord_compl_q))) { +++ ath10k_htt_rx_in_ord_ind(ar, skb); +++ dev_kfree_skb_any(skb); +++ } ++ spin_unlock_bh(&htt->rx_ring.lock); ++ } ++--- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++++ b/drivers/net/wireless/ath/ath10k/htt_tx.c ++@@ -56,98 +56,74 @@ exit: ++ return ret; ++ } ++ ++-int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt) +++int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb) ++ { ++- int msdu_id; +++ struct ath10k *ar = htt->ar; +++ int ret; ++ ++ lockdep_assert_held(&htt->tx_lock); ++ ++- msdu_id = find_first_zero_bit(htt->used_msdu_ids, ++- htt->max_num_pending_tx); ++- if (msdu_id == htt->max_num_pending_tx) ++- return -ENOBUFS; ++- ++- ath10k_dbg(ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", msdu_id); ++- __set_bit(msdu_id, htt->used_msdu_ids); ++- return msdu_id; +++ ret = idr_alloc(&htt->pending_tx, skb, 0, 0x10000, GFP_ATOMIC); +++ +++ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", ret); +++ +++ return ret; ++ } ++ ++ void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id) ++ { +++ struct ath10k *ar = htt->ar; +++ ++ lockdep_assert_held(&htt->tx_lock); ++ ++- if (!test_bit(msdu_id, htt->used_msdu_ids)) ++- ath10k_warn("trying to free unallocated msdu_id %d\n", msdu_id); +++ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx free msdu_id %hu\n", msdu_id); ++ ++- ath10k_dbg(ATH10K_DBG_HTT, "htt tx free msdu_id %hu\n", msdu_id); ++- __clear_bit(msdu_id, htt->used_msdu_ids); +++ idr_remove(&htt->pending_tx, msdu_id); ++ } ++ ++-int ath10k_htt_tx_attach(struct ath10k_htt *htt) +++int ath10k_htt_tx_alloc(struct ath10k_htt *htt) ++ { ++- spin_lock_init(&htt->tx_lock); ++- init_waitqueue_head(&htt->empty_tx_wq); ++- ++- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, htt->ar->fw_features)) ++- htt->max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC; ++- else ++- htt->max_num_pending_tx = TARGET_NUM_MSDU_DESC; +++ struct ath10k *ar = htt->ar; ++ ++- ath10k_dbg(ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n", +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n", ++ htt->max_num_pending_tx); ++ ++- htt->pending_tx = kzalloc(sizeof(*htt->pending_tx) * ++- htt->max_num_pending_tx, GFP_KERNEL); ++- if (!htt->pending_tx) ++- return -ENOMEM; ++- ++- htt->used_msdu_ids = kzalloc(sizeof(unsigned long) * ++- BITS_TO_LONGS(htt->max_num_pending_tx), ++- GFP_KERNEL); ++- if (!htt->used_msdu_ids) { ++- kfree(htt->pending_tx); ++- return -ENOMEM; ++- } +++ spin_lock_init(&htt->tx_lock); +++ idr_init(&htt->pending_tx); ++ ++ htt->tx_pool = dma_pool_create("ath10k htt tx pool", htt->ar->dev, ++ sizeof(struct ath10k_htt_txbuf), 4, 0); ++ if (!htt->tx_pool) { ++- kfree(htt->used_msdu_ids); ++- kfree(htt->pending_tx); +++ idr_destroy(&htt->pending_tx); ++ return -ENOMEM; ++ } ++ ++ return 0; ++ } ++ ++-static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt) +++static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx) ++ { +++ struct ath10k *ar = ctx; +++ struct ath10k_htt *htt = &ar->htt; ++ struct htt_tx_done tx_done = {0}; ++- int msdu_id; ++- ++- spin_lock_bh(&htt->tx_lock); ++- for (msdu_id = 0; msdu_id < htt->max_num_pending_tx; msdu_id++) { ++- if (!test_bit(msdu_id, htt->used_msdu_ids)) ++- continue; ++ ++- ath10k_dbg(ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n", ++- msdu_id); +++ ath10k_dbg(ar, ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n", msdu_id); ++ ++- tx_done.discard = 1; ++- tx_done.msdu_id = msdu_id; +++ tx_done.discard = 1; +++ tx_done.msdu_id = msdu_id; ++ ++- ath10k_txrx_tx_unref(htt, &tx_done); ++- } +++ spin_lock_bh(&htt->tx_lock); +++ ath10k_txrx_tx_unref(htt, &tx_done); ++ spin_unlock_bh(&htt->tx_lock); +++ +++ return 0; ++ } ++ ++-void ath10k_htt_tx_detach(struct ath10k_htt *htt) +++void ath10k_htt_tx_free(struct ath10k_htt *htt) ++ { ++- ath10k_htt_tx_cleanup_pending(htt); ++- kfree(htt->pending_tx); ++- kfree(htt->used_msdu_ids); +++ idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar); +++ idr_destroy(&htt->pending_tx); ++ dma_pool_destroy(htt->tx_pool); ++- return; ++ } ++ ++ void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb) ++@@ -157,6 +133,7 @@ void ath10k_htt_htc_tx_complete(struct a ++ ++ int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt) ++ { +++ struct ath10k *ar = htt->ar; ++ struct sk_buff *skb; ++ struct htt_cmd *cmd; ++ int len = 0; ++@@ -165,7 +142,7 @@ int ath10k_htt_h2t_ver_req_msg(struct at ++ len += sizeof(cmd->hdr); ++ len += sizeof(cmd->ver_req); ++ ++- skb = ath10k_htc_alloc_skb(len); +++ skb = ath10k_htc_alloc_skb(ar, len); ++ if (!skb) ++ return -ENOMEM; ++ ++@@ -184,6 +161,7 @@ int ath10k_htt_h2t_ver_req_msg(struct at ++ ++ int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie) ++ { +++ struct ath10k *ar = htt->ar; ++ struct htt_stats_req *req; ++ struct sk_buff *skb; ++ struct htt_cmd *cmd; ++@@ -192,7 +170,7 @@ int ath10k_htt_h2t_stats_req(struct ath1 ++ len += sizeof(cmd->hdr); ++ len += sizeof(cmd->stats_req); ++ ++- skb = ath10k_htc_alloc_skb(len); +++ skb = ath10k_htc_alloc_skb(ar, len); ++ if (!skb) ++ return -ENOMEM; ++ ++@@ -214,7 +192,8 @@ int ath10k_htt_h2t_stats_req(struct ath1 ++ ++ ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); ++ if (ret) { ++- ath10k_warn("failed to send htt type stats request: %d", ret); +++ ath10k_warn(ar, "failed to send htt type stats request: %d", +++ ret); ++ dev_kfree_skb_any(skb); ++ return ret; ++ } ++@@ -224,6 +203,7 @@ int ath10k_htt_h2t_stats_req(struct ath1 ++ ++ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt) ++ { +++ struct ath10k *ar = htt->ar; ++ struct sk_buff *skb; ++ struct htt_cmd *cmd; ++ struct htt_rx_ring_setup_ring *ring; ++@@ -242,7 +222,7 @@ int ath10k_htt_send_rx_ring_cfg_ll(struc ++ ++ len = sizeof(cmd->hdr) + sizeof(cmd->rx_setup.hdr) ++ + (sizeof(*ring) * num_rx_ring); ++- skb = ath10k_htc_alloc_skb(len); +++ skb = ath10k_htc_alloc_skb(ar, len); ++ if (!skb) ++ return -ENOMEM; ++ ++@@ -307,9 +287,57 @@ int ath10k_htt_send_rx_ring_cfg_ll(struc ++ return 0; ++ } ++ +++int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt, +++ u8 max_subfrms_ampdu, +++ u8 max_subfrms_amsdu) +++{ +++ struct ath10k *ar = htt->ar; +++ struct htt_aggr_conf *aggr_conf; +++ struct sk_buff *skb; +++ struct htt_cmd *cmd; +++ int len; +++ int ret; +++ +++ /* Firmware defaults are: amsdu = 3 and ampdu = 64 */ +++ +++ if (max_subfrms_ampdu == 0 || max_subfrms_ampdu > 64) +++ return -EINVAL; +++ +++ if (max_subfrms_amsdu == 0 || max_subfrms_amsdu > 31) +++ return -EINVAL; +++ +++ len = sizeof(cmd->hdr); +++ len += sizeof(cmd->aggr_conf); +++ +++ skb = ath10k_htc_alloc_skb(ar, len); +++ if (!skb) +++ return -ENOMEM; +++ +++ skb_put(skb, len); +++ cmd = (struct htt_cmd *)skb->data; +++ cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_AGGR_CFG; +++ +++ aggr_conf = &cmd->aggr_conf; +++ aggr_conf->max_num_ampdu_subframes = max_subfrms_ampdu; +++ aggr_conf->max_num_amsdu_subframes = max_subfrms_amsdu; +++ +++ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt h2t aggr cfg msg amsdu %d ampdu %d", +++ aggr_conf->max_num_amsdu_subframes, +++ aggr_conf->max_num_ampdu_subframes); +++ +++ ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); +++ if (ret) { +++ dev_kfree_skb_any(skb); +++ return ret; +++ } +++ +++ return 0; +++} +++ ++ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) ++ { ++- struct device *dev = htt->ar->dev; +++ struct ath10k *ar = htt->ar; +++ struct device *dev = ar->dev; ++ struct sk_buff *txdesc = NULL; ++ struct htt_cmd *cmd; ++ struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); ++@@ -318,7 +346,6 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt ++ int msdu_id = -1; ++ int res; ++ ++- ++ res = ath10k_htt_tx_inc_pending(htt); ++ if (res) ++ goto err; ++@@ -327,16 +354,15 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt ++ len += sizeof(cmd->mgmt_tx); ++ ++ spin_lock_bh(&htt->tx_lock); ++- res = ath10k_htt_tx_alloc_msdu_id(htt); +++ res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); ++ if (res < 0) { ++ spin_unlock_bh(&htt->tx_lock); ++ goto err_tx_dec; ++ } ++ msdu_id = res; ++- htt->pending_tx[msdu_id] = msdu; ++ spin_unlock_bh(&htt->tx_lock); ++ ++- txdesc = ath10k_htc_alloc_skb(len); +++ txdesc = ath10k_htc_alloc_skb(ar, len); ++ if (!txdesc) { ++ res = -ENOMEM; ++ goto err_free_msdu_id; ++@@ -372,7 +398,6 @@ err_free_txdesc: ++ dev_kfree_skb_any(txdesc); ++ err_free_msdu_id: ++ spin_lock_bh(&htt->tx_lock); ++- htt->pending_tx[msdu_id] = NULL; ++ ath10k_htt_tx_free_msdu_id(htt, msdu_id); ++ spin_unlock_bh(&htt->tx_lock); ++ err_tx_dec: ++@@ -383,7 +408,8 @@ err: ++ ++ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) ++ { ++- struct device *dev = htt->ar->dev; +++ struct ath10k *ar = htt->ar; +++ struct device *dev = ar->dev; ++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; ++ struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); ++ struct ath10k_hif_sg_item sg_items[2]; ++@@ -403,13 +429,12 @@ int ath10k_htt_tx(struct ath10k_htt *htt ++ goto err; ++ ++ spin_lock_bh(&htt->tx_lock); ++- res = ath10k_htt_tx_alloc_msdu_id(htt); +++ res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); ++ if (res < 0) { ++ spin_unlock_bh(&htt->tx_lock); ++ goto err_tx_dec; ++ } ++ msdu_id = res; ++- htt->pending_tx[msdu_id] = msdu; ++ spin_unlock_bh(&htt->tx_lock); ++ ++ prefetch_len = min(htt->prefetch_len, msdu->len); ++@@ -423,10 +448,18 @@ int ath10k_htt_tx(struct ath10k_htt *htt ++ ++ skb_cb->htt.txbuf = dma_pool_alloc(htt->tx_pool, GFP_ATOMIC, ++ &paddr); ++- if (!skb_cb->htt.txbuf) +++ if (!skb_cb->htt.txbuf) { +++ res = -ENOMEM; ++ goto err_free_msdu_id; +++ } ++ skb_cb->htt.txbuf_paddr = paddr; ++ +++ if ((ieee80211_is_action(hdr->frame_control) || +++ ieee80211_is_deauth(hdr->frame_control) || +++ ieee80211_is_disassoc(hdr->frame_control)) && +++ ieee80211_has_protected(hdr->frame_control)) +++ skb_put(msdu, IEEE80211_CCMP_MIC_LEN); +++ ++ skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, ++ DMA_TO_DEVICE); ++ res = dma_mapping_error(dev, skb_cb->paddr); ++@@ -482,8 +515,16 @@ int ath10k_htt_tx(struct ath10k_htt *htt ++ ++ flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID); ++ flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID); ++- flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; ++- flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; +++ if (msdu->ip_summed == CHECKSUM_PARTIAL) { +++ flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; +++ flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; +++ } +++ +++ /* Prevent firmware from sending up tx inspection requests. There's +++ * nothing ath10k can do with frames requested for inspection so force +++ * it to simply rely a regular tx completion with discard status. +++ */ +++ flags1 |= HTT_DATA_TX_DESC_FLAGS1_POSTPONED; ++ ++ skb_cb->htt.txbuf->cmd_hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM; ++ skb_cb->htt.txbuf->cmd_tx.flags0 = flags0; ++@@ -491,14 +532,18 @@ int ath10k_htt_tx(struct ath10k_htt *htt ++ skb_cb->htt.txbuf->cmd_tx.len = __cpu_to_le16(msdu->len); ++ skb_cb->htt.txbuf->cmd_tx.id = __cpu_to_le16(msdu_id); ++ skb_cb->htt.txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr); ++- skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID); +++ skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le16(HTT_INVALID_PEERID); +++ skb_cb->htt.txbuf->cmd_tx.freq = __cpu_to_le16(skb_cb->htt.freq); ++ ++- ath10k_dbg(ATH10K_DBG_HTT, ++- "htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu\n", +++ trace_ath10k_htt_tx(ar, msdu_id, msdu->len, vdev_id, tid); +++ ath10k_dbg(ar, ATH10K_DBG_HTT, +++ "htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu freq %hu\n", ++ flags0, flags1, msdu->len, msdu_id, frags_paddr, ++- (u32)skb_cb->paddr, vdev_id, tid); ++- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ", +++ (u32)skb_cb->paddr, vdev_id, tid, skb_cb->htt.freq); +++ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ", ++ msdu->data, msdu->len); +++ trace_ath10k_tx_hdr(ar, msdu->data, msdu->len); +++ trace_ath10k_tx_payload(ar, msdu->data, msdu->len); ++ ++ sg_items[0].transfer_id = 0; ++ sg_items[0].transfer_context = NULL; ++@@ -531,7 +576,6 @@ err_free_txbuf: ++ skb_cb->htt.txbuf_paddr); ++ err_free_msdu_id: ++ spin_lock_bh(&htt->tx_lock); ++- htt->pending_tx[msdu_id] = NULL; ++ ath10k_htt_tx_free_msdu_id(htt, msdu_id); ++ spin_unlock_bh(&htt->tx_lock); ++ err_tx_dec: ++--- a/drivers/net/wireless/ath/ath10k/hw.h +++++ b/drivers/net/wireless/ath/ath10k/hw.h ++@@ -20,24 +20,73 @@ ++ ++ #include "targaddrs.h" ++ +++#define ATH10K_FW_DIR "ath10k" +++ ++ /* QCA988X 1.0 definitions (unsupported) */ ++ #define QCA988X_HW_1_0_CHIP_ID_REV 0x0 ++ ++ /* QCA988X 2.0 definitions */ ++ #define QCA988X_HW_2_0_VERSION 0x4100016c ++ #define QCA988X_HW_2_0_CHIP_ID_REV 0x2 ++-#define QCA988X_HW_2_0_FW_DIR "ath10k/QCA988X/hw2.0" +++#define QCA988X_HW_2_0_FW_DIR ATH10K_FW_DIR "/QCA988X/hw2.0" ++ #define QCA988X_HW_2_0_FW_FILE "firmware.bin" ++-#define QCA988X_HW_2_0_FW_2_FILE "firmware-2.bin" ++ #define QCA988X_HW_2_0_OTP_FILE "otp.bin" ++ #define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin" ++ #define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234 ++ +++/* QCA6174 target BMI version signatures */ +++#define QCA6174_HW_1_0_VERSION 0x05000000 +++#define QCA6174_HW_1_1_VERSION 0x05000001 +++#define QCA6174_HW_1_3_VERSION 0x05000003 +++#define QCA6174_HW_2_1_VERSION 0x05010000 +++#define QCA6174_HW_3_0_VERSION 0x05020000 +++#define QCA6174_HW_3_2_VERSION 0x05030000 +++ +++enum qca6174_pci_rev { +++ QCA6174_PCI_REV_1_1 = 0x11, +++ QCA6174_PCI_REV_1_3 = 0x13, +++ QCA6174_PCI_REV_2_0 = 0x20, +++ QCA6174_PCI_REV_3_0 = 0x30, +++}; +++ +++enum qca6174_chip_id_rev { +++ QCA6174_HW_1_0_CHIP_ID_REV = 0, +++ QCA6174_HW_1_1_CHIP_ID_REV = 1, +++ QCA6174_HW_1_3_CHIP_ID_REV = 2, +++ QCA6174_HW_2_1_CHIP_ID_REV = 4, +++ QCA6174_HW_2_2_CHIP_ID_REV = 5, +++ QCA6174_HW_3_0_CHIP_ID_REV = 8, +++ QCA6174_HW_3_1_CHIP_ID_REV = 9, +++ QCA6174_HW_3_2_CHIP_ID_REV = 10, +++}; +++ +++#define QCA6174_HW_2_1_FW_DIR "ath10k/QCA6174/hw2.1" +++#define QCA6174_HW_2_1_FW_FILE "firmware.bin" +++#define QCA6174_HW_2_1_OTP_FILE "otp.bin" +++#define QCA6174_HW_2_1_BOARD_DATA_FILE "board.bin" +++#define QCA6174_HW_2_1_PATCH_LOAD_ADDR 0x1234 +++ +++#define QCA6174_HW_3_0_FW_DIR "ath10k/QCA6174/hw3.0" +++#define QCA6174_HW_3_0_FW_FILE "firmware.bin" +++#define QCA6174_HW_3_0_OTP_FILE "otp.bin" +++#define QCA6174_HW_3_0_BOARD_DATA_FILE "board.bin" +++#define QCA6174_HW_3_0_PATCH_LOAD_ADDR 0x1234 +++ ++ #define ATH10K_FW_API2_FILE "firmware-2.bin" +++#define ATH10K_FW_API3_FILE "firmware-3.bin" +++ +++/* added support for ATH10K_FW_IE_WMI_OP_VERSION */ +++#define ATH10K_FW_API4_FILE "firmware-4.bin" +++ +++#define ATH10K_FW_UTF_FILE "utf.bin" ++ ++ /* includes also the null byte */ ++ #define ATH10K_FIRMWARE_MAGIC "QCA-ATH10K" ++ +++#define REG_DUMP_COUNT_QCA988X 60 +++ +++#define QCA988X_CAL_DATA_LEN 2116 +++ ++ struct ath10k_fw_ie { ++ __le32 id; ++ __le32 len; ++@@ -50,8 +99,57 @@ enum ath10k_fw_ie_type { ++ ATH10K_FW_IE_FEATURES = 2, ++ ATH10K_FW_IE_FW_IMAGE = 3, ++ ATH10K_FW_IE_OTP_IMAGE = 4, +++ +++ /* WMI "operations" interface version, 32 bit value. Supported from +++ * FW API 4 and above. +++ */ +++ ATH10K_FW_IE_WMI_OP_VERSION = 5, +++}; +++ +++enum ath10k_fw_wmi_op_version { +++ ATH10K_FW_WMI_OP_VERSION_UNSET = 0, +++ +++ ATH10K_FW_WMI_OP_VERSION_MAIN = 1, +++ ATH10K_FW_WMI_OP_VERSION_10_1 = 2, +++ ATH10K_FW_WMI_OP_VERSION_10_2 = 3, +++ ATH10K_FW_WMI_OP_VERSION_TLV = 4, +++ ATH10K_FW_WMI_OP_VERSION_10_2_4 = 5, +++ +++ /* keep last */ +++ ATH10K_FW_WMI_OP_VERSION_MAX, +++}; +++ +++enum ath10k_hw_rev { +++ ATH10K_HW_QCA988X, +++ ATH10K_HW_QCA6174, +++}; +++ +++struct ath10k_hw_regs { +++ u32 rtc_state_cold_reset_mask; +++ u32 rtc_soc_base_address; +++ u32 rtc_wmac_base_address; +++ u32 soc_core_base_address; +++ u32 ce_wrapper_base_address; +++ u32 ce0_base_address; +++ u32 ce1_base_address; +++ u32 ce2_base_address; +++ u32 ce3_base_address; +++ u32 ce4_base_address; +++ u32 ce5_base_address; +++ u32 ce6_base_address; +++ u32 ce7_base_address; +++ u32 soc_reset_control_si0_rst_mask; +++ u32 soc_reset_control_ce_rst_mask; +++ u32 soc_chip_id_address; +++ u32 scratch_3_address; ++ }; ++ +++extern const struct ath10k_hw_regs qca988x_regs; +++extern const struct ath10k_hw_regs qca6174_regs; +++ +++#define QCA_REV_988X(ar) ((ar)->hw_rev == ATH10K_HW_QCA988X) +++#define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174) +++ ++ /* Known pecularities: ++ * - current FW doesn't support raw rx mode (last tested v599) ++ * - current FW dumps upon raw tx mode (last tested v599) ++@@ -73,6 +171,15 @@ enum ath10k_mcast2ucast_mode { ++ ATH10K_MCAST2UCAST_ENABLED = 1, ++ }; ++ +++struct ath10k_pktlog_hdr { +++ __le16 flags; +++ __le16 missed_cnt; +++ __le16 log_type; +++ __le16 size; +++ __le32 timestamp; +++ u8 payload[0]; +++} __packed; +++ ++ /* Target specific defines for MAIN firmware */ ++ #define TARGET_NUM_VDEVS 8 ++ #define TARGET_NUM_PEER_AST 2 ++@@ -80,11 +187,13 @@ enum ath10k_mcast2ucast_mode { ++ #define TARGET_DMA_BURST_SIZE 0 ++ #define TARGET_MAC_AGGR_DELIM 0 ++ #define TARGET_AST_SKID_LIMIT 16 ++-#define TARGET_NUM_PEERS 16 +++#define TARGET_NUM_STATIONS 16 +++#define TARGET_NUM_PEERS ((TARGET_NUM_STATIONS) + \ +++ (TARGET_NUM_VDEVS)) ++ #define TARGET_NUM_OFFLOAD_PEERS 0 ++ #define TARGET_NUM_OFFLOAD_REORDER_BUFS 0 ++ #define TARGET_NUM_PEER_KEYS 2 ++-#define TARGET_NUM_TIDS (2 * ((TARGET_NUM_PEERS) + (TARGET_NUM_VDEVS))) +++#define TARGET_NUM_TIDS ((TARGET_NUM_PEERS) * 2) ++ #define TARGET_TX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) ++ #define TARGET_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) ++ #define TARGET_RX_TIMEOUT_LO_PRI 100 ++@@ -115,12 +224,15 @@ enum ath10k_mcast2ucast_mode { ++ #define TARGET_10X_DMA_BURST_SIZE 0 ++ #define TARGET_10X_MAC_AGGR_DELIM 0 ++ #define TARGET_10X_AST_SKID_LIMIT 16 ++-#define TARGET_10X_NUM_PEERS (128 + (TARGET_10X_NUM_VDEVS)) ++-#define TARGET_10X_NUM_PEERS_MAX 128 +++#define TARGET_10X_NUM_STATIONS 128 +++#define TARGET_10X_NUM_PEERS ((TARGET_10X_NUM_STATIONS) + \ +++ (TARGET_10X_NUM_VDEVS)) ++ #define TARGET_10X_NUM_OFFLOAD_PEERS 0 ++ #define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS 0 ++ #define TARGET_10X_NUM_PEER_KEYS 2 ++-#define TARGET_10X_NUM_TIDS 256 +++#define TARGET_10X_NUM_TIDS_MAX 256 +++#define TARGET_10X_NUM_TIDS min((TARGET_10X_NUM_TIDS_MAX), \ +++ (TARGET_10X_NUM_PEERS) * 2) ++ #define TARGET_10X_TX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) ++ #define TARGET_10X_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) ++ #define TARGET_10X_RX_TIMEOUT_LO_PRI 100 ++@@ -140,6 +252,18 @@ enum ath10k_mcast2ucast_mode { ++ #define TARGET_10X_NUM_MSDU_DESC (1024 + 400) ++ #define TARGET_10X_MAX_FRAG_ENTRIES 0 ++ +++/* 10.2 parameters */ +++#define TARGET_10_2_DMA_BURST_SIZE 1 +++ +++/* Target specific defines for WMI-TLV firmware */ +++#define TARGET_TLV_NUM_VDEVS 3 +++#define TARGET_TLV_NUM_STATIONS 32 +++#define TARGET_TLV_NUM_PEERS ((TARGET_TLV_NUM_STATIONS) + \ +++ (TARGET_TLV_NUM_VDEVS) + \ +++ 2) +++#define TARGET_TLV_NUM_TIDS ((TARGET_TLV_NUM_PEERS) * 2) +++#define TARGET_TLV_NUM_MSDU_DESC (1024 + 32) +++ ++ /* Number of Copy Engines supported */ ++ #define CE_COUNT 8 ++ ++@@ -170,7 +294,7 @@ enum ath10k_mcast2ucast_mode { ++ /* as of IP3.7.1 */ ++ #define RTC_STATE_V_ON 3 ++ ++-#define RTC_STATE_COLD_RESET_MASK 0x00000400 +++#define RTC_STATE_COLD_RESET_MASK ar->regs->rtc_state_cold_reset_mask ++ #define RTC_STATE_V_LSB 0 ++ #define RTC_STATE_V_MASK 0x00000007 ++ #define RTC_STATE_ADDRESS 0x0000 ++@@ -179,12 +303,12 @@ enum ath10k_mcast2ucast_mode { ++ #define PCIE_SOC_WAKE_RESET 0x00000000 ++ #define SOC_GLOBAL_RESET_ADDRESS 0x0008 ++ ++-#define RTC_SOC_BASE_ADDRESS 0x00004000 ++-#define RTC_WMAC_BASE_ADDRESS 0x00005000 +++#define RTC_SOC_BASE_ADDRESS ar->regs->rtc_soc_base_address +++#define RTC_WMAC_BASE_ADDRESS ar->regs->rtc_wmac_base_address ++ #define MAC_COEX_BASE_ADDRESS 0x00006000 ++ #define BT_COEX_BASE_ADDRESS 0x00007000 ++ #define SOC_PCIE_BASE_ADDRESS 0x00008000 ++-#define SOC_CORE_BASE_ADDRESS 0x00009000 +++#define SOC_CORE_BASE_ADDRESS ar->regs->soc_core_base_address ++ #define WLAN_UART_BASE_ADDRESS 0x0000c000 ++ #define WLAN_SI_BASE_ADDRESS 0x00010000 ++ #define WLAN_GPIO_BASE_ADDRESS 0x00014000 ++@@ -193,23 +317,23 @@ enum ath10k_mcast2ucast_mode { ++ #define EFUSE_BASE_ADDRESS 0x00030000 ++ #define FPGA_REG_BASE_ADDRESS 0x00039000 ++ #define WLAN_UART2_BASE_ADDRESS 0x00054c00 ++-#define CE_WRAPPER_BASE_ADDRESS 0x00057000 ++-#define CE0_BASE_ADDRESS 0x00057400 ++-#define CE1_BASE_ADDRESS 0x00057800 ++-#define CE2_BASE_ADDRESS 0x00057c00 ++-#define CE3_BASE_ADDRESS 0x00058000 ++-#define CE4_BASE_ADDRESS 0x00058400 ++-#define CE5_BASE_ADDRESS 0x00058800 ++-#define CE6_BASE_ADDRESS 0x00058c00 ++-#define CE7_BASE_ADDRESS 0x00059000 +++#define CE_WRAPPER_BASE_ADDRESS ar->regs->ce_wrapper_base_address +++#define CE0_BASE_ADDRESS ar->regs->ce0_base_address +++#define CE1_BASE_ADDRESS ar->regs->ce1_base_address +++#define CE2_BASE_ADDRESS ar->regs->ce2_base_address +++#define CE3_BASE_ADDRESS ar->regs->ce3_base_address +++#define CE4_BASE_ADDRESS ar->regs->ce4_base_address +++#define CE5_BASE_ADDRESS ar->regs->ce5_base_address +++#define CE6_BASE_ADDRESS ar->regs->ce6_base_address +++#define CE7_BASE_ADDRESS ar->regs->ce7_base_address ++ #define DBI_BASE_ADDRESS 0x00060000 ++ #define WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x0006c000 ++ #define PCIE_LOCAL_BASE_ADDRESS 0x00080000 ++ ++ #define SOC_RESET_CONTROL_ADDRESS 0x00000000 ++ #define SOC_RESET_CONTROL_OFFSET 0x00000000 ++-#define SOC_RESET_CONTROL_SI0_RST_MASK 0x00000001 ++-#define SOC_RESET_CONTROL_CE_RST_MASK 0x00040000 +++#define SOC_RESET_CONTROL_SI0_RST_MASK ar->regs->soc_reset_control_si0_rst_mask +++#define SOC_RESET_CONTROL_CE_RST_MASK ar->regs->soc_reset_control_ce_rst_mask ++ #define SOC_RESET_CONTROL_CPU_WARM_RST_MASK 0x00000040 ++ #define SOC_CPU_CLOCK_OFFSET 0x00000020 ++ #define SOC_CPU_CLOCK_STANDARD_LSB 0 ++@@ -223,7 +347,7 @@ enum ath10k_mcast2ucast_mode { ++ #define SOC_LF_TIMER_CONTROL0_ADDRESS 0x00000050 ++ #define SOC_LF_TIMER_CONTROL0_ENABLE_MASK 0x00000004 ++ ++-#define SOC_CHIP_ID_ADDRESS 0x000000ec +++#define SOC_CHIP_ID_ADDRESS ar->regs->soc_chip_id_address ++ #define SOC_CHIP_ID_REV_LSB 8 ++ #define SOC_CHIP_ID_REV_MASK 0x00000f00 ++ ++@@ -274,11 +398,12 @@ enum ath10k_mcast2ucast_mode { ++ #define SI_RX_DATA1_OFFSET 0x00000014 ++ ++ #define CORE_CTRL_CPU_INTR_MASK 0x00002000 +++#define CORE_CTRL_PCIE_REG_31_MASK 0x00000800 ++ #define CORE_CTRL_ADDRESS 0x0000 ++ #define PCIE_INTR_ENABLE_ADDRESS 0x0008 ++ #define PCIE_INTR_CAUSE_ADDRESS 0x000c ++ #define PCIE_INTR_CLR_ADDRESS 0x0014 ++-#define SCRATCH_3_ADDRESS 0x0030 +++#define SCRATCH_3_ADDRESS ar->regs->scratch_3_address ++ #define CPU_INTR_ADDRESS 0x0010 ++ ++ /* Firmware indications to the Host via SCRATCH_3 register. */ ++--- a/drivers/net/wireless/ath/ath10k/mac.c +++++ b/drivers/net/wireless/ath/ath10k/mac.c ++@@ -26,6 +26,9 @@ ++ #include "wmi.h" ++ #include "htt.h" ++ #include "txrx.h" +++#include "testmode.h" +++#include "wmi.h" +++#include "wmi-ops.h" ++ ++ /**********/ ++ /* Crypto */ ++@@ -34,8 +37,9 @@ ++ static int ath10k_send_key(struct ath10k_vif *arvif, ++ struct ieee80211_key_conf *key, ++ enum set_key_cmd cmd, ++- const u8 *macaddr) +++ const u8 *macaddr, bool def_idx) ++ { +++ struct ath10k *ar = arvif->ar; ++ struct wmi_vdev_install_key_arg arg = { ++ .vdev_id = arvif->vdev_id, ++ .key_idx = key->keyidx, ++@@ -54,7 +58,7 @@ static int ath10k_send_key(struct ath10k ++ switch (key->cipher) { ++ case WLAN_CIPHER_SUITE_CCMP: ++ arg.key_cipher = WMI_CIPHER_AES_CCM; ++- key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; +++ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT; ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ arg.key_cipher = WMI_CIPHER_TKIP; ++@@ -68,9 +72,12 @@ static int ath10k_send_key(struct ath10k ++ * Otherwise pairwise key must be set */ ++ if (memcmp(macaddr, arvif->vif->addr, ETH_ALEN)) ++ arg.key_flags = WMI_KEY_PAIRWISE; +++ +++ if (def_idx) +++ arg.key_flags |= WMI_KEY_TX_USAGE; ++ break; ++ default: ++- ath10k_warn("cipher %d is not supported\n", key->cipher); +++ ath10k_warn(ar, "cipher %d is not supported\n", key->cipher); ++ return -EOPNOTSUPP; ++ } ++ ++@@ -85,7 +92,7 @@ static int ath10k_send_key(struct ath10k ++ static int ath10k_install_key(struct ath10k_vif *arvif, ++ struct ieee80211_key_conf *key, ++ enum set_key_cmd cmd, ++- const u8 *macaddr) +++ const u8 *macaddr, bool def_idx) ++ { ++ struct ath10k *ar = arvif->ar; ++ int ret; ++@@ -94,7 +101,7 @@ static int ath10k_install_key(struct ath ++ ++ reinit_completion(&ar->install_key_done); ++ ++- ret = ath10k_send_key(arvif, key, cmd, macaddr); +++ ret = ath10k_send_key(arvif, key, cmd, macaddr, def_idx); ++ if (ret) ++ return ret; ++ ++@@ -112,6 +119,7 @@ static int ath10k_install_peer_wep_keys( ++ struct ath10k_peer *peer; ++ int ret; ++ int i; +++ bool def_idx; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++@@ -125,13 +133,20 @@ static int ath10k_install_peer_wep_keys( ++ for (i = 0; i < ARRAY_SIZE(arvif->wep_keys); i++) { ++ if (arvif->wep_keys[i] == NULL) ++ continue; +++ /* set TX_USAGE flag for default key id */ +++ if (arvif->def_wep_key_idx == i) +++ def_idx = true; +++ else +++ def_idx = false; ++ ++ ret = ath10k_install_key(arvif, arvif->wep_keys[i], SET_KEY, ++- addr); +++ addr, def_idx); ++ if (ret) ++ return ret; ++ +++ spin_lock_bh(&ar->data_lock); ++ peer->keys[i] = arvif->wep_keys[i]; +++ spin_unlock_bh(&ar->data_lock); ++ } ++ ++ return 0; ++@@ -159,21 +174,49 @@ static int ath10k_clear_peer_keys(struct ++ if (peer->keys[i] == NULL) ++ continue; ++ +++ /* key flags are not required to delete the key */ ++ ret = ath10k_install_key(arvif, peer->keys[i], ++- DISABLE_KEY, addr); +++ DISABLE_KEY, addr, false); ++ if (ret && first_errno == 0) ++ first_errno = ret; ++ ++ if (ret) ++- ath10k_warn("failed to remove peer wep key %d: %d\n", +++ ath10k_warn(ar, "failed to remove peer wep key %d: %d\n", ++ i, ret); ++ +++ spin_lock_bh(&ar->data_lock); ++ peer->keys[i] = NULL; +++ spin_unlock_bh(&ar->data_lock); ++ } ++ ++ return first_errno; ++ } ++ +++bool ath10k_mac_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr, +++ u8 keyidx) +++{ +++ struct ath10k_peer *peer; +++ int i; +++ +++ lockdep_assert_held(&ar->data_lock); +++ +++ /* We don't know which vdev this peer belongs to, +++ * since WMI doesn't give us that information. +++ * +++ * FIXME: multi-bss needs to be handled. +++ */ +++ peer = ath10k_peer_find(ar, 0, addr); +++ if (!peer) +++ return false; +++ +++ for (i = 0; i < ARRAY_SIZE(peer->keys); i++) { +++ if (peer->keys[i] && peer->keys[i]->keyidx == keyidx) +++ return true; +++ } +++ +++ return false; +++} +++ ++ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif, ++ struct ieee80211_key_conf *key) ++ { ++@@ -194,7 +237,7 @@ static int ath10k_clear_vdev_key(struct ++ list_for_each_entry(peer, &ar->peers, list) { ++ for (i = 0; i < ARRAY_SIZE(peer->keys); i++) { ++ if (peer->keys[i] == key) { ++- memcpy(addr, peer->addr, ETH_ALEN); +++ ether_addr_copy(addr, peer->addr); ++ peer->keys[i] = NULL; ++ break; ++ } ++@@ -207,20 +250,19 @@ static int ath10k_clear_vdev_key(struct ++ ++ if (i == ARRAY_SIZE(peer->keys)) ++ break; ++- ++- ret = ath10k_install_key(arvif, key, DISABLE_KEY, addr); +++ /* key flags are not required to delete the key */ +++ ret = ath10k_install_key(arvif, key, DISABLE_KEY, addr, false); ++ if (ret && first_errno == 0) ++ first_errno = ret; ++ ++ if (ret) ++- ath10k_warn("failed to remove key for %pM: %d\n", +++ ath10k_warn(ar, "failed to remove key for %pM: %d\n", ++ addr, ret); ++ } ++ ++ return first_errno; ++ } ++ ++- ++ /*********************/ ++ /* General utilities */ ++ /*********************/ ++@@ -234,7 +276,10 @@ chan_to_phymode(const struct cfg80211_ch ++ case IEEE80211_BAND_2GHZ: ++ switch (chandef->width) { ++ case NL80211_CHAN_WIDTH_20_NOHT: ++- phymode = MODE_11G; +++ if (chandef->chan->flags & IEEE80211_CHAN_NO_OFDM) +++ phymode = MODE_11B; +++ else +++ phymode = MODE_11G; ++ break; ++ case NL80211_CHAN_WIDTH_20: ++ phymode = MODE_11NG_HT20; ++@@ -322,22 +367,24 @@ static int ath10k_peer_create(struct ath ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ +++ if (ar->num_peers >= ar->max_num_peers) +++ return -ENOBUFS; +++ ++ ret = ath10k_wmi_peer_create(ar, vdev_id, addr); ++ if (ret) { ++- ath10k_warn("failed to create wmi peer %pM on vdev %i: %i\n", +++ ath10k_warn(ar, "failed to create wmi peer %pM on vdev %i: %i\n", ++ addr, vdev_id, ret); ++ return ret; ++ } ++ ++ ret = ath10k_wait_for_peer_created(ar, vdev_id, addr); ++ if (ret) { ++- ath10k_warn("failed to wait for created wmi peer %pM on vdev %i: %i\n", +++ ath10k_warn(ar, "failed to wait for created wmi peer %pM on vdev %i: %i\n", ++ addr, vdev_id, ret); ++ return ret; ++ } ++- spin_lock_bh(&ar->data_lock); +++ ++ ar->num_peers++; ++- spin_unlock_bh(&ar->data_lock); ++ ++ return 0; ++ } ++@@ -352,7 +399,7 @@ static int ath10k_mac_set_kickout(struct ++ ret = ath10k_wmi_pdev_set_param(ar, param, ++ ATH10K_KICKOUT_THRESHOLD); ++ if (ret) { ++- ath10k_warn("failed to set kickout threshold on vdev %i: %d\n", +++ ath10k_warn(ar, "failed to set kickout threshold on vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ return ret; ++ } ++@@ -361,7 +408,7 @@ static int ath10k_mac_set_kickout(struct ++ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, ++ ATH10K_KEEPALIVE_MIN_IDLE); ++ if (ret) { ++- ath10k_warn("failed to set keepalive minimum idle time on vdev %i: %d\n", +++ ath10k_warn(ar, "failed to set keepalive minimum idle time on vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ return ret; ++ } ++@@ -370,7 +417,7 @@ static int ath10k_mac_set_kickout(struct ++ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, ++ ATH10K_KEEPALIVE_MAX_IDLE); ++ if (ret) { ++- ath10k_warn("failed to set keepalive maximum idle time on vdev %i: %d\n", +++ ath10k_warn(ar, "failed to set keepalive maximum idle time on vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ return ret; ++ } ++@@ -379,7 +426,7 @@ static int ath10k_mac_set_kickout(struct ++ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, ++ ATH10K_KEEPALIVE_MAX_UNRESPONSIVE); ++ if (ret) { ++- ath10k_warn("failed to set keepalive maximum unresponsive time on vdev %i: %d\n", +++ ath10k_warn(ar, "failed to set keepalive maximum unresponsive time on vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ return ret; ++ } ++@@ -387,15 +434,11 @@ static int ath10k_mac_set_kickout(struct ++ return 0; ++ } ++ ++-static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value) +++static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value) ++ { ++ struct ath10k *ar = arvif->ar; ++ u32 vdev_param; ++ ++- if (value != 0xFFFFFFFF) ++- value = min_t(u32, arvif->ar->hw->wiphy->rts_threshold, ++- ATH10K_RTS_MAX); ++- ++ vdev_param = ar->wmi.vdev_param->rts_threshold; ++ return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value); ++ } ++@@ -428,9 +471,7 @@ static int ath10k_peer_delete(struct ath ++ if (ret) ++ return ret; ++ ++- spin_lock_bh(&ar->data_lock); ++ ar->num_peers--; ++- spin_unlock_bh(&ar->data_lock); ++ ++ return 0; ++ } ++@@ -446,7 +487,7 @@ static void ath10k_peer_cleanup(struct a ++ if (peer->vdev_id != vdev_id) ++ continue; ++ ++- ath10k_warn("removing stale peer %pM from vdev_id %d\n", +++ ath10k_warn(ar, "removing stale peer %pM from vdev_id %d\n", ++ peer->addr, vdev_id); ++ ++ list_del(&peer->list); ++@@ -467,20 +508,63 @@ static void ath10k_peer_cleanup_all(stru ++ list_del(&peer->list); ++ kfree(peer); ++ } ++- ar->num_peers = 0; ++ spin_unlock_bh(&ar->data_lock); +++ +++ ar->num_peers = 0; +++ ar->num_stations = 0; ++ } ++ ++ /************************/ ++ /* Interface management */ ++ /************************/ ++ +++void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif) +++{ +++ struct ath10k *ar = arvif->ar; +++ +++ lockdep_assert_held(&ar->data_lock); +++ +++ if (!arvif->beacon) +++ return; +++ +++ if (!arvif->beacon_buf) +++ dma_unmap_single(ar->dev, ATH10K_SKB_CB(arvif->beacon)->paddr, +++ arvif->beacon->len, DMA_TO_DEVICE); +++ +++ if (WARN_ON(arvif->beacon_state != ATH10K_BEACON_SCHEDULED && +++ arvif->beacon_state != ATH10K_BEACON_SENT)) +++ return; +++ +++ dev_kfree_skb_any(arvif->beacon); +++ +++ arvif->beacon = NULL; +++ arvif->beacon_state = ATH10K_BEACON_SCHEDULED; +++} +++ +++static void ath10k_mac_vif_beacon_cleanup(struct ath10k_vif *arvif) +++{ +++ struct ath10k *ar = arvif->ar; +++ +++ lockdep_assert_held(&ar->data_lock); +++ +++ ath10k_mac_vif_beacon_free(arvif); +++ +++ if (arvif->beacon_buf) { +++ dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN, +++ arvif->beacon_buf, arvif->beacon_paddr); +++ arvif->beacon_buf = NULL; +++ } +++} +++ ++ static inline int ath10k_vdev_setup_sync(struct ath10k *ar) ++ { ++ int ret; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ +++ if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) +++ return -ESHUTDOWN; +++ ++ ret = wait_for_completion_timeout(&ar->vdev_setup_done, ++ ATH10K_VDEV_SETUP_TIMEOUT_HZ); ++ if (ret == 0) ++@@ -489,19 +573,6 @@ static inline int ath10k_vdev_setup_sync ++ return 0; ++ } ++ ++-static bool ath10k_monitor_is_enabled(struct ath10k *ar) ++-{ ++- lockdep_assert_held(&ar->conf_mutex); ++- ++- ath10k_dbg(ATH10K_DBG_MAC, ++- "mac monitor refs: promisc %d monitor %d cac %d\n", ++- ar->promisc, ar->monitor, ++- test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)); ++- ++- return ar->promisc || ar->monitor || ++- test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); ++-} ++- ++ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) ++ { ++ struct cfg80211_chan_def *chandef = &ar->chandef; ++@@ -526,37 +597,39 @@ static int ath10k_monitor_vdev_start(str ++ arg.channel.max_reg_power = channel->max_reg_power * 2; ++ arg.channel.max_antenna_gain = channel->max_antenna_gain * 2; ++ +++ reinit_completion(&ar->vdev_setup_done); +++ ++ ret = ath10k_wmi_vdev_start(ar, &arg); ++ if (ret) { ++- ath10k_warn("failed to request monitor vdev %i start: %d\n", +++ ath10k_warn(ar, "failed to request monitor vdev %i start: %d\n", ++ vdev_id, ret); ++ return ret; ++ } ++ ++ ret = ath10k_vdev_setup_sync(ar); ++ if (ret) { ++- ath10k_warn("failed to synchronize setup for monitor vdev %i: %d\n", +++ ath10k_warn(ar, "failed to synchronize setup for monitor vdev %i start: %d\n", ++ vdev_id, ret); ++ return ret; ++ } ++ ++ ret = ath10k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr); ++ if (ret) { ++- ath10k_warn("failed to put up monitor vdev %i: %d\n", +++ ath10k_warn(ar, "failed to put up monitor vdev %i: %d\n", ++ vdev_id, ret); ++ goto vdev_stop; ++ } ++ ++ ar->monitor_vdev_id = vdev_id; ++ ++- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %i started\n", +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %i started\n", ++ ar->monitor_vdev_id); ++ return 0; ++ ++ vdev_stop: ++ ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id); ++ if (ret) ++- ath10k_warn("failed to stop monitor vdev %i after start failure: %d\n", +++ ath10k_warn(ar, "failed to stop monitor vdev %i after start failure: %d\n", ++ ar->monitor_vdev_id, ret); ++ ++ return ret; ++@@ -570,20 +643,22 @@ static int ath10k_monitor_vdev_stop(stru ++ ++ ret = ath10k_wmi_vdev_down(ar, ar->monitor_vdev_id); ++ if (ret) ++- ath10k_warn("failed to put down monitor vdev %i: %d\n", +++ ath10k_warn(ar, "failed to put down monitor vdev %i: %d\n", ++ ar->monitor_vdev_id, ret); ++ +++ reinit_completion(&ar->vdev_setup_done); +++ ++ ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id); ++ if (ret) ++- ath10k_warn("failed to to request monitor vdev %i stop: %d\n", +++ ath10k_warn(ar, "failed to to request monitor vdev %i stop: %d\n", ++ ar->monitor_vdev_id, ret); ++ ++ ret = ath10k_vdev_setup_sync(ar); ++ if (ret) ++- ath10k_warn("failed to synchronise monitor vdev %i: %d\n", +++ ath10k_warn(ar, "failed to synchronize monitor vdev %i stop: %d\n", ++ ar->monitor_vdev_id, ret); ++ ++- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n", +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n", ++ ar->monitor_vdev_id); ++ return ret; ++ } ++@@ -594,35 +669,29 @@ static int ath10k_monitor_vdev_create(st ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++- bit = ffs(ar->free_vdev_map); ++- if (bit == 0) { ++- ath10k_warn("failed to find free vdev id for monitor vdev\n"); +++ if (ar->free_vdev_map == 0) { +++ ath10k_warn(ar, "failed to find free vdev id for monitor vdev\n"); ++ return -ENOMEM; ++ } ++ ++- ar->monitor_vdev_id = bit - 1; ++- ar->free_vdev_map &= ~(1 << ar->monitor_vdev_id); +++ bit = __ffs64(ar->free_vdev_map); +++ +++ ar->monitor_vdev_id = bit; ++ ++ ret = ath10k_wmi_vdev_create(ar, ar->monitor_vdev_id, ++ WMI_VDEV_TYPE_MONITOR, ++ 0, ar->mac_addr); ++ if (ret) { ++- ath10k_warn("failed to request monitor vdev %i creation: %d\n", +++ ath10k_warn(ar, "failed to request monitor vdev %i creation: %d\n", ++ ar->monitor_vdev_id, ret); ++- goto vdev_fail; +++ return ret; ++ } ++ ++- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d created\n", +++ ar->free_vdev_map &= ~(1LL << ar->monitor_vdev_id); +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d created\n", ++ ar->monitor_vdev_id); ++ ++ return 0; ++- ++-vdev_fail: ++- /* ++- * Restore the ID to the global map. ++- */ ++- ar->free_vdev_map |= 1 << (ar->monitor_vdev_id); ++- return ret; ++ } ++ ++ static int ath10k_monitor_vdev_delete(struct ath10k *ar) ++@@ -633,14 +702,14 @@ static int ath10k_monitor_vdev_delete(st ++ ++ ret = ath10k_wmi_vdev_delete(ar, ar->monitor_vdev_id); ++ if (ret) { ++- ath10k_warn("failed to request wmi monitor vdev %i removal: %d\n", +++ ath10k_warn(ar, "failed to request wmi monitor vdev %i removal: %d\n", ++ ar->monitor_vdev_id, ret); ++ return ret; ++ } ++ ++- ar->free_vdev_map |= 1 << (ar->monitor_vdev_id); +++ ar->free_vdev_map |= 1LL << ar->monitor_vdev_id; ++ ++- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n", +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n", ++ ar->monitor_vdev_id); ++ return ret; ++ } ++@@ -651,63 +720,70 @@ static int ath10k_monitor_start(struct a ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++- if (!ath10k_monitor_is_enabled(ar)) { ++- ath10k_warn("trying to start monitor with no references\n"); ++- return 0; ++- } ++- ++- if (ar->monitor_started) { ++- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor already started\n"); ++- return 0; ++- } ++- ++ ret = ath10k_monitor_vdev_create(ar); ++ if (ret) { ++- ath10k_warn("failed to create monitor vdev: %d\n", ret); +++ ath10k_warn(ar, "failed to create monitor vdev: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ath10k_monitor_vdev_start(ar, ar->monitor_vdev_id); ++ if (ret) { ++- ath10k_warn("failed to start monitor vdev: %d\n", ret); +++ ath10k_warn(ar, "failed to start monitor vdev: %d\n", ret); ++ ath10k_monitor_vdev_delete(ar); ++ return ret; ++ } ++ ++ ar->monitor_started = true; ++- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor started\n"); +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor started\n"); ++ ++ return 0; ++ } ++ ++-static void ath10k_monitor_stop(struct ath10k *ar) +++static int ath10k_monitor_stop(struct ath10k *ar) ++ { ++ int ret; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++- if (ath10k_monitor_is_enabled(ar)) { ++- ath10k_dbg(ATH10K_DBG_MAC, ++- "mac monitor will be stopped later\n"); ++- return; +++ ret = ath10k_monitor_vdev_stop(ar); +++ if (ret) { +++ ath10k_warn(ar, "failed to stop monitor vdev: %d\n", ret); +++ return ret; ++ } ++ ++- if (!ar->monitor_started) { ++- ath10k_dbg(ATH10K_DBG_MAC, ++- "mac monitor probably failed to start earlier\n"); ++- return; +++ ret = ath10k_monitor_vdev_delete(ar); +++ if (ret) { +++ ath10k_warn(ar, "failed to delete monitor vdev: %d\n", ret); +++ return ret; ++ } ++ ++- ret = ath10k_monitor_vdev_stop(ar); ++- if (ret) ++- ath10k_warn("failed to stop monitor vdev: %d\n", ret); +++ ar->monitor_started = false; +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor stopped\n"); ++ ++- ret = ath10k_monitor_vdev_delete(ar); ++- if (ret) ++- ath10k_warn("failed to delete monitor vdev: %d\n", ret); +++ return 0; +++} ++ ++- ar->monitor_started = false; ++- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor stopped\n"); +++static int ath10k_monitor_recalc(struct ath10k *ar) +++{ +++ bool should_start; +++ +++ lockdep_assert_held(&ar->conf_mutex); +++ +++ should_start = ar->monitor || +++ ar->filter_flags & FIF_PROMISC_IN_BSS || +++ test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); +++ +++ ath10k_dbg(ar, ATH10K_DBG_MAC, +++ "mac monitor recalc started? %d should? %d\n", +++ ar->monitor_started, should_start); +++ +++ if (should_start == ar->monitor_started) +++ return 0; +++ +++ if (should_start) +++ return ath10k_monitor_start(ar); +++ +++ return ath10k_monitor_stop(ar); ++ } ++ ++ static int ath10k_recalc_rtscts_prot(struct ath10k_vif *arvif) ++@@ -738,14 +814,14 @@ static int ath10k_start_cac(struct ath10 ++ ++ set_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); ++ ++- ret = ath10k_monitor_start(ar); +++ ret = ath10k_monitor_recalc(ar); ++ if (ret) { ++- ath10k_warn("failed to start monitor (cac): %d\n", ret); +++ ath10k_warn(ar, "failed to start monitor (cac): %d\n", ret); ++ clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); ++ return ret; ++ } ++ ++- ath10k_dbg(ATH10K_DBG_MAC, "mac cac start monitor vdev %d\n", +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac cac start monitor vdev %d\n", ++ ar->monitor_vdev_id); ++ ++ return 0; ++@@ -762,7 +838,7 @@ static int ath10k_stop_cac(struct ath10k ++ clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); ++ ath10k_monitor_stop(ar); ++ ++- ath10k_dbg(ATH10K_DBG_MAC, "mac cac finished\n"); +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac cac finished\n"); ++ ++ return 0; ++ } ++@@ -788,12 +864,12 @@ static void ath10k_recalc_radar_detectio ++ * radiation is not allowed, make this channel DFS_UNAVAILABLE ++ * by indicating that radar was detected. ++ */ ++- ath10k_warn("failed to start CAC: %d\n", ret); +++ ath10k_warn(ar, "failed to start CAC: %d\n", ret); ++ ieee80211_radar_detected(ar->hw); ++ } ++ } ++ ++-static int ath10k_vdev_start(struct ath10k_vif *arvif) +++static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, bool restart) ++ { ++ struct ath10k *ar = arvif->ar; ++ struct cfg80211_chan_def *chandef = &ar->chandef; ++@@ -830,22 +906,27 @@ static int ath10k_vdev_start(struct ath1 ++ arg.ssid_len = arvif->vif->bss_conf.ssid_len; ++ } ++ ++- ath10k_dbg(ATH10K_DBG_MAC, +++ ath10k_dbg(ar, ATH10K_DBG_MAC, ++ "mac vdev %d start center_freq %d phymode %s\n", ++ arg.vdev_id, arg.channel.freq, ++ ath10k_wmi_phymode_str(arg.channel.mode)); ++ ++- ret = ath10k_wmi_vdev_start(ar, &arg); +++ if (restart) +++ ret = ath10k_wmi_vdev_restart(ar, &arg); +++ else +++ ret = ath10k_wmi_vdev_start(ar, &arg); +++ ++ if (ret) { ++- ath10k_warn("failed to start WMI vdev %i: %d\n", +++ ath10k_warn(ar, "failed to start WMI vdev %i: %d\n", ++ arg.vdev_id, ret); ++ return ret; ++ } ++ ++ ret = ath10k_vdev_setup_sync(ar); ++ if (ret) { ++- ath10k_warn("failed to synchronise setup for vdev %i: %d\n", ++- arg.vdev_id, ret); +++ ath10k_warn(ar, +++ "failed to synchronize setup for vdev %i restart %d: %d\n", +++ arg.vdev_id, restart, ret); ++ return ret; ++ } ++ ++@@ -855,6 +936,16 @@ static int ath10k_vdev_start(struct ath1 ++ return ret; ++ } ++ +++static int ath10k_vdev_start(struct ath10k_vif *arvif) +++{ +++ return ath10k_vdev_start_restart(arvif, false); +++} +++ +++static int ath10k_vdev_restart(struct ath10k_vif *arvif) +++{ +++ return ath10k_vdev_start_restart(arvif, true); +++} +++ ++ static int ath10k_vdev_stop(struct ath10k_vif *arvif) ++ { ++ struct ath10k *ar = arvif->ar; ++@@ -866,14 +957,14 @@ static int ath10k_vdev_stop(struct ath10 ++ ++ ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id); ++ if (ret) { ++- ath10k_warn("failed to stop WMI vdev %i: %d\n", +++ ath10k_warn(ar, "failed to stop WMI vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ return ret; ++ } ++ ++ ret = ath10k_vdev_setup_sync(ar); ++ if (ret) { ++- ath10k_warn("failed to syncronise setup for vdev %i: %d\n", +++ ath10k_warn(ar, "failed to synchronize setup for vdev %i stop: %d\n", ++ arvif->vdev_id, ret); ++ return ret; ++ } ++@@ -888,9 +979,147 @@ static int ath10k_vdev_stop(struct ath10 ++ return ret; ++ } ++ +++static int ath10k_mac_setup_bcn_p2p_ie(struct ath10k_vif *arvif, +++ struct sk_buff *bcn) +++{ +++ struct ath10k *ar = arvif->ar; +++ struct ieee80211_mgmt *mgmt; +++ const u8 *p2p_ie; +++ int ret; +++ +++ if (arvif->vdev_type != WMI_VDEV_TYPE_AP) +++ return 0; +++ +++ if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO) +++ return 0; +++ +++ mgmt = (void *)bcn->data; +++ p2p_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P, +++ mgmt->u.beacon.variable, +++ bcn->len - (mgmt->u.beacon.variable - +++ bcn->data)); +++ if (!p2p_ie) +++ return -ENOENT; +++ +++ ret = ath10k_wmi_p2p_go_bcn_ie(ar, arvif->vdev_id, p2p_ie); +++ if (ret) { +++ ath10k_warn(ar, "failed to submit p2p go bcn ie for vdev %i: %d\n", +++ arvif->vdev_id, ret); +++ return ret; +++ } +++ +++ return 0; +++} +++ +++static int ath10k_mac_remove_vendor_ie(struct sk_buff *skb, unsigned int oui, +++ u8 oui_type, size_t ie_offset) +++{ +++ size_t len; +++ const u8 *next; +++ const u8 *end; +++ u8 *ie; +++ +++ if (WARN_ON(skb->len < ie_offset)) +++ return -EINVAL; +++ +++ ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type, +++ skb->data + ie_offset, +++ skb->len - ie_offset); +++ if (!ie) +++ return -ENOENT; +++ +++ len = ie[1] + 2; +++ end = skb->data + skb->len; +++ next = ie + len; +++ +++ if (WARN_ON(next > end)) +++ return -EINVAL; +++ +++ memmove(ie, next, end - next); +++ skb_trim(skb, skb->len - len); +++ +++ return 0; +++} +++ +++static int ath10k_mac_setup_bcn_tmpl(struct ath10k_vif *arvif) +++{ +++ struct ath10k *ar = arvif->ar; +++ struct ieee80211_hw *hw = ar->hw; +++ struct ieee80211_vif *vif = arvif->vif; +++ struct ieee80211_mutable_offsets offs = {}; +++ struct sk_buff *bcn; +++ int ret; +++ +++ if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map)) +++ return 0; +++ +++ bcn = ieee80211_beacon_get_template(hw, vif, &offs); +++ if (!bcn) { +++ ath10k_warn(ar, "failed to get beacon template from mac80211\n"); +++ return -EPERM; +++ } +++ +++ ret = ath10k_mac_setup_bcn_p2p_ie(arvif, bcn); +++ if (ret) { +++ ath10k_warn(ar, "failed to setup p2p go bcn ie: %d\n", ret); +++ kfree_skb(bcn); +++ return ret; +++ } +++ +++ /* P2P IE is inserted by firmware automatically (as configured above) +++ * so remove it from the base beacon template to avoid duplicate P2P +++ * IEs in beacon frames. +++ */ +++ ath10k_mac_remove_vendor_ie(bcn, WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P, +++ offsetof(struct ieee80211_mgmt, +++ u.beacon.variable)); +++ +++ ret = ath10k_wmi_bcn_tmpl(ar, arvif->vdev_id, offs.tim_offset, bcn, 0, +++ 0, NULL, 0); +++ kfree_skb(bcn); +++ +++ if (ret) { +++ ath10k_warn(ar, "failed to submit beacon template command: %d\n", +++ ret); +++ return ret; +++ } +++ +++ return 0; +++} +++ +++static int ath10k_mac_setup_prb_tmpl(struct ath10k_vif *arvif) +++{ +++ struct ath10k *ar = arvif->ar; +++ struct ieee80211_hw *hw = ar->hw; +++ struct ieee80211_vif *vif = arvif->vif; +++ struct sk_buff *prb; +++ int ret; +++ +++ if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map)) +++ return 0; +++ +++ prb = ieee80211_proberesp_get(hw, vif); +++ if (!prb) { +++ ath10k_warn(ar, "failed to get probe resp template from mac80211\n"); +++ return -EPERM; +++ } +++ +++ ret = ath10k_wmi_prb_tmpl(ar, arvif->vdev_id, prb); +++ kfree_skb(prb); +++ +++ if (ret) { +++ ath10k_warn(ar, "failed to submit probe resp template command: %d\n", +++ ret); +++ return ret; +++ } +++ +++ return 0; +++} +++ ++ static void ath10k_control_beaconing(struct ath10k_vif *arvif, ++- struct ieee80211_bss_conf *info) +++ struct ieee80211_bss_conf *info) ++ { +++ struct ath10k *ar = arvif->ar; ++ int ret = 0; ++ ++ lockdep_assert_held(&arvif->ar->conf_mutex); ++@@ -902,15 +1131,7 @@ static void ath10k_control_beaconing(str ++ arvif->is_up = false; ++ ++ spin_lock_bh(&arvif->ar->data_lock); ++- if (arvif->beacon) { ++- dma_unmap_single(arvif->ar->dev, ++- ATH10K_SKB_CB(arvif->beacon)->paddr, ++- arvif->beacon->len, DMA_TO_DEVICE); ++- dev_kfree_skb_any(arvif->beacon); ++- ++- arvif->beacon = NULL; ++- arvif->beacon_sent = false; ++- } +++ ath10k_mac_vif_beacon_free(arvif); ++ spin_unlock_bh(&arvif->ar->data_lock); ++ ++ return; ++@@ -923,12 +1144,12 @@ static void ath10k_control_beaconing(str ++ return; ++ ++ arvif->aid = 0; ++- memcpy(arvif->bssid, info->bssid, ETH_ALEN); +++ ether_addr_copy(arvif->bssid, info->bssid); ++ ++ ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, ++ arvif->bssid); ++ if (ret) { ++- ath10k_warn("failed to bring up vdev %d: %i\n", +++ ath10k_warn(ar, "failed to bring up vdev %d: %i\n", ++ arvif->vdev_id, ret); ++ ath10k_vdev_stop(arvif); ++ return; ++@@ -937,13 +1158,14 @@ static void ath10k_control_beaconing(str ++ arvif->is_started = true; ++ arvif->is_up = true; ++ ++- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id); +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id); ++ } ++ ++ static void ath10k_control_ibss(struct ath10k_vif *arvif, ++ struct ieee80211_bss_conf *info, ++ const u8 self_peer[ETH_ALEN]) ++ { +++ struct ath10k *ar = arvif->ar; ++ u32 vdev_param; ++ int ret = 0; ++ ++@@ -952,20 +1174,12 @@ static void ath10k_control_ibss(struct a ++ if (!info->ibss_joined) { ++ ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, self_peer); ++ if (ret) ++- ath10k_warn("failed to delete IBSS self peer %pM for vdev %d: %d\n", +++ ath10k_warn(ar, "failed to delete IBSS self peer %pM for vdev %d: %d\n", ++ self_peer, arvif->vdev_id, ret); ++ ++ if (is_zero_ether_addr(arvif->bssid)) ++ return; ++ ++- ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, ++- arvif->bssid); ++- if (ret) { ++- ath10k_warn("failed to delete IBSS BSSID peer %pM for vdev %d: %d\n", ++- arvif->bssid, arvif->vdev_id, ret); ++- return; ++- } ++- ++ memset(arvif->bssid, 0, ETH_ALEN); ++ ++ return; ++@@ -973,7 +1187,7 @@ static void ath10k_control_ibss(struct a ++ ++ ret = ath10k_peer_create(arvif->ar, arvif->vdev_id, self_peer); ++ if (ret) { ++- ath10k_warn("failed to create IBSS self peer %pM for vdev %d: %d\n", +++ ath10k_warn(ar, "failed to create IBSS self peer %pM for vdev %d: %d\n", ++ self_peer, arvif->vdev_id, ret); ++ return; ++ } ++@@ -982,103 +1196,211 @@ static void ath10k_control_ibss(struct a ++ ret = ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, vdev_param, ++ ATH10K_DEFAULT_ATIM); ++ if (ret) ++- ath10k_warn("failed to set IBSS ATIM for vdev %d: %d\n", +++ ath10k_warn(ar, "failed to set IBSS ATIM for vdev %d: %d\n", ++ arvif->vdev_id, ret); ++ } ++ ++-/* ++- * Review this when mac80211 gains per-interface powersave support. ++- */ ++-static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) +++static int ath10k_mac_vif_recalc_ps_wake_threshold(struct ath10k_vif *arvif) ++ { ++ struct ath10k *ar = arvif->ar; ++- struct ieee80211_conf *conf = &ar->hw->conf; ++- enum wmi_sta_powersave_param param; ++- enum wmi_sta_ps_mode psmode; +++ u32 param; +++ u32 value; ++ int ret; ++ ++ lockdep_assert_held(&arvif->ar->conf_mutex); ++ ++- if (arvif->vif->type != NL80211_IFTYPE_STATION) ++- return 0; ++- ++- if (conf->flags & IEEE80211_CONF_PS) { ++- psmode = WMI_STA_PS_MODE_ENABLED; ++- param = WMI_STA_PS_PARAM_INACTIVITY_TIME; +++ if (arvif->u.sta.uapsd) +++ value = WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER; +++ else +++ value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS; ++ ++- ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, ++- conf->dynamic_ps_timeout); ++- if (ret) { ++- ath10k_warn("failed to set inactivity time for vdev %d: %i\n", ++- arvif->vdev_id, ret); ++- return ret; ++- } ++- } else { ++- psmode = WMI_STA_PS_MODE_DISABLED; +++ param = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD; +++ ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, value); +++ if (ret) { +++ ath10k_warn(ar, "failed to submit ps wake threshold %u on vdev %i: %d\n", +++ value, arvif->vdev_id, ret); +++ return ret; ++ } ++ ++- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d psmode %s\n", ++- arvif->vdev_id, psmode ? "enable" : "disable"); +++ return 0; +++} ++ ++- ret = ath10k_wmi_set_psmode(ar, arvif->vdev_id, psmode); +++static int ath10k_mac_vif_recalc_ps_poll_count(struct ath10k_vif *arvif) +++{ +++ struct ath10k *ar = arvif->ar; +++ u32 param; +++ u32 value; +++ int ret; +++ +++ lockdep_assert_held(&arvif->ar->conf_mutex); +++ +++ if (arvif->u.sta.uapsd) +++ value = WMI_STA_PS_PSPOLL_COUNT_UAPSD; +++ else +++ value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX; +++ +++ param = WMI_STA_PS_PARAM_PSPOLL_COUNT; +++ ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, +++ param, value); ++ if (ret) { ++- ath10k_warn("failed to set PS Mode %d for vdev %d: %d\n", ++- psmode, arvif->vdev_id, ret); +++ ath10k_warn(ar, "failed to submit ps poll count %u on vdev %i: %d\n", +++ value, arvif->vdev_id, ret); ++ return ret; ++ } ++ ++ return 0; ++ } ++ ++-/**********************/ ++-/* Station management */ ++-/**********************/ ++- ++-static void ath10k_peer_assoc_h_basic(struct ath10k *ar, ++- struct ath10k_vif *arvif, ++- struct ieee80211_sta *sta, ++- struct ieee80211_bss_conf *bss_conf, ++- struct wmi_peer_assoc_complete_arg *arg) +++static int ath10k_mac_ps_vif_count(struct ath10k *ar) ++ { +++ struct ath10k_vif *arvif; +++ int num = 0; +++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++- memcpy(arg->addr, sta->addr, ETH_ALEN); ++- arg->vdev_id = arvif->vdev_id; ++- arg->peer_aid = sta->aid; ++- arg->peer_flags |= WMI_PEER_AUTH; +++ list_for_each_entry(arvif, &ar->arvifs, list) +++ if (arvif->ps) +++ num++; ++ ++- if (arvif->vdev_type == WMI_VDEV_TYPE_STA) ++- /* ++- * Seems FW have problems with Power Save in STA ++- * mode when we setup this parameter to high (eg. 5). ++- * Often we see that FW don't send NULL (with clean P flags) ++- * frame even there is info about buffered frames in beacons. ++- * Sometimes we have to wait more than 10 seconds before FW ++- * will wakeup. Often sending one ping from AP to our device ++- * just fail (more than 50%). ++- * ++- * Seems setting this FW parameter to 1 couse FW ++- * will check every beacon and will wakup immediately ++- * after detection buffered data. ++- */ ++- arg->peer_listen_intval = 1; ++- else ++- arg->peer_listen_intval = ar->hw->conf.listen_interval; +++ return num; +++} ++ ++- arg->peer_num_spatial_streams = 1; +++static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) +++{ +++ struct ath10k *ar = arvif->ar; +++ struct ieee80211_vif *vif = arvif->vif; +++ struct ieee80211_conf *conf = &ar->hw->conf; +++ enum wmi_sta_powersave_param param; +++ enum wmi_sta_ps_mode psmode; +++ int ret; +++ int ps_timeout; +++ bool enable_ps; ++ ++- /* ++- * The assoc capabilities are available only in managed mode. +++ lockdep_assert_held(&arvif->ar->conf_mutex); +++ +++ if (arvif->vif->type != NL80211_IFTYPE_STATION) +++ return 0; +++ +++ enable_ps = arvif->ps; +++ +++ if (enable_ps && ath10k_mac_ps_vif_count(ar) > 1 && +++ !test_bit(ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT, +++ ar->fw_features)) { +++ ath10k_warn(ar, "refusing to enable ps on vdev %i: not supported by fw\n", +++ arvif->vdev_id); +++ enable_ps = false; +++ } +++ +++ if (enable_ps) { +++ psmode = WMI_STA_PS_MODE_ENABLED; +++ param = WMI_STA_PS_PARAM_INACTIVITY_TIME; +++ +++ ps_timeout = conf->dynamic_ps_timeout; +++ if (ps_timeout == 0) { +++ /* Firmware doesn't like 0 */ +++ ps_timeout = ieee80211_tu_to_usec( +++ vif->bss_conf.beacon_int) / 1000; +++ } +++ +++ ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, +++ ps_timeout); +++ if (ret) { +++ ath10k_warn(ar, "failed to set inactivity time for vdev %d: %i\n", +++ arvif->vdev_id, ret); +++ return ret; +++ } +++ } else { +++ psmode = WMI_STA_PS_MODE_DISABLED; +++ } +++ +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d psmode %s\n", +++ arvif->vdev_id, psmode ? "enable" : "disable"); +++ +++ ret = ath10k_wmi_set_psmode(ar, arvif->vdev_id, psmode); +++ if (ret) { +++ ath10k_warn(ar, "failed to set PS Mode %d for vdev %d: %d\n", +++ psmode, arvif->vdev_id, ret); +++ return ret; +++ } +++ +++ return 0; +++} +++ +++static int ath10k_mac_vif_disable_keepalive(struct ath10k_vif *arvif) +++{ +++ struct ath10k *ar = arvif->ar; +++ struct wmi_sta_keepalive_arg arg = {}; +++ int ret; +++ +++ lockdep_assert_held(&arvif->ar->conf_mutex); +++ +++ if (arvif->vdev_type != WMI_VDEV_TYPE_STA) +++ return 0; +++ +++ if (!test_bit(WMI_SERVICE_STA_KEEP_ALIVE, ar->wmi.svc_map)) +++ return 0; +++ +++ /* Some firmware revisions have a bug and ignore the `enabled` field. +++ * Instead use the interval to disable the keepalive. +++ */ +++ arg.vdev_id = arvif->vdev_id; +++ arg.enabled = 1; +++ arg.method = WMI_STA_KEEPALIVE_METHOD_NULL_FRAME; +++ arg.interval = WMI_STA_KEEPALIVE_INTERVAL_DISABLE; +++ +++ ret = ath10k_wmi_sta_keepalive(ar, &arg); +++ if (ret) { +++ ath10k_warn(ar, "failed to submit keepalive on vdev %i: %d\n", +++ arvif->vdev_id, ret); +++ return ret; +++ } +++ +++ return 0; +++} +++ +++/**********************/ +++/* Station management */ +++/**********************/ +++ +++static u32 ath10k_peer_assoc_h_listen_intval(struct ath10k *ar, +++ struct ieee80211_vif *vif) +++{ +++ /* Some firmware revisions have unstable STA powersave when listen +++ * interval is set too high (e.g. 5). The symptoms are firmware doesn't +++ * generate NullFunc frames properly even if buffered frames have been +++ * indicated in Beacon TIM. Firmware would seldom wake up to pull +++ * buffered frames. Often pinging the device from AP would simply fail. +++ * +++ * As a workaround set it to 1. ++ */ ++- if (arvif->vdev_type == WMI_VDEV_TYPE_STA && bss_conf) ++- arg->peer_caps = bss_conf->assoc_capability; +++ if (vif->type == NL80211_IFTYPE_STATION) +++ return 1; +++ +++ return ar->hw->conf.listen_interval; +++} +++ +++static void ath10k_peer_assoc_h_basic(struct ath10k *ar, +++ struct ieee80211_vif *vif, +++ struct ieee80211_sta *sta, +++ struct wmi_peer_assoc_complete_arg *arg) +++{ +++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); +++ +++ lockdep_assert_held(&ar->conf_mutex); +++ +++ ether_addr_copy(arg->addr, sta->addr); +++ arg->vdev_id = arvif->vdev_id; +++ arg->peer_aid = sta->aid; +++ arg->peer_flags |= WMI_PEER_AUTH; +++ arg->peer_listen_intval = ath10k_peer_assoc_h_listen_intval(ar, vif); +++ arg->peer_num_spatial_streams = 1; +++ arg->peer_caps = vif->bss_conf.assoc_capability; ++ } ++ ++ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar, ++- struct ath10k_vif *arvif, +++ struct ieee80211_vif *vif, ++ struct wmi_peer_assoc_complete_arg *arg) ++ { ++- struct ieee80211_vif *vif = arvif->vif; ++ struct ieee80211_bss_conf *info = &vif->bss_conf; ++ struct cfg80211_bss *bss; ++ const u8 *rsnie = NULL; ++@@ -1097,21 +1419,21 @@ static void ath10k_peer_assoc_h_crypto(s ++ ies = rcu_dereference(bss->ies); ++ ++ wpaie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, ++- WLAN_OUI_TYPE_MICROSOFT_WPA, ++- ies->data, ++- ies->len); +++ WLAN_OUI_TYPE_MICROSOFT_WPA, +++ ies->data, +++ ies->len); ++ rcu_read_unlock(); ++ cfg80211_put_bss(ar->hw->wiphy, bss); ++ } ++ ++ /* FIXME: base on RSN IE/WPA IE is a correct idea? */ ++ if (rsnie || wpaie) { ++- ath10k_dbg(ATH10K_DBG_WMI, "%s: rsn ie found\n", __func__); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: rsn ie found\n", __func__); ++ arg->peer_flags |= WMI_PEER_NEED_PTK_4_WAY; ++ } ++ ++ if (wpaie) { ++- ath10k_dbg(ATH10K_DBG_WMI, "%s: wpa ie found\n", __func__); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: wpa ie found\n", __func__); ++ arg->peer_flags |= WMI_PEER_NEED_GTK_2_WAY; ++ } ++ } ++@@ -1149,6 +1471,7 @@ static void ath10k_peer_assoc_h_ht(struc ++ { ++ const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; ++ int i, n; +++ u32 stbc; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++@@ -1185,7 +1508,6 @@ static void ath10k_peer_assoc_h_ht(struc ++ } ++ ++ if (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC) { ++- u32 stbc; ++ stbc = ht_cap->cap & IEEE80211_HT_CAP_RX_STBC; ++ stbc = stbc >> IEEE80211_HT_CAP_RX_STBC_SHIFT; ++ stbc = stbc << WMI_RC_RX_STBC_FLAG_S; ++@@ -1220,7 +1542,7 @@ static void ath10k_peer_assoc_h_ht(struc ++ arg->peer_num_spatial_streams = sta->rx_nss; ++ } ++ ++- ath10k_dbg(ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n", +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n", ++ arg->addr, ++ arg->peer_ht_rates.num_rates, ++ arg->peer_num_spatial_streams); ++@@ -1237,7 +1559,7 @@ static int ath10k_peer_assoc_qos_ap(stru ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ if (sta->wme && sta->uapsd_queues) { ++- ath10k_dbg(ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n", +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n", ++ sta->uapsd_queues, sta->max_sp); ++ ++ if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) ++@@ -1253,7 +1575,6 @@ static int ath10k_peer_assoc_qos_ap(stru ++ uapsd |= WMI_AP_PS_UAPSD_AC0_DELIVERY_EN | ++ WMI_AP_PS_UAPSD_AC0_TRIGGER_EN; ++ ++- ++ if (sta->max_sp < MAX_WMI_AP_PS_PEER_PARAM_MAX_SP) ++ max_sp = sta->max_sp; ++ ++@@ -1262,7 +1583,7 @@ static int ath10k_peer_assoc_qos_ap(stru ++ WMI_AP_PS_PEER_PARAM_UAPSD, ++ uapsd); ++ if (ret) { ++- ath10k_warn("failed to set ap ps peer param uapsd for vdev %i: %d\n", +++ ath10k_warn(ar, "failed to set ap ps peer param uapsd for vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ return ret; ++ } ++@@ -1272,7 +1593,7 @@ static int ath10k_peer_assoc_qos_ap(stru ++ WMI_AP_PS_PEER_PARAM_MAX_SP, ++ max_sp); ++ if (ret) { ++- ath10k_warn("failed to set ap ps peer param max sp for vdev %i: %d\n", +++ ath10k_warn(ar, "failed to set ap ps peer param max sp for vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ return ret; ++ } ++@@ -1282,9 +1603,10 @@ static int ath10k_peer_assoc_qos_ap(stru ++ sta->listen_interval - mac80211 patch required. ++ Currently use 10 seconds */ ++ ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, sta->addr, ++- WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, 10); +++ WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, +++ 10); ++ if (ret) { ++- ath10k_warn("failed to set ap ps peer param ageout time for vdev %i: %d\n", +++ ath10k_warn(ar, "failed to set ap ps peer param ageout time for vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ return ret; ++ } ++@@ -1304,8 +1626,11 @@ static void ath10k_peer_assoc_h_vht(stru ++ return; ++ ++ arg->peer_flags |= WMI_PEER_VHT; ++- arg->peer_vht_caps = vht_cap->cap; ++ +++ if (ar->hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ) +++ arg->peer_flags |= WMI_PEER_VHT_2G; +++ +++ arg->peer_vht_caps = vht_cap->cap; ++ ++ ampdu_factor = (vht_cap->cap & ++ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >> ++@@ -1331,16 +1656,17 @@ static void ath10k_peer_assoc_h_vht(stru ++ arg->peer_vht_rates.tx_mcs_set = ++ __le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map); ++ ++- ath10k_dbg(ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n", +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n", ++ sta->addr, arg->peer_max_mpdu, arg->peer_flags); ++ } ++ ++ static void ath10k_peer_assoc_h_qos(struct ath10k *ar, ++- struct ath10k_vif *arvif, +++ struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta, ++- struct ieee80211_bss_conf *bss_conf, ++ struct wmi_peer_assoc_complete_arg *arg) ++ { +++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); +++ ++ switch (arvif->vdev_type) { ++ case WMI_VDEV_TYPE_AP: ++ if (sta->wme) ++@@ -1352,16 +1678,29 @@ static void ath10k_peer_assoc_h_qos(stru ++ } ++ break; ++ case WMI_VDEV_TYPE_STA: ++- if (bss_conf->qos) +++ if (vif->bss_conf.qos) +++ arg->peer_flags |= WMI_PEER_QOS; +++ break; +++ case WMI_VDEV_TYPE_IBSS: +++ if (sta->wme) ++ arg->peer_flags |= WMI_PEER_QOS; ++ break; ++ default: ++ break; ++ } +++ +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac peer %pM qos %d\n", +++ sta->addr, !!(arg->peer_flags & WMI_PEER_QOS)); +++} +++ +++static bool ath10k_mac_sta_has_11g_rates(struct ieee80211_sta *sta) +++{ +++ /* First 4 rates in ath10k_rates are CCK (11b) rates. */ +++ return sta->supp_rates[IEEE80211_BAND_2GHZ] >> 4; ++ } ++ ++ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar, ++- struct ath10k_vif *arvif, +++ struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta, ++ struct wmi_peer_assoc_complete_arg *arg) ++ { ++@@ -1369,13 +1708,20 @@ static void ath10k_peer_assoc_h_phymode( ++ ++ switch (ar->hw->conf.chandef.chan->band) { ++ case IEEE80211_BAND_2GHZ: ++- if (sta->ht_cap.ht_supported) { +++ if (sta->vht_cap.vht_supported) { +++ if (sta->bandwidth == IEEE80211_STA_RX_BW_40) +++ phymode = MODE_11AC_VHT40; +++ else +++ phymode = MODE_11AC_VHT20; +++ } else if (sta->ht_cap.ht_supported) { ++ if (sta->bandwidth == IEEE80211_STA_RX_BW_40) ++ phymode = MODE_11NG_HT40; ++ else ++ phymode = MODE_11NG_HT20; ++- } else { +++ } else if (ath10k_mac_sta_has_11g_rates(sta)) { ++ phymode = MODE_11G; +++ } else { +++ phymode = MODE_11B; ++ } ++ ++ break; ++@@ -1404,7 +1750,7 @@ static void ath10k_peer_assoc_h_phymode( ++ break; ++ } ++ ++- ath10k_dbg(ATH10K_DBG_MAC, "mac peer %pM phymode %s\n", +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac peer %pM phymode %s\n", ++ sta->addr, ath10k_wmi_phymode_str(phymode)); ++ ++ arg->peer_phymode = phymode; ++@@ -1412,22 +1758,21 @@ static void ath10k_peer_assoc_h_phymode( ++ } ++ ++ static int ath10k_peer_assoc_prepare(struct ath10k *ar, ++- struct ath10k_vif *arvif, +++ struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta, ++- struct ieee80211_bss_conf *bss_conf, ++ struct wmi_peer_assoc_complete_arg *arg) ++ { ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ memset(arg, 0, sizeof(*arg)); ++ ++- ath10k_peer_assoc_h_basic(ar, arvif, sta, bss_conf, arg); ++- ath10k_peer_assoc_h_crypto(ar, arvif, arg); +++ ath10k_peer_assoc_h_basic(ar, vif, sta, arg); +++ ath10k_peer_assoc_h_crypto(ar, vif, arg); ++ ath10k_peer_assoc_h_rates(ar, sta, arg); ++ ath10k_peer_assoc_h_ht(ar, sta, arg); ++ ath10k_peer_assoc_h_vht(ar, sta, arg); ++- ath10k_peer_assoc_h_qos(ar, arvif, sta, bss_conf, arg); ++- ath10k_peer_assoc_h_phymode(ar, arvif, sta, arg); +++ ath10k_peer_assoc_h_qos(ar, vif, sta, arg); +++ ath10k_peer_assoc_h_phymode(ar, vif, sta, arg); ++ ++ return 0; ++ } ++@@ -1459,6 +1804,68 @@ static int ath10k_setup_peer_smps(struct ++ ath10k_smps_map[smps]); ++ } ++ +++static int ath10k_mac_vif_recalc_txbf(struct ath10k *ar, +++ struct ieee80211_vif *vif, +++ struct ieee80211_sta_vht_cap vht_cap) +++{ +++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); +++ int ret; +++ u32 param; +++ u32 value; +++ +++ if (!(ar->vht_cap_info & +++ (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | +++ IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | +++ IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | +++ IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE))) +++ return 0; +++ +++ param = ar->wmi.vdev_param->txbf; +++ value = 0; +++ +++ if (WARN_ON(param == WMI_VDEV_PARAM_UNSUPPORTED)) +++ return 0; +++ +++ /* The following logic is correct. If a remote STA advertises support +++ * for being a beamformer then we should enable us being a beamformee. +++ */ +++ +++ if (ar->vht_cap_info & +++ (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | +++ IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)) { +++ if (vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) +++ value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFEE; +++ +++ if (vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) +++ value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFEE; +++ } +++ +++ if (ar->vht_cap_info & +++ (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | +++ IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) { +++ if (vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) +++ value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFER; +++ +++ if (vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) +++ value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFER; +++ } +++ +++ if (value & WMI_VDEV_PARAM_TXBF_MU_TX_BFEE) +++ value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFEE; +++ +++ if (value & WMI_VDEV_PARAM_TXBF_MU_TX_BFER) +++ value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFER; +++ +++ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, value); +++ if (ret) { +++ ath10k_warn(ar, "failed to submit vdev param txbf 0x%x: %d\n", +++ value, ret); +++ return ret; +++ } +++ +++ return 0; +++} +++ ++ /* can be called only in mac80211 callbacks due to `key_count` usage */ ++ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++@@ -1467,17 +1874,21 @@ static void ath10k_bss_assoc(struct ieee ++ struct ath10k *ar = hw->priv; ++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); ++ struct ieee80211_sta_ht_cap ht_cap; +++ struct ieee80211_sta_vht_cap vht_cap; ++ struct wmi_peer_assoc_complete_arg peer_arg; ++ struct ieee80211_sta *ap_sta; ++ int ret; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i assoc bssid %pM aid %d\n", +++ arvif->vdev_id, arvif->bssid, arvif->aid); +++ ++ rcu_read_lock(); ++ ++ ap_sta = ieee80211_find_sta(vif, bss_conf->bssid); ++ if (!ap_sta) { ++- ath10k_warn("failed to find station entry for bss %pM vdev %i\n", +++ ath10k_warn(ar, "failed to find station entry for bss %pM vdev %i\n", ++ bss_conf->bssid, arvif->vdev_id); ++ rcu_read_unlock(); ++ return; ++@@ -1486,11 +1897,11 @@ static void ath10k_bss_assoc(struct ieee ++ /* ap_sta must be accessed only within rcu section which must be left ++ * before calling ath10k_setup_peer_smps() which might sleep. */ ++ ht_cap = ap_sta->ht_cap; +++ vht_cap = ap_sta->vht_cap; ++ ++- ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta, ++- bss_conf, &peer_arg); +++ ret = ath10k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg); ++ if (ret) { ++- ath10k_warn("failed to prepare peer assoc for %pM vdev %i: %d\n", +++ ath10k_warn(ar, "failed to prepare peer assoc for %pM vdev %i: %d\n", ++ bss_conf->bssid, arvif->vdev_id, ret); ++ rcu_read_unlock(); ++ return; ++@@ -1500,88 +1911,100 @@ static void ath10k_bss_assoc(struct ieee ++ ++ ret = ath10k_wmi_peer_assoc(ar, &peer_arg); ++ if (ret) { ++- ath10k_warn("failed to run peer assoc for %pM vdev %i: %d\n", +++ ath10k_warn(ar, "failed to run peer assoc for %pM vdev %i: %d\n", ++ bss_conf->bssid, arvif->vdev_id, ret); ++ return; ++ } ++ ++ ret = ath10k_setup_peer_smps(ar, arvif, bss_conf->bssid, &ht_cap); ++ if (ret) { ++- ath10k_warn("failed to setup peer SMPS for vdev %i: %d\n", +++ ath10k_warn(ar, "failed to setup peer SMPS for vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ return; ++ } ++ ++- ath10k_dbg(ATH10K_DBG_MAC, +++ ret = ath10k_mac_vif_recalc_txbf(ar, vif, vht_cap); +++ if (ret) { +++ ath10k_warn(ar, "failed to recalc txbf for vdev %i on bss %pM: %d\n", +++ arvif->vdev_id, bss_conf->bssid, ret); +++ return; +++ } +++ +++ ath10k_dbg(ar, ATH10K_DBG_MAC, ++ "mac vdev %d up (associated) bssid %pM aid %d\n", ++ arvif->vdev_id, bss_conf->bssid, bss_conf->aid); ++ +++ WARN_ON(arvif->is_up); +++ ++ arvif->aid = bss_conf->aid; ++- memcpy(arvif->bssid, bss_conf->bssid, ETH_ALEN); +++ ether_addr_copy(arvif->bssid, bss_conf->bssid); ++ ++ ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid); ++ if (ret) { ++- ath10k_warn("failed to set vdev %d up: %d\n", +++ ath10k_warn(ar, "failed to set vdev %d up: %d\n", ++ arvif->vdev_id, ret); ++ return; ++ } ++ ++ arvif->is_up = true; +++ +++ /* Workaround: Some firmware revisions (tested with qca6174 +++ * WLAN.RM.2.0-00073) have buggy powersave state machine and must be +++ * poked with peer param command. +++ */ +++ ret = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, arvif->bssid, +++ WMI_PEER_DUMMY_VAR, 1); +++ if (ret) { +++ ath10k_warn(ar, "failed to poke peer %pM param for ps workaround on vdev %i: %d\n", +++ arvif->bssid, arvif->vdev_id, ret); +++ return; +++ } ++ } ++ ++-/* ++- * FIXME: flush TIDs ++- */ ++ static void ath10k_bss_disassoc(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif) ++ { ++ struct ath10k *ar = hw->priv; ++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); +++ struct ieee80211_sta_vht_cap vht_cap = {}; ++ int ret; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++- /* ++- * For some reason, calling VDEV-DOWN before VDEV-STOP ++- * makes the FW to send frames via HTT after disassociation. ++- * No idea why this happens, even though VDEV-DOWN is supposed ++- * to be analogous to link down, so just stop the VDEV. ++- */ ++- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d stop (disassociated\n", ++- arvif->vdev_id); ++- ++- /* FIXME: check return value */ ++- ret = ath10k_vdev_stop(arvif); ++- ++- /* ++- * If we don't call VDEV-DOWN after VDEV-STOP FW will remain active and ++- * report beacons from previously associated network through HTT. ++- * This in turn would spam mac80211 WARN_ON if we bring down all ++- * interfaces as it expects there is no rx when no interface is ++- * running. ++- */ ++- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d down\n", arvif->vdev_id); +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i disassoc bssid %pM\n", +++ arvif->vdev_id, arvif->bssid); ++ ++- /* FIXME: why don't we print error if wmi call fails? */ ++ ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); +++ if (ret) +++ ath10k_warn(ar, "faield to down vdev %i: %d\n", +++ arvif->vdev_id, ret); ++ ++- arvif->def_wep_key_idx = 0; +++ arvif->def_wep_key_idx = -1; +++ +++ ret = ath10k_mac_vif_recalc_txbf(ar, vif, vht_cap); +++ if (ret) { +++ ath10k_warn(ar, "failed to recalc txbf for vdev %i: %d\n", +++ arvif->vdev_id, ret); +++ return; +++ } ++ ++- arvif->is_started = false; ++ arvif->is_up = false; ++ } ++ ++-static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, ++- struct ieee80211_sta *sta, bool reassoc) +++static int ath10k_station_assoc(struct ath10k *ar, +++ struct ieee80211_vif *vif, +++ struct ieee80211_sta *sta, +++ bool reassoc) ++ { +++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); ++ struct wmi_peer_assoc_complete_arg peer_arg; ++ int ret = 0; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++- ret = ath10k_peer_assoc_prepare(ar, arvif, sta, NULL, &peer_arg); +++ ret = ath10k_peer_assoc_prepare(ar, vif, sta, &peer_arg); ++ if (ret) { ++- ath10k_warn("failed to prepare WMI peer assoc for %pM vdev %i: %i\n", +++ ath10k_warn(ar, "failed to prepare WMI peer assoc for %pM vdev %i: %i\n", ++ sta->addr, arvif->vdev_id, ret); ++ return ret; ++ } ++@@ -1589,48 +2012,59 @@ static int ath10k_station_assoc(struct a ++ peer_arg.peer_reassoc = reassoc; ++ ret = ath10k_wmi_peer_assoc(ar, &peer_arg); ++ if (ret) { ++- ath10k_warn("failed to run peer assoc for STA %pM vdev %i: %d\n", +++ ath10k_warn(ar, "failed to run peer assoc for STA %pM vdev %i: %d\n", ++ sta->addr, arvif->vdev_id, ret); ++ return ret; ++ } ++ ++- ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap); ++- if (ret) { ++- ath10k_warn("failed to setup peer SMPS for vdev %d: %d\n", ++- arvif->vdev_id, ret); ++- return ret; ++- } ++- ++- if (!sta->wme) { ++- arvif->num_legacy_stations++; ++- ret = ath10k_recalc_rtscts_prot(arvif); +++ /* Re-assoc is run only to update supported rates for given station. It +++ * doesn't make much sense to reconfigure the peer completely. +++ */ +++ if (!reassoc) { +++ ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, +++ &sta->ht_cap); ++ if (ret) { ++- ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n", +++ ath10k_warn(ar, "failed to setup peer SMPS for vdev %d: %d\n", ++ arvif->vdev_id, ret); ++ return ret; ++ } ++- } ++ ++- ret = ath10k_install_peer_wep_keys(arvif, sta->addr); ++- if (ret) { ++- ath10k_warn("failed to install peer wep keys for vdev %i: %d\n", ++- arvif->vdev_id, ret); ++- return ret; ++- } +++ ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta); +++ if (ret) { +++ ath10k_warn(ar, "failed to set qos params for STA %pM for vdev %i: %d\n", +++ sta->addr, arvif->vdev_id, ret); +++ return ret; +++ } ++ ++- ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta); ++- if (ret) { ++- ath10k_warn("failed to set qos params for STA %pM for vdev %i: %d\n", ++- sta->addr, arvif->vdev_id, ret); ++- return ret; +++ if (!sta->wme) { +++ arvif->num_legacy_stations++; +++ ret = ath10k_recalc_rtscts_prot(arvif); +++ if (ret) { +++ ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n", +++ arvif->vdev_id, ret); +++ return ret; +++ } +++ } +++ +++ /* Plumb cached keys only for static WEP */ +++ if (arvif->def_wep_key_idx != -1) { +++ ret = ath10k_install_peer_wep_keys(arvif, sta->addr); +++ if (ret) { +++ ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n", +++ arvif->vdev_id, ret); +++ return ret; +++ } +++ } ++ } ++ ++ return ret; ++ } ++ ++-static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif, +++static int ath10k_station_disassoc(struct ath10k *ar, +++ struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta) ++ { +++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); ++ int ret = 0; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++@@ -1639,7 +2073,7 @@ static int ath10k_station_disassoc(struc ++ arvif->num_legacy_stations--; ++ ret = ath10k_recalc_rtscts_prot(arvif); ++ if (ret) { ++- ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n", +++ ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n", ++ arvif->vdev_id, ret); ++ return ret; ++ } ++@@ -1647,7 +2081,7 @@ static int ath10k_station_disassoc(struc ++ ++ ret = ath10k_clear_peer_keys(arvif, sta->addr); ++ if (ret) { ++- ath10k_warn("failed to clear all peer wep keys for vdev %i: %d\n", +++ ath10k_warn(ar, "failed to clear all peer wep keys for vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ return ret; ++ } ++@@ -1722,6 +2156,7 @@ static int ath10k_update_channel_list(st ++ ch->passive = passive; ++ ++ ch->freq = channel->center_freq; +++ ch->band_center_freq1 = channel->center_freq; ++ ch->min_power = 0; ++ ch->max_power = channel->max_power * 2; ++ ch->max_reg_power = channel->max_reg_power * 2; ++@@ -1739,7 +2174,7 @@ static int ath10k_update_channel_list(st ++ if (WARN_ON_ONCE(ch->mode == MODE_UNKNOWN)) ++ continue; ++ ++- ath10k_dbg(ATH10K_DBG_WMI, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "mac channel [%zd/%d] freq %d maxpower %d regpower %d antenna %d mode %d\n", ++ ch - arg.channels, arg.n_channels, ++ ch->freq, ch->max_power, ch->max_reg_power, ++@@ -1782,7 +2217,7 @@ static void ath10k_regd_update(struct at ++ ++ ret = ath10k_update_channel_list(ar); ++ if (ret) ++- ath10k_warn("failed to update channel list: %d\n", ret); +++ ath10k_warn(ar, "failed to update channel list: %d\n", ret); ++ ++ regpair = ar->ath_common.regulatory.regpair; ++ ++@@ -1803,7 +2238,7 @@ static void ath10k_regd_update(struct at ++ regpair->reg_5ghz_ctl, ++ wmi_dfs_reg); ++ if (ret) ++- ath10k_warn("failed to set pdev regdomain: %d\n", ret); +++ ath10k_warn(ar, "failed to set pdev regdomain: %d\n", ret); ++ } ++ ++ static void ath10k_reg_notifier(struct wiphy *wiphy, ++@@ -1816,12 +2251,12 @@ static void ath10k_reg_notifier(struct w ++ ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory); ++ ++ if (config_enabled(CPTCFG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) { ++- ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs region 0x%x\n", +++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs region 0x%x\n", ++ request->dfs_region); ++ result = ar->dfs_detector->set_dfs_domain(ar->dfs_detector, ++ request->dfs_region); ++ if (!result) ++- ath10k_warn("DFS region 0x%X not supported, will trigger radar for every pulse\n", +++ ath10k_warn(ar, "DFS region 0x%X not supported, will trigger radar for every pulse\n", ++ request->dfs_region); ++ } ++ ++@@ -1849,28 +2284,25 @@ static u8 ath10k_tx_h_get_tid(struct iee ++ return ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; ++ } ++ ++-static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, ++- struct ieee80211_tx_info *info) +++static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, struct ieee80211_vif *vif) ++ { ++- if (info->control.vif) ++- return ath10k_vif_to_arvif(info->control.vif)->vdev_id; +++ if (vif) +++ return ath10k_vif_to_arvif(vif)->vdev_id; ++ ++ if (ar->monitor_started) ++ return ar->monitor_vdev_id; ++ ++- ath10k_warn("failed to resolve vdev id\n"); +++ ath10k_warn(ar, "failed to resolve vdev id\n"); ++ return 0; ++ } ++ ++-/* ++- * Frames sent to the FW have to be in "Native Wifi" format. ++- * Strip the QoS field from the 802.11 header. +++/* HTT Tx uses Native Wifi tx mode which expects 802.11 frames without QoS +++ * Control in the header. ++ */ ++-static void ath10k_tx_h_qos_workaround(struct ieee80211_hw *hw, ++- struct ieee80211_tx_control *control, ++- struct sk_buff *skb) +++static void ath10k_tx_h_nwifi(struct ieee80211_hw *hw, struct sk_buff *skb) ++ { ++ struct ieee80211_hdr *hdr = (void *)skb->data; +++ struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb); ++ u8 *qos_ctl; ++ ++ if (!ieee80211_is_data_qos(hdr->frame_control)) ++@@ -1880,68 +2312,24 @@ static void ath10k_tx_h_qos_workaround(s ++ memmove(skb->data + IEEE80211_QOS_CTL_LEN, ++ skb->data, (void *)qos_ctl - (void *)skb->data); ++ skb_pull(skb, IEEE80211_QOS_CTL_LEN); ++-} ++- ++-static void ath10k_tx_wep_key_work(struct work_struct *work) ++-{ ++- struct ath10k_vif *arvif = container_of(work, struct ath10k_vif, ++- wep_key_work); ++- int ret, keyidx = arvif->def_wep_key_newidx; ++- ++- if (arvif->def_wep_key_idx == keyidx) ++- return; ++- ++- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n", ++- arvif->vdev_id, keyidx); ++ ++- ret = ath10k_wmi_vdev_set_param(arvif->ar, ++- arvif->vdev_id, ++- arvif->ar->wmi.vdev_param->def_keyid, ++- keyidx); ++- if (ret) { ++- ath10k_warn("failed to update wep key index for vdev %d: %d\n", ++- arvif->vdev_id, ++- ret); ++- return; +++ /* Fw/Hw generates a corrupted QoS Control Field for QoS NullFunc +++ * frames. Powersave is handled by the fw/hw so QoS NyllFunc frames are +++ * used only for CQM purposes (e.g. hostapd station keepalive ping) so +++ * it is safe to downgrade to NullFunc. +++ */ +++ hdr = (void *)skb->data; +++ if (ieee80211_is_qos_nullfunc(hdr->frame_control)) { +++ hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA); +++ cb->htt.tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST; ++ } ++- ++- arvif->def_wep_key_idx = keyidx; ++ } ++ ++-static void ath10k_tx_h_update_wep_key(struct sk_buff *skb) ++-{ ++- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ++- struct ieee80211_vif *vif = info->control.vif; ++- struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); ++- struct ath10k *ar = arvif->ar; ++- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; ++- struct ieee80211_key_conf *key = info->control.hw_key; ++- ++- if (!ieee80211_has_protected(hdr->frame_control)) ++- return; ++- ++- if (!key) ++- return; ++- ++- if (key->cipher != WLAN_CIPHER_SUITE_WEP40 && ++- key->cipher != WLAN_CIPHER_SUITE_WEP104) ++- return; ++- ++- if (key->keyidx == arvif->def_wep_key_idx) ++- return; ++- ++- /* FIXME: Most likely a few frames will be TXed with an old key. Simply ++- * queueing frames until key index is updated is not an option because ++- * sk_buff may need more processing to be done, e.g. offchannel */ ++- arvif->def_wep_key_newidx = key->keyidx; ++- ieee80211_queue_work(ar->hw, &arvif->wep_key_work); ++-} ++- ++-static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, struct sk_buff *skb) +++static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, +++ struct ieee80211_vif *vif, +++ struct sk_buff *skb) ++ { ++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; ++- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ++- struct ieee80211_vif *vif = info->control.vif; ++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); ++ ++ /* This is case only for P2P_GO */ ++@@ -1961,6 +2349,18 @@ static void ath10k_tx_h_add_p2p_noa_ie(s ++ } ++ } ++ +++static bool ath10k_mac_need_offchan_tx_work(struct ath10k *ar) +++{ +++ /* FIXME: Not really sure since when the behaviour changed. At some +++ * point new firmware stopped requiring creation of peer entries for +++ * offchannel tx (and actually creating them causes issues with wmi-htc +++ * tx credit replenishment and reliability). Assuming it's at least 3.4 +++ * because that's when the `freq` was introduced to TX_FRM HTT command. +++ */ +++ return !(ar->htt.target_version_major >= 3 && +++ ar->htt.target_version_minor >= 4); +++} +++ ++ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb) ++ { ++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; ++@@ -1977,7 +2377,7 @@ static void ath10k_tx_htt(struct ath10k ++ ar->fw_features)) { ++ if (skb_queue_len(&ar->wmi_mgmt_tx_queue) >= ++ ATH10K_MAX_NUM_MGMT_PENDING) { ++- ath10k_warn("reached WMI management tranmist queue limit\n"); +++ ath10k_warn(ar, "reached WMI management transmit queue limit\n"); ++ ret = -EBUSY; ++ goto exit; ++ } ++@@ -2001,7 +2401,8 @@ static void ath10k_tx_htt(struct ath10k ++ ++ exit: ++ if (ret) { ++- ath10k_warn("failed to transmit packet, dropping: %d\n", ret); +++ ath10k_warn(ar, "failed to transmit packet, dropping: %d\n", +++ ret); ++ ieee80211_free_txskb(ar->hw, skb); ++ } ++ } ++@@ -2043,7 +2444,7 @@ void ath10k_offchan_tx_work(struct work_ ++ ++ mutex_lock(&ar->conf_mutex); ++ ++- ath10k_dbg(ATH10K_DBG_MAC, "mac offchannel skb %p\n", +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac offchannel skb %p\n", ++ skb); ++ ++ hdr = (struct ieee80211_hdr *)skb->data; ++@@ -2056,13 +2457,13 @@ void ath10k_offchan_tx_work(struct work_ ++ ++ if (peer) ++ /* FIXME: should this use ath10k_warn()? */ ++- ath10k_dbg(ATH10K_DBG_MAC, "peer %pM on vdev %d already present\n", +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "peer %pM on vdev %d already present\n", ++ peer_addr, vdev_id); ++ ++ if (!peer) { ++ ret = ath10k_peer_create(ar, vdev_id, peer_addr); ++ if (ret) ++- ath10k_warn("failed to create peer %pM on vdev %d: %d\n", +++ ath10k_warn(ar, "failed to create peer %pM on vdev %d: %d\n", ++ peer_addr, vdev_id, ret); ++ } ++ ++@@ -2075,14 +2476,14 @@ void ath10k_offchan_tx_work(struct work_ ++ ++ ret = wait_for_completion_timeout(&ar->offchan_tx_completed, ++ 3 * HZ); ++- if (ret <= 0) ++- ath10k_warn("timed out waiting for offchannel skb %p\n", +++ if (ret == 0) +++ ath10k_warn(ar, "timed out waiting for offchannel skb %p\n", ++ skb); ++ ++ if (!peer) { ++ ret = ath10k_peer_delete(ar, vdev_id, peer_addr); ++ if (ret) ++- ath10k_warn("failed to delete peer %pM on vdev %d: %d\n", +++ ath10k_warn(ar, "failed to delete peer %pM on vdev %d: %d\n", ++ peer_addr, vdev_id, ret); ++ } ++ ++@@ -2116,7 +2517,7 @@ void ath10k_mgmt_over_wmi_tx_work(struct ++ ++ ret = ath10k_wmi_mgmt_tx(ar, skb); ++ if (ret) { ++- ath10k_warn("failed to transmit management frame via WMI: %d\n", +++ ath10k_warn(ar, "failed to transmit management frame via WMI: %d\n", ++ ret); ++ ieee80211_free_txskb(ar->hw, skb); ++ } ++@@ -2127,34 +2528,41 @@ void ath10k_mgmt_over_wmi_tx_work(struct ++ /* Scanning */ ++ /************/ ++ ++-/* ++- * This gets called if we dont get a heart-beat during scan. ++- * This may indicate the FW has hung and we need to abort the ++- * scan manually to prevent cancel_hw_scan() from deadlocking ++- */ ++-void ath10k_reset_scan(unsigned long ptr) +++void __ath10k_scan_finish(struct ath10k *ar) ++ { ++- struct ath10k *ar = (struct ath10k *)ptr; ++- ++- spin_lock_bh(&ar->data_lock); ++- if (!ar->scan.in_progress) { ++- spin_unlock_bh(&ar->data_lock); ++- return; ++- } +++ lockdep_assert_held(&ar->data_lock); ++ ++- ath10k_warn("scan timed out, firmware problem?\n"); ++- ++- if (ar->scan.is_roc) ++- ieee80211_remain_on_channel_expired(ar->hw); ++- else ++- ieee80211_scan_completed(ar->hw, 1 /* aborted */); +++ switch (ar->scan.state) { +++ case ATH10K_SCAN_IDLE: +++ break; +++ case ATH10K_SCAN_RUNNING: +++ if (ar->scan.is_roc) +++ ieee80211_remain_on_channel_expired(ar->hw); +++ /* fall through */ +++ case ATH10K_SCAN_ABORTING: +++ if (!ar->scan.is_roc) +++ ieee80211_scan_completed(ar->hw, +++ (ar->scan.state == +++ ATH10K_SCAN_ABORTING)); +++ /* fall through */ +++ case ATH10K_SCAN_STARTING: +++ ar->scan.state = ATH10K_SCAN_IDLE; +++ ar->scan_channel = NULL; +++ ath10k_offchan_tx_purge(ar); +++ cancel_delayed_work(&ar->scan.timeout); +++ complete_all(&ar->scan.completed); +++ break; +++ } +++} ++ ++- ar->scan.in_progress = false; ++- complete_all(&ar->scan.completed); +++void ath10k_scan_finish(struct ath10k *ar) +++{ +++ spin_lock_bh(&ar->data_lock); +++ __ath10k_scan_finish(ar); ++ spin_unlock_bh(&ar->data_lock); ++ } ++ ++-static int ath10k_abort_scan(struct ath10k *ar) +++static int ath10k_scan_stop(struct ath10k *ar) ++ { ++ struct wmi_stop_scan_arg arg = { ++ .req_id = 1, /* FIXME */ ++@@ -2165,47 +2573,79 @@ static int ath10k_abort_scan(struct ath1 ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++- del_timer_sync(&ar->scan.timeout); +++ ret = ath10k_wmi_stop_scan(ar, &arg); +++ if (ret) { +++ ath10k_warn(ar, "failed to stop wmi scan: %d\n", ret); +++ goto out; +++ } ++ ++- spin_lock_bh(&ar->data_lock); ++- if (!ar->scan.in_progress) { ++- spin_unlock_bh(&ar->data_lock); ++- return 0; +++ ret = wait_for_completion_timeout(&ar->scan.completed, 3*HZ); +++ if (ret == 0) { +++ ath10k_warn(ar, "failed to receive scan abortion completion: timed out\n"); +++ ret = -ETIMEDOUT; +++ } else if (ret > 0) { +++ ret = 0; ++ } ++ ++- ar->scan.aborting = true; +++out: +++ /* Scan state should be updated upon scan completion but in case +++ * firmware fails to deliver the event (for whatever reason) it is +++ * desired to clean up scan state anyway. Firmware may have just +++ * dropped the scan completion event delivery due to transport pipe +++ * being overflown with data and/or it can recover on its own before +++ * next scan request is submitted. +++ */ +++ spin_lock_bh(&ar->data_lock); +++ if (ar->scan.state != ATH10K_SCAN_IDLE) +++ __ath10k_scan_finish(ar); ++ spin_unlock_bh(&ar->data_lock); ++ ++- ret = ath10k_wmi_stop_scan(ar, &arg); ++- if (ret) { ++- ath10k_warn("failed to stop wmi scan: %d\n", ret); ++- spin_lock_bh(&ar->data_lock); ++- ar->scan.in_progress = false; ++- ath10k_offchan_tx_purge(ar); ++- spin_unlock_bh(&ar->data_lock); ++- return -EIO; ++- } +++ return ret; +++} ++ ++- ret = wait_for_completion_timeout(&ar->scan.completed, 3*HZ); ++- if (ret == 0) ++- ath10k_warn("timed out while waiting for scan to stop\n"); +++static void ath10k_scan_abort(struct ath10k *ar) +++{ +++ int ret; ++ ++- /* scan completion may be done right after we timeout here, so let's ++- * check the in_progress and tell mac80211 scan is completed. if we ++- * don't do that and FW fails to send us scan completion indication ++- * then userspace won't be able to scan anymore */ ++- ret = 0; +++ lockdep_assert_held(&ar->conf_mutex); ++ ++ spin_lock_bh(&ar->data_lock); ++- if (ar->scan.in_progress) { ++- ath10k_warn("failed to stop scan, it's still in progress\n"); ++- ar->scan.in_progress = false; ++- ath10k_offchan_tx_purge(ar); ++- ret = -ETIMEDOUT; +++ +++ switch (ar->scan.state) { +++ case ATH10K_SCAN_IDLE: +++ /* This can happen if timeout worker kicked in and called +++ * abortion while scan completion was being processed. +++ */ +++ break; +++ case ATH10K_SCAN_STARTING: +++ case ATH10K_SCAN_ABORTING: +++ ath10k_warn(ar, "refusing scan abortion due to invalid scan state: %s (%d)\n", +++ ath10k_scan_state_str(ar->scan.state), +++ ar->scan.state); +++ break; +++ case ATH10K_SCAN_RUNNING: +++ ar->scan.state = ATH10K_SCAN_ABORTING; +++ spin_unlock_bh(&ar->data_lock); +++ +++ ret = ath10k_scan_stop(ar); +++ if (ret) +++ ath10k_warn(ar, "failed to abort scan: %d\n", ret); +++ +++ spin_lock_bh(&ar->data_lock); +++ break; ++ } +++ ++ spin_unlock_bh(&ar->data_lock); +++} ++ ++- return ret; +++void ath10k_scan_timeout_work(struct work_struct *work) +++{ +++ struct ath10k *ar = container_of(work, struct ath10k, +++ scan.timeout.work); +++ +++ mutex_lock(&ar->conf_mutex); +++ ath10k_scan_abort(ar); +++ mutex_unlock(&ar->conf_mutex); ++ } ++ ++ static int ath10k_start_scan(struct ath10k *ar, ++@@ -2221,17 +2661,27 @@ static int ath10k_start_scan(struct ath1 ++ ++ ret = wait_for_completion_timeout(&ar->scan.started, 1*HZ); ++ if (ret == 0) { ++- ath10k_abort_scan(ar); ++- return ret; +++ ret = ath10k_scan_stop(ar); +++ if (ret) +++ ath10k_warn(ar, "failed to stop scan: %d\n", ret); +++ +++ return -ETIMEDOUT; +++ } +++ +++ /* If we failed to start the scan, return error code at +++ * this point. This is probably due to some issue in the +++ * firmware, but no need to wedge the driver due to that... +++ */ +++ spin_lock_bh(&ar->data_lock); +++ if (ar->scan.state == ATH10K_SCAN_IDLE) { +++ spin_unlock_bh(&ar->data_lock); +++ return -EINVAL; ++ } +++ spin_unlock_bh(&ar->data_lock); ++ ++- /* the scan can complete earlier, before we even ++- * start the timer. in that case the timer handler ++- * checks ar->scan.in_progress and bails out if its ++- * false. Add a 200ms margin to account event/command ++- * processing. */ ++- mod_timer(&ar->scan.timeout, jiffies + ++- msecs_to_jiffies(arg->max_scan_time+200)); +++ /* 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; ++ } ++ ++@@ -2243,90 +2693,163 @@ static void ath10k_tx(struct ieee80211_h ++ struct ieee80211_tx_control *control, ++ struct sk_buff *skb) ++ { +++ struct ath10k *ar = hw->priv; ++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); +++ struct ieee80211_vif *vif = info->control.vif; ++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; ++- struct ath10k *ar = hw->priv; ++- u8 tid, vdev_id; ++ ++ /* We should disable CCK RATE due to P2P */ ++ if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE) ++- ath10k_dbg(ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n"); +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n"); ++ ++- /* we must calculate tid before we apply qos workaround ++- * as we'd lose the qos control field */ ++- tid = ath10k_tx_h_get_tid(hdr); ++- vdev_id = ath10k_tx_h_get_vdev_id(ar, info); +++ ATH10K_SKB_CB(skb)->htt.is_offchan = false; +++ ATH10K_SKB_CB(skb)->htt.tid = ath10k_tx_h_get_tid(hdr); +++ ATH10K_SKB_CB(skb)->vdev_id = ath10k_tx_h_get_vdev_id(ar, vif); ++ ++ /* it makes no sense to process injected frames like that */ ++- if (info->control.vif && ++- info->control.vif->type != NL80211_IFTYPE_MONITOR) { ++- ath10k_tx_h_qos_workaround(hw, control, skb); ++- ath10k_tx_h_update_wep_key(skb); ++- ath10k_tx_h_add_p2p_noa_ie(ar, skb); ++- ath10k_tx_h_seq_no(skb); +++ if (vif && vif->type != NL80211_IFTYPE_MONITOR) { +++ ath10k_tx_h_nwifi(hw, skb); +++ ath10k_tx_h_add_p2p_noa_ie(ar, vif, skb); +++ ath10k_tx_h_seq_no(vif, skb); ++ } ++ ++- ATH10K_SKB_CB(skb)->vdev_id = vdev_id; ++- ATH10K_SKB_CB(skb)->htt.is_offchan = false; ++- ATH10K_SKB_CB(skb)->htt.tid = tid; ++- ++ if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { ++ spin_lock_bh(&ar->data_lock); ++- ATH10K_SKB_CB(skb)->htt.is_offchan = true; +++ ATH10K_SKB_CB(skb)->htt.freq = ar->scan.roc_freq; ++ ATH10K_SKB_CB(skb)->vdev_id = ar->scan.vdev_id; ++ spin_unlock_bh(&ar->data_lock); ++ ++- ath10k_dbg(ATH10K_DBG_MAC, "queued offchannel skb %p\n", skb); +++ if (ath10k_mac_need_offchan_tx_work(ar)) { +++ ATH10K_SKB_CB(skb)->htt.freq = 0; +++ ATH10K_SKB_CB(skb)->htt.is_offchan = true; ++ ++- skb_queue_tail(&ar->offchan_tx_queue, skb); ++- ieee80211_queue_work(hw, &ar->offchan_tx_work); ++- return; +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %p\n", +++ skb); +++ +++ skb_queue_tail(&ar->offchan_tx_queue, skb); +++ ieee80211_queue_work(hw, &ar->offchan_tx_work); +++ return; +++ } ++ } ++ ++ ath10k_tx_htt(ar, skb); ++ } ++ ++-/* ++- * Initialize various parameters with default vaules. ++- */ +++/* Must not be called with conf_mutex held as workers can use that also. */ +++void ath10k_drain_tx(struct ath10k *ar) +++{ +++ /* make sure rcu-protected mac80211 tx path itself is drained */ +++ synchronize_net(); +++ +++ ath10k_offchan_tx_purge(ar); +++ ath10k_mgmt_over_wmi_tx_purge(ar); +++ +++ cancel_work_sync(&ar->offchan_tx_work); +++ cancel_work_sync(&ar->wmi_mgmt_tx_work); +++} +++ ++ void ath10k_halt(struct ath10k *ar) ++ { ++ struct ath10k_vif *arvif; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++- if (ath10k_monitor_is_enabled(ar)) { ++- clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); ++- ar->promisc = false; ++- ar->monitor = false; +++ clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); +++ ar->filter_flags = 0; +++ ar->monitor = false; +++ +++ if (ar->monitor_started) ++ ath10k_monitor_stop(ar); ++- } ++ ++- del_timer_sync(&ar->scan.timeout); ++- ath10k_offchan_tx_purge(ar); ++- ath10k_mgmt_over_wmi_tx_purge(ar); +++ ar->monitor_started = false; +++ +++ ath10k_scan_finish(ar); ++ ath10k_peer_cleanup_all(ar); ++ ath10k_core_stop(ar); ++ ath10k_hif_power_down(ar); ++ ++ spin_lock_bh(&ar->data_lock); ++- if (ar->scan.in_progress) { ++- del_timer(&ar->scan.timeout); ++- ar->scan.in_progress = false; ++- ieee80211_scan_completed(ar->hw, true); +++ list_for_each_entry(arvif, &ar->arvifs, list) +++ ath10k_mac_vif_beacon_cleanup(arvif); +++ spin_unlock_bh(&ar->data_lock); +++} +++ +++static int ath10k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +++{ +++ struct ath10k *ar = hw->priv; +++ +++ mutex_lock(&ar->conf_mutex); +++ +++ if (ar->cfg_tx_chainmask) { +++ *tx_ant = ar->cfg_tx_chainmask; +++ *rx_ant = ar->cfg_rx_chainmask; +++ } else { +++ *tx_ant = ar->supp_tx_chainmask; +++ *rx_ant = ar->supp_rx_chainmask; ++ } ++ ++- list_for_each_entry(arvif, &ar->arvifs, list) { ++- if (!arvif->beacon) ++- continue; +++ mutex_unlock(&ar->conf_mutex); ++ ++- dma_unmap_single(arvif->ar->dev, ++- ATH10K_SKB_CB(arvif->beacon)->paddr, ++- arvif->beacon->len, DMA_TO_DEVICE); ++- dev_kfree_skb_any(arvif->beacon); ++- arvif->beacon = NULL; +++ return 0; +++} +++ +++static void ath10k_check_chain_mask(struct ath10k *ar, u32 cm, const char *dbg) +++{ +++ /* It is not clear that allowing gaps in chainmask +++ * is helpful. Probably it will not do what user +++ * is hoping for, so warn in that case. +++ */ +++ if (cm == 15 || cm == 7 || cm == 3 || cm == 1 || cm == 0) +++ return; +++ +++ ath10k_warn(ar, "mac %s antenna chainmask may be invalid: 0x%x. Suggested values: 15, 7, 3, 1 or 0.\n", +++ dbg, cm); +++} +++ +++static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant) +++{ +++ int ret; +++ +++ lockdep_assert_held(&ar->conf_mutex); +++ +++ ath10k_check_chain_mask(ar, tx_ant, "tx"); +++ ath10k_check_chain_mask(ar, rx_ant, "rx"); +++ +++ ar->cfg_tx_chainmask = tx_ant; +++ ar->cfg_rx_chainmask = rx_ant; +++ +++ if ((ar->state != ATH10K_STATE_ON) && +++ (ar->state != ATH10K_STATE_RESTARTED)) +++ return 0; +++ +++ ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->tx_chain_mask, +++ tx_ant); +++ if (ret) { +++ ath10k_warn(ar, "failed to set tx-chainmask: %d, req 0x%x\n", +++ ret, tx_ant); +++ return ret; ++ } ++- spin_unlock_bh(&ar->data_lock); +++ +++ ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->rx_chain_mask, +++ rx_ant); +++ if (ret) { +++ ath10k_warn(ar, "failed to set rx-chainmask: %d, req 0x%x\n", +++ ret, rx_ant); +++ return ret; +++ } +++ +++ return 0; +++} +++ +++static int ath10k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +++{ +++ struct ath10k *ar = hw->priv; +++ int ret; +++ +++ mutex_lock(&ar->conf_mutex); +++ ret = __ath10k_set_antenna(ar, tx_ant, rx_ant); +++ mutex_unlock(&ar->conf_mutex); +++ return ret; ++ } ++ ++ static int ath10k_start(struct ieee80211_hw *hw) ++@@ -2334,41 +2857,61 @@ static int ath10k_start(struct ieee80211 ++ struct ath10k *ar = hw->priv; ++ int ret = 0; ++ +++ /* +++ * This makes sense only when restarting hw. It is harmless to call +++ * uncoditionally. This is necessary to make sure no HTT/WMI tx +++ * commands will be submitted while restarting. +++ */ +++ ath10k_drain_tx(ar); +++ ++ mutex_lock(&ar->conf_mutex); ++ ++- if (ar->state != ATH10K_STATE_OFF && ++- ar->state != ATH10K_STATE_RESTARTING) { +++ switch (ar->state) { +++ case ATH10K_STATE_OFF: +++ ar->state = ATH10K_STATE_ON; +++ break; +++ case ATH10K_STATE_RESTARTING: +++ ath10k_halt(ar); +++ ar->state = ATH10K_STATE_RESTARTED; +++ break; +++ case ATH10K_STATE_ON: +++ case ATH10K_STATE_RESTARTED: +++ case ATH10K_STATE_WEDGED: +++ WARN_ON(1); ++ ret = -EINVAL; ++- goto exit; +++ goto err; +++ case ATH10K_STATE_UTF: +++ ret = -EBUSY; +++ goto err; ++ } ++ ++ ret = ath10k_hif_power_up(ar); ++ if (ret) { ++- ath10k_err("Could not init hif: %d\n", ret); ++- ar->state = ATH10K_STATE_OFF; ++- goto exit; +++ ath10k_err(ar, "Could not init hif: %d\n", ret); +++ goto err_off; ++ } ++ ++- ret = ath10k_core_start(ar); +++ ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL); ++ if (ret) { ++- ath10k_err("Could not init core: %d\n", ret); ++- ath10k_hif_power_down(ar); ++- ar->state = ATH10K_STATE_OFF; ++- goto exit; +++ ath10k_err(ar, "Could not init core: %d\n", ret); +++ goto err_power_down; ++ } ++ ++- if (ar->state == ATH10K_STATE_OFF) ++- ar->state = ATH10K_STATE_ON; ++- else if (ar->state == ATH10K_STATE_RESTARTING) ++- ar->state = ATH10K_STATE_RESTARTED; ++- ++ ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pmf_qos, 1); ++- if (ret) ++- ath10k_warn("failed to enable PMF QOS: %d\n", ret); +++ if (ret) { +++ ath10k_warn(ar, "failed to enable PMF QOS: %d\n", ret); +++ goto err_core_stop; +++ } ++ ++ ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 1); ++- if (ret) ++- ath10k_warn("failed to enable dynamic BW: %d\n", ret); +++ if (ret) { +++ ath10k_warn(ar, "failed to enable dynamic BW: %d\n", ret); +++ goto err_core_stop; +++ } +++ +++ if (ar->cfg_tx_chainmask) +++ __ath10k_set_antenna(ar, ar->cfg_tx_chainmask, +++ ar->cfg_rx_chainmask); ++ ++ /* ++ * By default FW set ARP frames ac to voice (6). In that case ARP ++@@ -2382,16 +2925,29 @@ static int ath10k_start(struct ieee80211 ++ ret = ath10k_wmi_pdev_set_param(ar, ++ ar->wmi.pdev_param->arp_ac_override, 0); ++ if (ret) { ++- ath10k_warn("failed to set arp ac override parameter: %d\n", +++ ath10k_warn(ar, "failed to set arp ac override parameter: %d\n", ++ ret); ++- goto exit; +++ goto err_core_stop; ++ } ++ ++ ar->num_started_vdevs = 0; ++ ath10k_regd_update(ar); ++- ret = 0; ++ ++-exit: +++ ath10k_spectral_start(ar); +++ +++ mutex_unlock(&ar->conf_mutex); +++ return 0; +++ +++err_core_stop: +++ ath10k_core_stop(ar); +++ +++err_power_down: +++ ath10k_hif_power_down(ar); +++ +++err_off: +++ ar->state = ATH10K_STATE_OFF; +++ +++err: ++ mutex_unlock(&ar->conf_mutex); ++ return ret; ++ } ++@@ -2400,19 +2956,16 @@ static void ath10k_stop(struct ieee80211 ++ { ++ struct ath10k *ar = hw->priv; ++ +++ ath10k_drain_tx(ar); +++ ++ mutex_lock(&ar->conf_mutex); ++- if (ar->state == ATH10K_STATE_ON || ++- ar->state == ATH10K_STATE_RESTARTED || ++- ar->state == ATH10K_STATE_WEDGED) +++ if (ar->state != ATH10K_STATE_OFF) { ++ ath10k_halt(ar); ++- ++- ar->state = ATH10K_STATE_OFF; +++ ar->state = ATH10K_STATE_OFF; +++ } ++ mutex_unlock(&ar->conf_mutex); ++ ++- ath10k_mgmt_over_wmi_tx_purge(ar); ++- ++- cancel_work_sync(&ar->offchan_tx_work); ++- cancel_work_sync(&ar->wmi_mgmt_tx_work); +++ cancel_delayed_work_sync(&ar->scan.timeout); ++ cancel_work_sync(&ar->restart_work); ++ } ++ ++@@ -2426,7 +2979,7 @@ static int ath10k_config_ps(struct ath10 ++ list_for_each_entry(arvif, &ar->arvifs, list) { ++ ret = ath10k_mac_vif_setup_ps(arvif); ++ if (ret) { ++- ath10k_warn("failed to setup powersave: %d\n", ret); +++ ath10k_warn(ar, "failed to setup powersave: %d\n", ret); ++ break; ++ } ++ } ++@@ -2464,7 +3017,7 @@ static void ath10k_config_chan(struct at ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++- ath10k_dbg(ATH10K_DBG_MAC, +++ ath10k_dbg(ar, ATH10K_DBG_MAC, ++ "mac config channel to %dMHz (cf1 %dMHz cf2 %dMHz width %s)\n", ++ ar->chandef.chan->center_freq, ++ ar->chandef.center_freq1, ++@@ -2474,24 +3027,27 @@ static void ath10k_config_chan(struct at ++ /* First stop monitor interface. Some FW versions crash if there's a ++ * lone monitor interface. */ ++ if (ar->monitor_started) ++- ath10k_monitor_vdev_stop(ar); +++ ath10k_monitor_stop(ar); ++ ++ list_for_each_entry(arvif, &ar->arvifs, list) { ++ if (!arvif->is_started) ++ continue; ++ +++ if (!arvif->is_up) +++ continue; +++ ++ if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) ++ continue; ++ ++- ret = ath10k_vdev_stop(arvif); +++ ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); ++ if (ret) { ++- ath10k_warn("failed to stop vdev %d: %d\n", +++ ath10k_warn(ar, "failed to down vdev %d: %d\n", ++ arvif->vdev_id, ret); ++ continue; ++ } ++ } ++ ++- /* all vdevs are now stopped - now attempt to restart them */ +++ /* all vdevs are downed now - attempt to restart and re-up them */ ++ ++ list_for_each_entry(arvif, &ar->arvifs, list) { ++ if (!arvif->is_started) ++@@ -2500,9 +3056,9 @@ static void ath10k_config_chan(struct at ++ if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) ++ continue; ++ ++- ret = ath10k_vdev_start(arvif); +++ ret = ath10k_vdev_restart(arvif); ++ if (ret) { ++- ath10k_warn("failed to start vdev %d: %d\n", +++ ath10k_warn(ar, "failed to restart vdev %d: %d\n", ++ arvif->vdev_id, ret); ++ continue; ++ } ++@@ -2513,14 +3069,70 @@ static void ath10k_config_chan(struct at ++ ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, ++ arvif->bssid); ++ if (ret) { ++- ath10k_warn("failed to bring vdev up %d: %d\n", +++ ath10k_warn(ar, "failed to bring vdev up %d: %d\n", ++ arvif->vdev_id, ret); ++ continue; ++ } ++ } ++ ++- if (ath10k_monitor_is_enabled(ar)) ++- ath10k_monitor_vdev_start(ar, ar->monitor_vdev_id); +++ ath10k_monitor_recalc(ar); +++} +++ +++static int ath10k_mac_txpower_setup(struct ath10k *ar, int txpower) +++{ +++ int ret; +++ u32 param; +++ +++ lockdep_assert_held(&ar->conf_mutex); +++ +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac txpower %d\n", txpower); +++ +++ param = ar->wmi.pdev_param->txpower_limit2g; +++ ret = ath10k_wmi_pdev_set_param(ar, param, txpower * 2); +++ if (ret) { +++ ath10k_warn(ar, "failed to set 2g txpower %d: %d\n", +++ txpower, ret); +++ return ret; +++ } +++ +++ param = ar->wmi.pdev_param->txpower_limit5g; +++ ret = ath10k_wmi_pdev_set_param(ar, param, txpower * 2); +++ if (ret) { +++ ath10k_warn(ar, "failed to set 5g txpower %d: %d\n", +++ txpower, ret); +++ return ret; +++ } +++ +++ return 0; +++} +++ +++static int ath10k_mac_txpower_recalc(struct ath10k *ar) +++{ +++ struct ath10k_vif *arvif; +++ int ret, txpower = -1; +++ +++ lockdep_assert_held(&ar->conf_mutex); +++ +++ list_for_each_entry(arvif, &ar->arvifs, list) { +++ WARN_ON(arvif->txpower < 0); +++ +++ if (txpower == -1) +++ txpower = arvif->txpower; +++ else +++ txpower = min(txpower, arvif->txpower); +++ } +++ +++ if (WARN_ON(txpower == -1)) +++ return -EINVAL; +++ +++ ret = ath10k_mac_txpower_setup(ar, txpower); +++ if (ret) { +++ ath10k_warn(ar, "failed to setup tx power %d: %d\n", +++ txpower, ret); +++ return ret; +++ } +++ +++ return 0; ++ } ++ ++ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) ++@@ -2528,12 +3140,11 @@ static int ath10k_config(struct ieee8021 ++ struct ath10k *ar = hw->priv; ++ struct ieee80211_conf *conf = &hw->conf; ++ int ret = 0; ++- u32 param; ++ ++ mutex_lock(&ar->conf_mutex); ++ ++ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { ++- ath10k_dbg(ATH10K_DBG_MAC, +++ ath10k_dbg(ar, ATH10K_DBG_MAC, ++ "mac config channel %dMHz flags 0x%x radar %d\n", ++ conf->chandef.chan->center_freq, ++ conf->chandef.chan->flags, ++@@ -2552,48 +3163,31 @@ static int ath10k_config(struct ieee8021 ++ } ++ } ++ ++- if (changed & IEEE80211_CONF_CHANGE_POWER) { ++- ath10k_dbg(ATH10K_DBG_MAC, "mac config power %d\n", ++- hw->conf.power_level); ++- ++- param = ar->wmi.pdev_param->txpower_limit2g; ++- ret = ath10k_wmi_pdev_set_param(ar, param, ++- hw->conf.power_level * 2); ++- if (ret) ++- ath10k_warn("failed to set 2g txpower %d: %d\n", ++- hw->conf.power_level, ret); ++- ++- param = ar->wmi.pdev_param->txpower_limit5g; ++- ret = ath10k_wmi_pdev_set_param(ar, param, ++- hw->conf.power_level * 2); ++- if (ret) ++- ath10k_warn("failed to set 5g txpower %d: %d\n", ++- hw->conf.power_level, ret); ++- } ++- ++ if (changed & IEEE80211_CONF_CHANGE_PS) ++ ath10k_config_ps(ar); ++ ++ if (changed & IEEE80211_CONF_CHANGE_MONITOR) { ++- if (conf->flags & IEEE80211_CONF_MONITOR && !ar->monitor) { ++- ar->monitor = true; ++- ret = ath10k_monitor_start(ar); ++- if (ret) { ++- ath10k_warn("failed to start monitor (config): %d\n", ++- ret); ++- ar->monitor = false; ++- } ++- } else if (!(conf->flags & IEEE80211_CONF_MONITOR) && ++- ar->monitor) { ++- ar->monitor = false; ++- ath10k_monitor_stop(ar); ++- } +++ ar->monitor = conf->flags & IEEE80211_CONF_MONITOR; +++ ret = ath10k_monitor_recalc(ar); +++ if (ret) +++ ath10k_warn(ar, "failed to recalc monitor: %d\n", ret); ++ } ++ ++ mutex_unlock(&ar->conf_mutex); ++ return ret; ++ } ++ +++static u32 get_nss_from_chainmask(u16 chain_mask) +++{ +++ if ((chain_mask & 0x15) == 0x15) +++ return 4; +++ else if ((chain_mask & 0x7) == 0x7) +++ return 3; +++ else if ((chain_mask & 0x3) == 0x3) +++ return 2; +++ return 1; +++} +++ ++ /* ++ * TODO: ++ * Figure out how to handle WMI_VDEV_SUBTYPE_P2P_DEVICE, ++@@ -2619,22 +3213,26 @@ static int ath10k_add_interface(struct i ++ arvif->ar = ar; ++ arvif->vif = vif; ++ ++- INIT_WORK(&arvif->wep_key_work, ath10k_tx_wep_key_work); ++ INIT_LIST_HEAD(&arvif->list); ++ ++- bit = ffs(ar->free_vdev_map); ++- if (bit == 0) { +++ if (ar->free_vdev_map == 0) { +++ ath10k_warn(ar, "Free vdev map is empty, no more interfaces allowed.\n"); ++ ret = -EBUSY; ++ goto err; ++ } +++ bit = __ffs64(ar->free_vdev_map); ++ ++- arvif->vdev_id = bit - 1; ++- arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE; +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac create vdev %i map %llx\n", +++ bit, ar->free_vdev_map); ++ ++- if (ar->p2p) ++- arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE; +++ arvif->vdev_id = bit; +++ arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE; ++ ++ switch (vif->type) { +++ case NL80211_IFTYPE_P2P_DEVICE: +++ arvif->vdev_type = WMI_VDEV_TYPE_STA; +++ arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE; +++ break; ++ case NL80211_IFTYPE_UNSPECIFIED: ++ case NL80211_IFTYPE_STATION: ++ arvif->vdev_type = WMI_VDEV_TYPE_STA; ++@@ -2658,50 +3256,98 @@ static int ath10k_add_interface(struct i ++ break; ++ } ++ ++- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d\n", ++- arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype); +++ /* Some firmware revisions don't wait for beacon tx completion before +++ * sending another SWBA event. This could lead to hardware using old +++ * (freed) beacon data in some cases, e.g. tx credit starvation +++ * combined with missed TBTT. This is very very rare. +++ * +++ * On non-IOMMU-enabled hosts this could be a possible security issue +++ * because hw could beacon some random data on the air. On +++ * IOMMU-enabled hosts DMAR faults would occur in most cases and target +++ * device would crash. +++ * +++ * Since there are no beacon tx completions (implicit nor explicit) +++ * propagated to host the only workaround for this is to allocate a +++ * DMA-coherent buffer for a lifetime of a vif and use it for all +++ * beacon tx commands. Worst case for this approach is some beacons may +++ * become corrupted, e.g. have garbled IEs or out-of-date TIM bitmap. +++ */ +++ if (vif->type == NL80211_IFTYPE_ADHOC || +++ vif->type == NL80211_IFTYPE_AP) { +++ arvif->beacon_buf = dma_zalloc_coherent(ar->dev, +++ IEEE80211_MAX_FRAME_LEN, +++ &arvif->beacon_paddr, +++ GFP_ATOMIC); +++ if (!arvif->beacon_buf) { +++ ret = -ENOMEM; +++ ath10k_warn(ar, "failed to allocate beacon buffer: %d\n", +++ ret); +++ goto err; +++ } +++ } +++ +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d bcnmode %s\n", +++ arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype, +++ arvif->beacon_buf ? "single-buf" : "per-skb"); ++ ++ ret = ath10k_wmi_vdev_create(ar, arvif->vdev_id, arvif->vdev_type, ++ arvif->vdev_subtype, vif->addr); ++ if (ret) { ++- ath10k_warn("failed to create WMI vdev %i: %d\n", +++ ath10k_warn(ar, "failed to create WMI vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ goto err; ++ } ++ ++- ar->free_vdev_map &= ~BIT(arvif->vdev_id); +++ ar->free_vdev_map &= ~(1LL << arvif->vdev_id); ++ list_add(&arvif->list, &ar->arvifs); ++ ++- vdev_param = ar->wmi.vdev_param->def_keyid; ++- ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param, ++- arvif->def_wep_key_idx); +++ /* It makes no sense to have firmware do keepalives. mac80211 already +++ * takes care of this with idle connection polling. +++ */ +++ ret = ath10k_mac_vif_disable_keepalive(arvif); ++ if (ret) { ++- ath10k_warn("failed to set vdev %i default key id: %d\n", +++ ath10k_warn(ar, "failed to disable keepalive on vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ goto err_vdev_delete; ++ } ++ +++ arvif->def_wep_key_idx = -1; +++ ++ vdev_param = ar->wmi.vdev_param->tx_encap_type; ++ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, ++ ATH10K_HW_TXRX_NATIVE_WIFI); ++ /* 10.X firmware does not support this VDEV parameter. Do not warn */ ++ if (ret && ret != -EOPNOTSUPP) { ++- ath10k_warn("failed to set vdev %i TX encapsulation: %d\n", +++ ath10k_warn(ar, "failed to set vdev %i TX encapsulation: %d\n", ++ arvif->vdev_id, ret); ++ goto err_vdev_delete; ++ } ++ +++ if (ar->cfg_tx_chainmask) { +++ u16 nss = get_nss_from_chainmask(ar->cfg_tx_chainmask); +++ +++ vdev_param = ar->wmi.vdev_param->nss; +++ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, +++ nss); +++ if (ret) { +++ ath10k_warn(ar, "failed to set vdev %i chainmask 0x%x, nss %i: %d\n", +++ arvif->vdev_id, ar->cfg_tx_chainmask, nss, +++ ret); +++ goto err_vdev_delete; +++ } +++ } +++ ++ if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { ++ ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr); ++ if (ret) { ++- ath10k_warn("failed to create vdev %i peer for AP: %d\n", +++ ath10k_warn(ar, "failed to create vdev %i peer for AP: %d\n", ++ arvif->vdev_id, ret); ++ goto err_vdev_delete; ++ } ++ ++ ret = ath10k_mac_set_kickout(arvif); ++ if (ret) { ++- ath10k_warn("failed to set vdev %i kickout parameters: %d\n", +++ ath10k_warn(ar, "failed to set vdev %i kickout parameters: %d\n", ++ arvif->vdev_id, ret); ++ goto err_peer_delete; ++ } ++@@ -2713,27 +3359,21 @@ static int ath10k_add_interface(struct i ++ ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, ++ param, value); ++ if (ret) { ++- ath10k_warn("failed to set vdev %i RX wake policy: %d\n", +++ ath10k_warn(ar, "failed to set vdev %i RX wake policy: %d\n", ++ arvif->vdev_id, ret); ++ goto err_peer_delete; ++ } ++ ++- param = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD; ++- value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS; ++- ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, ++- param, value); +++ ret = ath10k_mac_vif_recalc_ps_wake_threshold(arvif); ++ if (ret) { ++- ath10k_warn("failed to set vdev %i TX wake thresh: %d\n", +++ ath10k_warn(ar, "failed to recalc ps wake threshold on vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ goto err_peer_delete; ++ } ++ ++- param = WMI_STA_PS_PARAM_PSPOLL_COUNT; ++- value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX; ++- ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, ++- param, value); +++ ret = ath10k_mac_vif_recalc_ps_poll_count(arvif); ++ if (ret) { ++- ath10k_warn("failed to set vdev %i PSPOLL count: %d\n", +++ ath10k_warn(ar, "failed to recalc ps poll count on vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ goto err_peer_delete; ++ } ++@@ -2741,15 +3381,22 @@ static int ath10k_add_interface(struct i ++ ++ ret = ath10k_mac_set_rts(arvif, ar->hw->wiphy->rts_threshold); ++ if (ret) { ++- ath10k_warn("failed to set rts threshold for vdev %d: %d\n", +++ ath10k_warn(ar, "failed to set rts threshold for vdev %d: %d\n", +++ arvif->vdev_id, ret); +++ goto err_peer_delete; +++ } +++ +++ ret = ath10k_mac_set_frag(arvif, ar->hw->wiphy->frag_threshold); +++ if (ret) { +++ ath10k_warn(ar, "failed to set frag threshold for vdev %d: %d\n", ++ arvif->vdev_id, ret); ++ goto err_peer_delete; ++ } ++ ++- ret = ath10k_mac_set_frag(arvif, ar->hw->wiphy->frag_threshold); +++ arvif->txpower = vif->bss_conf.txpower; +++ ret = ath10k_mac_txpower_recalc(ar); ++ if (ret) { ++- ath10k_warn("failed to set frag threshold for vdev %d: %d\n", ++- arvif->vdev_id, ret); +++ ath10k_warn(ar, "failed to recalc tx power: %d\n", ret); ++ goto err_peer_delete; ++ } ++ ++@@ -2762,10 +3409,16 @@ err_peer_delete: ++ ++ err_vdev_delete: ++ ath10k_wmi_vdev_delete(ar, arvif->vdev_id); ++- ar->free_vdev_map &= ~BIT(arvif->vdev_id); +++ ar->free_vdev_map |= 1LL << arvif->vdev_id; ++ list_del(&arvif->list); ++ ++ err: +++ if (arvif->beacon_buf) { +++ dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN, +++ arvif->beacon_buf, arvif->beacon_paddr); +++ arvif->beacon_buf = NULL; +++ } +++ ++ mutex_unlock(&ar->conf_mutex); ++ ++ return ret; ++@@ -2780,38 +3433,51 @@ static void ath10k_remove_interface(stru ++ ++ mutex_lock(&ar->conf_mutex); ++ ++- cancel_work_sync(&arvif->wep_key_work); ++- ++ spin_lock_bh(&ar->data_lock); ++- if (arvif->beacon) { ++- dma_unmap_single(arvif->ar->dev, ++- ATH10K_SKB_CB(arvif->beacon)->paddr, ++- arvif->beacon->len, DMA_TO_DEVICE); ++- dev_kfree_skb_any(arvif->beacon); ++- arvif->beacon = NULL; ++- } +++ ath10k_mac_vif_beacon_cleanup(arvif); ++ spin_unlock_bh(&ar->data_lock); ++ ++- ar->free_vdev_map |= 1 << (arvif->vdev_id); +++ ret = ath10k_spectral_vif_stop(arvif); +++ if (ret) +++ ath10k_warn(ar, "failed to stop spectral for vdev %i: %d\n", +++ arvif->vdev_id, ret); +++ +++ ar->free_vdev_map |= 1LL << arvif->vdev_id; ++ list_del(&arvif->list); ++ ++ if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { ++- ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, vif->addr); +++ ret = ath10k_wmi_peer_delete(arvif->ar, arvif->vdev_id, +++ vif->addr); ++ if (ret) ++- ath10k_warn("failed to remove peer for AP vdev %i: %d\n", +++ ath10k_warn(ar, "failed to submit AP self-peer removal on vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ ++ kfree(arvif->u.ap.noa_data); ++ } ++ ++- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %i delete (remove interface)\n", +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i delete (remove interface)\n", ++ arvif->vdev_id); ++ ++ ret = ath10k_wmi_vdev_delete(ar, arvif->vdev_id); ++ if (ret) ++- ath10k_warn("failed to delete WMI vdev %i: %d\n", +++ ath10k_warn(ar, "failed to delete WMI vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ +++ /* Some firmware revisions don't notify host about self-peer removal +++ * until after associated vdev is deleted. +++ */ +++ if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { +++ ret = ath10k_wait_for_peer_deleted(ar, arvif->vdev_id, +++ vif->addr); +++ if (ret) +++ ath10k_warn(ar, "failed to remove AP self-peer on vdev %i: %d\n", +++ arvif->vdev_id, ret); +++ +++ spin_lock_bh(&ar->data_lock); +++ ar->num_peers--; +++ spin_unlock_bh(&ar->data_lock); +++ } +++ ++ ath10k_peer_cleanup(ar, arvif->vdev_id); ++ ++ mutex_unlock(&ar->conf_mutex); ++@@ -2844,18 +3510,9 @@ static void ath10k_configure_filter(stru ++ *total_flags &= SUPPORTED_FILTERS; ++ ar->filter_flags = *total_flags; ++ ++- if (ar->filter_flags & FIF_PROMISC_IN_BSS && !ar->promisc) { ++- ar->promisc = true; ++- ret = ath10k_monitor_start(ar); ++- if (ret) { ++- ath10k_warn("failed to start monitor (promisc): %d\n", ++- ret); ++- ar->promisc = false; ++- } ++- } else if (!(ar->filter_flags & FIF_PROMISC_IN_BSS) && ar->promisc) { ++- ar->promisc = false; ++- ath10k_monitor_stop(ar); ++- } +++ ret = ath10k_monitor_recalc(ar); +++ if (ret) +++ ath10k_warn(ar, "failed to recalc montior: %d\n", ret); ++ ++ mutex_unlock(&ar->conf_mutex); ++ } ++@@ -2868,7 +3525,7 @@ static void ath10k_bss_info_changed(stru ++ struct ath10k *ar = hw->priv; ++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); ++ int ret = 0; ++- u32 vdev_param, pdev_param; +++ u32 vdev_param, pdev_param, slottime, preamble; ++ ++ mutex_lock(&ar->conf_mutex); ++ ++@@ -2880,17 +3537,17 @@ static void ath10k_bss_info_changed(stru ++ vdev_param = ar->wmi.vdev_param->beacon_interval; ++ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, ++ arvif->beacon_interval); ++- ath10k_dbg(ATH10K_DBG_MAC, +++ ath10k_dbg(ar, ATH10K_DBG_MAC, ++ "mac vdev %d beacon_interval %d\n", ++ arvif->vdev_id, arvif->beacon_interval); ++ ++ if (ret) ++- ath10k_warn("failed to set beacon interval for vdev %d: %i\n", +++ ath10k_warn(ar, "failed to set beacon interval for vdev %d: %i\n", ++ arvif->vdev_id, ret); ++ } ++ ++ if (changed & BSS_CHANGED_BEACON) { ++- ath10k_dbg(ATH10K_DBG_MAC, +++ ath10k_dbg(ar, ATH10K_DBG_MAC, ++ "vdev %d set beacon tx mode to staggered\n", ++ arvif->vdev_id); ++ ++@@ -2898,14 +3555,26 @@ static void ath10k_bss_info_changed(stru ++ ret = ath10k_wmi_pdev_set_param(ar, pdev_param, ++ WMI_BEACON_STAGGERED_MODE); ++ if (ret) ++- ath10k_warn("failed to set beacon mode for vdev %d: %i\n", +++ ath10k_warn(ar, "failed to set beacon mode for vdev %d: %i\n", +++ arvif->vdev_id, ret); +++ +++ ret = ath10k_mac_setup_bcn_tmpl(arvif); +++ if (ret) +++ ath10k_warn(ar, "failed to update beacon template: %d\n", +++ ret); +++ } +++ +++ if (changed & BSS_CHANGED_AP_PROBE_RESP) { +++ ret = ath10k_mac_setup_prb_tmpl(arvif); +++ if (ret) +++ ath10k_warn(ar, "failed to setup probe resp template on vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ } ++ ++- if (changed & BSS_CHANGED_BEACON_INFO) { +++ if (changed & (BSS_CHANGED_BEACON_INFO | BSS_CHANGED_BEACON)) { ++ arvif->dtim_period = info->dtim_period; ++ ++- ath10k_dbg(ATH10K_DBG_MAC, +++ ath10k_dbg(ar, ATH10K_DBG_MAC, ++ "mac vdev %d dtim_period %d\n", ++ arvif->vdev_id, arvif->dtim_period); ++ ++@@ -2913,7 +3582,7 @@ static void ath10k_bss_info_changed(stru ++ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, ++ arvif->dtim_period); ++ if (ret) ++- ath10k_warn("failed to set dtim period for vdev %d: %i\n", +++ ath10k_warn(ar, "failed to set dtim period for vdev %d: %i\n", ++ arvif->vdev_id, ret); ++ } ++ ++@@ -2925,91 +3594,48 @@ static void ath10k_bss_info_changed(stru ++ arvif->u.ap.hidden_ssid = info->hidden_ssid; ++ } ++ ++- if (changed & BSS_CHANGED_BSSID) { ++- if (!is_zero_ether_addr(info->bssid)) { ++- ath10k_dbg(ATH10K_DBG_MAC, ++- "mac vdev %d create peer %pM\n", ++- arvif->vdev_id, info->bssid); ++- ++- ret = ath10k_peer_create(ar, arvif->vdev_id, ++- info->bssid); ++- if (ret) ++- ath10k_warn("failed to add peer %pM for vdev %d when changing bssid: %i\n", ++- info->bssid, arvif->vdev_id, ret); ++- ++- if (vif->type == NL80211_IFTYPE_STATION) { ++- /* ++- * this is never erased as we it for crypto key ++- * clearing; this is FW requirement ++- */ ++- memcpy(arvif->bssid, info->bssid, ETH_ALEN); ++- ++- ath10k_dbg(ATH10K_DBG_MAC, ++- "mac vdev %d start %pM\n", ++- arvif->vdev_id, info->bssid); ++- ++- ret = ath10k_vdev_start(arvif); ++- if (ret) { ++- ath10k_warn("failed to start vdev %i: %d\n", ++- arvif->vdev_id, ret); ++- goto exit; ++- } ++- ++- arvif->is_started = true; ++- } ++- ++- /* ++- * Mac80211 does not keep IBSS bssid when leaving IBSS, ++- * so driver need to store it. It is needed when leaving ++- * IBSS in order to remove BSSID peer. ++- */ ++- if (vif->type == NL80211_IFTYPE_ADHOC) ++- memcpy(arvif->bssid, info->bssid, ++- ETH_ALEN); ++- } ++- } +++ if (changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid)) +++ ether_addr_copy(arvif->bssid, info->bssid); ++ ++ if (changed & BSS_CHANGED_BEACON_ENABLED) ++ ath10k_control_beaconing(arvif, info); ++ ++ if (changed & BSS_CHANGED_ERP_CTS_PROT) { ++ arvif->use_cts_prot = info->use_cts_prot; ++- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n", +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n", ++ arvif->vdev_id, info->use_cts_prot); ++ ++ ret = ath10k_recalc_rtscts_prot(arvif); ++ if (ret) ++- ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n", +++ ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n", ++ arvif->vdev_id, ret); ++ } ++ ++ if (changed & BSS_CHANGED_ERP_SLOT) { ++- u32 slottime; ++ if (info->use_short_slot) ++ slottime = WMI_VDEV_SLOT_TIME_SHORT; /* 9us */ ++ ++ else ++ slottime = WMI_VDEV_SLOT_TIME_LONG; /* 20us */ ++ ++- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d slot_time %d\n", +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d slot_time %d\n", ++ arvif->vdev_id, slottime); ++ ++ vdev_param = ar->wmi.vdev_param->slot_time; ++ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, ++ slottime); ++ if (ret) ++- ath10k_warn("failed to set erp slot for vdev %d: %i\n", +++ ath10k_warn(ar, "failed to set erp slot for vdev %d: %i\n", ++ arvif->vdev_id, ret); ++ } ++ ++ if (changed & BSS_CHANGED_ERP_PREAMBLE) { ++- u32 preamble; ++ if (info->use_short_preamble) ++ preamble = WMI_VDEV_PREAMBLE_SHORT; ++ else ++ preamble = WMI_VDEV_PREAMBLE_LONG; ++ ++- ath10k_dbg(ATH10K_DBG_MAC, +++ ath10k_dbg(ar, ATH10K_DBG_MAC, ++ "mac vdev %d preamble %dn", ++ arvif->vdev_id, preamble); ++ ++@@ -3017,16 +3643,44 @@ static void ath10k_bss_info_changed(stru ++ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, ++ preamble); ++ if (ret) ++- ath10k_warn("failed to set preamble for vdev %d: %i\n", +++ ath10k_warn(ar, "failed to set preamble for vdev %d: %i\n", ++ arvif->vdev_id, ret); ++ } ++ ++ if (changed & BSS_CHANGED_ASSOC) { ++- if (info->assoc) +++ if (info->assoc) { +++ /* Workaround: Make sure monitor vdev is not running +++ * when associating to prevent some firmware revisions +++ * (e.g. 10.1 and 10.2) from crashing. +++ */ +++ if (ar->monitor_started) +++ ath10k_monitor_stop(ar); ++ ath10k_bss_assoc(hw, vif, info); +++ ath10k_monitor_recalc(ar); +++ } else { +++ ath10k_bss_disassoc(hw, vif); +++ } +++ } +++ +++ if (changed & BSS_CHANGED_TXPOWER) { +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev_id %i txpower %d\n", +++ arvif->vdev_id, info->txpower); +++ +++ arvif->txpower = info->txpower; +++ ret = ath10k_mac_txpower_recalc(ar); +++ if (ret) +++ ath10k_warn(ar, "failed to recalc tx power: %d\n", ret); +++ } +++ +++ if (changed & BSS_CHANGED_PS) { +++ arvif->ps = vif->bss_conf.ps; +++ +++ ret = ath10k_config_ps(ar); +++ if (ret) +++ ath10k_warn(ar, "failed to setup ps on vdev %i: %d\n", +++ arvif->vdev_id, ret); ++ } ++ ++-exit: ++ mutex_unlock(&ar->conf_mutex); ++ } ++ ++@@ -3043,20 +3697,26 @@ static int ath10k_hw_scan(struct ieee802 ++ mutex_lock(&ar->conf_mutex); ++ ++ spin_lock_bh(&ar->data_lock); ++- if (ar->scan.in_progress) { ++- spin_unlock_bh(&ar->data_lock); +++ switch (ar->scan.state) { +++ case ATH10K_SCAN_IDLE: +++ reinit_completion(&ar->scan.started); +++ reinit_completion(&ar->scan.completed); +++ ar->scan.state = ATH10K_SCAN_STARTING; +++ ar->scan.is_roc = false; +++ ar->scan.vdev_id = arvif->vdev_id; +++ ret = 0; +++ break; +++ case ATH10K_SCAN_STARTING: +++ case ATH10K_SCAN_RUNNING: +++ case ATH10K_SCAN_ABORTING: ++ ret = -EBUSY; ++- goto exit; +++ break; ++ } ++- ++- reinit_completion(&ar->scan.started); ++- reinit_completion(&ar->scan.completed); ++- ar->scan.in_progress = true; ++- ar->scan.aborting = false; ++- ar->scan.is_roc = false; ++- ar->scan.vdev_id = arvif->vdev_id; ++ spin_unlock_bh(&ar->data_lock); ++ +++ if (ret) +++ goto exit; +++ ++ memset(&arg, 0, sizeof(arg)); ++ ath10k_wmi_start_scan_init(ar, &arg); ++ arg.vdev_id = arvif->vdev_id; ++@@ -3088,9 +3748,9 @@ static int ath10k_hw_scan(struct ieee802 ++ ++ ret = ath10k_start_scan(ar, &arg); ++ if (ret) { ++- ath10k_warn("failed to start hw scan: %d\n", ret); +++ ath10k_warn(ar, "failed to start hw scan: %d\n", ret); ++ spin_lock_bh(&ar->data_lock); ++- ar->scan.in_progress = false; +++ ar->scan.state = ATH10K_SCAN_IDLE; ++ spin_unlock_bh(&ar->data_lock); ++ } ++ ++@@ -3103,15 +3763,12 @@ static void ath10k_cancel_hw_scan(struct ++ struct ieee80211_vif *vif) ++ { ++ struct ath10k *ar = hw->priv; ++- int ret; ++ ++ mutex_lock(&ar->conf_mutex); ++- ret = ath10k_abort_scan(ar); ++- if (ret) { ++- ath10k_warn("failed to abort scan: %d\n", ret); ++- ieee80211_scan_completed(hw, 1 /* aborted */); ++- } +++ ath10k_scan_abort(ar); ++ mutex_unlock(&ar->conf_mutex); +++ +++ cancel_delayed_work_sync(&ar->scan.timeout); ++ } ++ ++ static void ath10k_set_key_h_def_keyidx(struct ath10k *ar, ++@@ -3148,7 +3805,7 @@ static void ath10k_set_key_h_def_keyidx( ++ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, ++ key->keyidx); ++ if (ret) ++- ath10k_warn("failed to set vdev %i group key as default key: %d\n", +++ ath10k_warn(ar, "failed to set vdev %i group key as default key: %d\n", ++ arvif->vdev_id, ret); ++ } ++ ++@@ -3162,6 +3819,7 @@ static int ath10k_set_key(struct ieee802 ++ const u8 *peer_addr; ++ bool is_wep = key->cipher == WLAN_CIPHER_SUITE_WEP40 || ++ key->cipher == WLAN_CIPHER_SUITE_WEP104; +++ bool def_idx = false; ++ int ret = 0; ++ ++ if (key->keyidx > WMI_MAX_KEY_INDEX) ++@@ -3186,7 +3844,7 @@ static int ath10k_set_key(struct ieee802 ++ ++ if (!peer) { ++ if (cmd == SET_KEY) { ++- ath10k_warn("failed to install key for non-existent peer %pM\n", +++ ath10k_warn(ar, "failed to install key for non-existent peer %pM\n", ++ peer_addr); ++ ret = -EOPNOTSUPP; ++ goto exit; ++@@ -3207,9 +3865,16 @@ static int ath10k_set_key(struct ieee802 ++ ath10k_clear_vdev_key(arvif, key); ++ } ++ ++- ret = ath10k_install_key(arvif, key, cmd, peer_addr); +++ /* set TX_USAGE flag for all the keys incase of dot1x-WEP. For +++ * static WEP, do not set this flag for the keys whose key id +++ * is greater than default key id. +++ */ +++ if (arvif->def_wep_key_idx == -1) +++ def_idx = true; +++ +++ ret = ath10k_install_key(arvif, key, cmd, peer_addr, def_idx); ++ if (ret) { ++- ath10k_warn("failed to install key for vdev %i peer %pM: %d\n", +++ ath10k_warn(ar, "failed to install key for vdev %i peer %pM: %d\n", ++ arvif->vdev_id, peer_addr, ret); ++ goto exit; ++ } ++@@ -3224,7 +3889,7 @@ static int ath10k_set_key(struct ieee802 ++ peer->keys[key->keyidx] = NULL; ++ else if (peer == NULL) ++ /* impossible unless FW goes crazy */ ++- ath10k_warn("Peer %pM disappeared!\n", peer_addr); +++ ath10k_warn(ar, "Peer %pM disappeared!\n", peer_addr); ++ spin_unlock_bh(&ar->data_lock); ++ ++ exit: ++@@ -3232,6 +3897,39 @@ exit: ++ return ret; ++ } ++ +++static void ath10k_set_default_unicast_key(struct ieee80211_hw *hw, +++ struct ieee80211_vif *vif, +++ int keyidx) +++{ +++ struct ath10k *ar = hw->priv; +++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); +++ int ret; +++ +++ mutex_lock(&arvif->ar->conf_mutex); +++ +++ if (arvif->ar->state != ATH10K_STATE_ON) +++ goto unlock; +++ +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n", +++ arvif->vdev_id, keyidx); +++ +++ ret = ath10k_wmi_vdev_set_param(arvif->ar, +++ arvif->vdev_id, +++ arvif->ar->wmi.vdev_param->def_keyid, +++ keyidx); +++ +++ if (ret) { +++ ath10k_warn(ar, "failed to update wep key index for vdev %d: %d\n", +++ arvif->vdev_id, +++ ret); +++ goto unlock; +++ } +++ +++ arvif->def_wep_key_idx = keyidx; +++unlock: +++ mutex_unlock(&arvif->ar->conf_mutex); +++} +++ ++ static void ath10k_sta_rc_update_wk(struct work_struct *wk) ++ { ++ struct ath10k *ar; ++@@ -3260,51 +3958,83 @@ static void ath10k_sta_rc_update_wk(stru ++ mutex_lock(&ar->conf_mutex); ++ ++ if (changed & IEEE80211_RC_BW_CHANGED) { ++- ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n", +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n", ++ sta->addr, bw); ++ ++ err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, ++ WMI_PEER_CHAN_WIDTH, bw); ++ if (err) ++- ath10k_warn("failed to update STA %pM peer bw %d: %d\n", +++ ath10k_warn(ar, "failed to update STA %pM peer bw %d: %d\n", ++ sta->addr, bw, err); ++ } ++ ++ if (changed & IEEE80211_RC_NSS_CHANGED) { ++- ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM nss %d\n", +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM nss %d\n", ++ sta->addr, nss); ++ ++ err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, ++ WMI_PEER_NSS, nss); ++ if (err) ++- ath10k_warn("failed to update STA %pM nss %d: %d\n", +++ ath10k_warn(ar, "failed to update STA %pM nss %d: %d\n", ++ sta->addr, nss, err); ++ } ++ ++ if (changed & IEEE80211_RC_SMPS_CHANGED) { ++- ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM smps %d\n", +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM smps %d\n", ++ sta->addr, smps); ++ ++ err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, ++ WMI_PEER_SMPS_STATE, smps); ++ if (err) ++- ath10k_warn("failed to update STA %pM smps %d: %d\n", +++ ath10k_warn(ar, "failed to update STA %pM smps %d: %d\n", ++ sta->addr, smps, err); ++ } ++ ++- if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { ++- ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM supp rates\n", +++ if (changed & IEEE80211_RC_SUPP_RATES_CHANGED || +++ changed & IEEE80211_RC_NSS_CHANGED) { +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates/nss\n", ++ sta->addr); ++ ++- err = ath10k_station_assoc(ar, arvif, sta, true); +++ err = ath10k_station_assoc(ar, arvif->vif, sta, true); ++ if (err) ++- ath10k_warn("failed to reassociate station: %pM\n", +++ ath10k_warn(ar, "failed to reassociate station: %pM\n", ++ sta->addr); ++ } ++ ++ mutex_unlock(&ar->conf_mutex); ++ } ++ +++static int ath10k_mac_inc_num_stations(struct ath10k_vif *arvif) +++{ +++ struct ath10k *ar = arvif->ar; +++ +++ lockdep_assert_held(&ar->conf_mutex); +++ +++ if (arvif->vdev_type != WMI_VDEV_TYPE_AP && +++ arvif->vdev_type != WMI_VDEV_TYPE_IBSS) +++ return 0; +++ +++ if (ar->num_stations >= ar->max_num_stations) +++ return -ENOBUFS; +++ +++ ar->num_stations++; +++ +++ return 0; +++} +++ +++static void ath10k_mac_dec_num_stations(struct ath10k_vif *arvif) +++{ +++ struct ath10k *ar = arvif->ar; +++ +++ lockdep_assert_held(&ar->conf_mutex); +++ +++ if (arvif->vdev_type != WMI_VDEV_TYPE_AP && +++ arvif->vdev_type != WMI_VDEV_TYPE_IBSS) +++ return; +++ +++ ar->num_stations--; +++} +++ ++ static int ath10k_sta_state(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta, ++@@ -3314,7 +4044,6 @@ static int ath10k_sta_state(struct ieee8 ++ struct ath10k *ar = hw->priv; ++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); ++ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; ++- int max_num_peers; ++ int ret = 0; ++ ++ if (old_state == IEEE80211_STA_NOTEXIST && ++@@ -3332,46 +4061,72 @@ static int ath10k_sta_state(struct ieee8 ++ mutex_lock(&ar->conf_mutex); ++ ++ if (old_state == IEEE80211_STA_NOTEXIST && ++- new_state == IEEE80211_STA_NONE && ++- vif->type != NL80211_IFTYPE_STATION) { +++ new_state == IEEE80211_STA_NONE) { ++ /* ++ * New station addition. ++ */ ++- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) ++- max_num_peers = TARGET_10X_NUM_PEERS_MAX - 1; ++- else ++- max_num_peers = TARGET_NUM_PEERS; +++ ath10k_dbg(ar, ATH10K_DBG_MAC, +++ "mac vdev %d peer create %pM (new sta) sta %d / %d peer %d / %d\n", +++ arvif->vdev_id, sta->addr, +++ ar->num_stations + 1, ar->max_num_stations, +++ ar->num_peers + 1, ar->max_num_peers); ++ ++- if (ar->num_peers >= max_num_peers) { ++- ath10k_warn("number of peers exceeded: peers number %d (max peers %d)\n", ++- ar->num_peers, max_num_peers); ++- ret = -ENOBUFS; +++ ret = ath10k_mac_inc_num_stations(arvif); +++ if (ret) { +++ ath10k_warn(ar, "refusing to associate station: too many connected already (%d)\n", +++ ar->max_num_stations); ++ goto exit; ++ } ++ ++- ath10k_dbg(ATH10K_DBG_MAC, ++- "mac vdev %d peer create %pM (new sta) num_peers %d\n", ++- arvif->vdev_id, sta->addr, ar->num_peers); ++- ++ ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr); ++- if (ret) ++- ath10k_warn("failed to add peer %pM for vdev %d when adding a new sta: %i\n", +++ if (ret) { +++ ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n", ++ sta->addr, arvif->vdev_id, ret); +++ ath10k_mac_dec_num_stations(arvif); +++ goto exit; +++ } +++ +++ if (vif->type == NL80211_IFTYPE_STATION) { +++ WARN_ON(arvif->is_started); +++ +++ ret = ath10k_vdev_start(arvif); +++ if (ret) { +++ ath10k_warn(ar, "failed to start vdev %i: %d\n", +++ arvif->vdev_id, ret); +++ WARN_ON(ath10k_peer_delete(ar, arvif->vdev_id, +++ sta->addr)); +++ ath10k_mac_dec_num_stations(arvif); +++ goto exit; +++ } +++ +++ arvif->is_started = true; +++ } ++ } else if ((old_state == IEEE80211_STA_NONE && ++ new_state == IEEE80211_STA_NOTEXIST)) { ++ /* ++ * Existing station deletion. ++ */ ++- ath10k_dbg(ATH10K_DBG_MAC, +++ ath10k_dbg(ar, ATH10K_DBG_MAC, ++ "mac vdev %d peer delete %pM (sta gone)\n", ++ arvif->vdev_id, sta->addr); +++ +++ if (vif->type == NL80211_IFTYPE_STATION) { +++ WARN_ON(!arvif->is_started); +++ +++ ret = ath10k_vdev_stop(arvif); +++ if (ret) +++ ath10k_warn(ar, "failed to stop vdev %i: %d\n", +++ arvif->vdev_id, ret); +++ +++ arvif->is_started = false; +++ } +++ ++ ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr); ++ if (ret) ++- ath10k_warn("failed to delete peer %pM for vdev %d: %i\n", +++ ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n", ++ sta->addr, arvif->vdev_id, ret); ++ ++- if (vif->type == NL80211_IFTYPE_STATION) ++- ath10k_bss_disassoc(hw, vif); +++ ath10k_mac_dec_num_stations(arvif); ++ } else if (old_state == IEEE80211_STA_AUTH && ++ new_state == IEEE80211_STA_ASSOC && ++ (vif->type == NL80211_IFTYPE_AP || ++@@ -3379,12 +4134,12 @@ static int ath10k_sta_state(struct ieee8 ++ /* ++ * New association. ++ */ ++- ath10k_dbg(ATH10K_DBG_MAC, "mac sta %pM associated\n", +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM associated\n", ++ sta->addr); ++ ++- ret = ath10k_station_assoc(ar, arvif, sta, false); +++ ret = ath10k_station_assoc(ar, vif, sta, false); ++ if (ret) ++- ath10k_warn("failed to associate station %pM for vdev %i: %i\n", +++ ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n", ++ sta->addr, arvif->vdev_id, ret); ++ } else if (old_state == IEEE80211_STA_ASSOC && ++ new_state == IEEE80211_STA_AUTH && ++@@ -3393,12 +4148,12 @@ static int ath10k_sta_state(struct ieee8 ++ /* ++ * Disassociation. ++ */ ++- ath10k_dbg(ATH10K_DBG_MAC, "mac sta %pM disassociated\n", +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM disassociated\n", ++ sta->addr); ++ ++- ret = ath10k_station_disassoc(ar, arvif, sta); +++ ret = ath10k_station_disassoc(ar, vif, sta); ++ if (ret) ++- ath10k_warn("failed to disassociate station: %pM vdev %i: %i\n", +++ ath10k_warn(ar, "failed to disassociate station: %pM vdev %i: %i\n", ++ sta->addr, arvif->vdev_id, ret); ++ } ++ exit: ++@@ -3407,9 +4162,11 @@ exit: ++ } ++ ++ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif, ++- u16 ac, bool enable) +++ u16 ac, bool enable) ++ { ++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); +++ struct wmi_sta_uapsd_auto_trig_arg arg = {}; +++ u32 prio = 0, acc = 0; ++ u32 value = 0; ++ int ret = 0; ++ ++@@ -3422,18 +4179,26 @@ static int ath10k_conf_tx_uapsd(struct a ++ case IEEE80211_AC_VO: ++ value = WMI_STA_PS_UAPSD_AC3_DELIVERY_EN | ++ WMI_STA_PS_UAPSD_AC3_TRIGGER_EN; +++ prio = 7; +++ acc = 3; ++ break; ++ case IEEE80211_AC_VI: ++ value = WMI_STA_PS_UAPSD_AC2_DELIVERY_EN | ++ WMI_STA_PS_UAPSD_AC2_TRIGGER_EN; +++ prio = 5; +++ acc = 2; ++ break; ++ case IEEE80211_AC_BE: ++ value = WMI_STA_PS_UAPSD_AC1_DELIVERY_EN | ++ WMI_STA_PS_UAPSD_AC1_TRIGGER_EN; +++ prio = 2; +++ acc = 1; ++ break; ++ case IEEE80211_AC_BK: ++ value = WMI_STA_PS_UAPSD_AC0_DELIVERY_EN | ++ WMI_STA_PS_UAPSD_AC0_TRIGGER_EN; +++ prio = 0; +++ acc = 0; ++ break; ++ } ++ ++@@ -3446,7 +4211,7 @@ static int ath10k_conf_tx_uapsd(struct a ++ WMI_STA_PS_PARAM_UAPSD, ++ arvif->u.sta.uapsd); ++ if (ret) { ++- ath10k_warn("failed to set uapsd params: %d\n", ret); +++ ath10k_warn(ar, "failed to set uapsd params: %d\n", ret); ++ goto exit; ++ } ++ ++@@ -3459,7 +4224,44 @@ static int ath10k_conf_tx_uapsd(struct a ++ WMI_STA_PS_PARAM_RX_WAKE_POLICY, ++ value); ++ if (ret) ++- ath10k_warn("failed to set rx wake param: %d\n", ret); +++ ath10k_warn(ar, "failed to set rx wake param: %d\n", ret); +++ +++ ret = ath10k_mac_vif_recalc_ps_wake_threshold(arvif); +++ if (ret) { +++ ath10k_warn(ar, "failed to recalc ps wake threshold on vdev %i: %d\n", +++ arvif->vdev_id, ret); +++ return ret; +++ } +++ +++ ret = ath10k_mac_vif_recalc_ps_poll_count(arvif); +++ if (ret) { +++ ath10k_warn(ar, "failed to recalc ps poll count on vdev %i: %d\n", +++ arvif->vdev_id, ret); +++ return ret; +++ } +++ +++ if (test_bit(WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, ar->wmi.svc_map) || +++ test_bit(WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, ar->wmi.svc_map)) { +++ /* Only userspace can make an educated decision when to send +++ * trigger frame. The following effectively disables u-UAPSD +++ * autotrigger in firmware (which is enabled by default +++ * provided the autotrigger service is available). +++ */ +++ +++ arg.wmm_ac = acc; +++ arg.user_priority = prio; +++ arg.service_interval = 0; +++ arg.suspend_interval = WMI_STA_UAPSD_MAX_INTERVAL_MSEC; +++ arg.delay_interval = WMI_STA_UAPSD_MAX_INTERVAL_MSEC; +++ +++ ret = ath10k_wmi_vdev_sta_uapsd(ar, arvif->vdev_id, +++ arvif->bssid, &arg, 1); +++ if (ret) { +++ ath10k_warn(ar, "failed to set uapsd auto trigger %d\n", +++ ret); +++ return ret; +++ } +++ } ++ ++ exit: ++ return ret; ++@@ -3470,6 +4272,7 @@ static int ath10k_conf_tx(struct ieee802 ++ const struct ieee80211_tx_queue_params *params) ++ { ++ struct ath10k *ar = hw->priv; +++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); ++ struct wmi_wmm_params_arg *p = NULL; ++ int ret; ++ ++@@ -3477,16 +4280,16 @@ static int ath10k_conf_tx(struct ieee802 ++ ++ switch (ac) { ++ case IEEE80211_AC_VO: ++- p = &ar->wmm_params.ac_vo; +++ p = &arvif->wmm_params.ac_vo; ++ break; ++ case IEEE80211_AC_VI: ++- p = &ar->wmm_params.ac_vi; +++ p = &arvif->wmm_params.ac_vi; ++ break; ++ case IEEE80211_AC_BE: ++- p = &ar->wmm_params.ac_be; +++ p = &arvif->wmm_params.ac_be; ++ break; ++ case IEEE80211_AC_BK: ++- p = &ar->wmm_params.ac_bk; +++ p = &arvif->wmm_params.ac_bk; ++ break; ++ } ++ ++@@ -3506,16 +4309,28 @@ static int ath10k_conf_tx(struct ieee802 ++ */ ++ p->txop = params->txop * 32; ++ ++- /* FIXME: FW accepts wmm params per hw, not per vif */ ++- ret = ath10k_wmi_pdev_set_wmm_params(ar, &ar->wmm_params); ++- if (ret) { ++- ath10k_warn("failed to set wmm params: %d\n", ret); ++- goto exit; +++ if (ar->wmi.ops->gen_vdev_wmm_conf) { +++ ret = ath10k_wmi_vdev_wmm_conf(ar, arvif->vdev_id, +++ &arvif->wmm_params); +++ if (ret) { +++ ath10k_warn(ar, "failed to set vdev wmm params on vdev %i: %d\n", +++ arvif->vdev_id, ret); +++ goto exit; +++ } +++ } else { +++ /* This won't work well with multi-interface cases but it's +++ * better than nothing. +++ */ +++ ret = ath10k_wmi_pdev_set_wmm_params(ar, &arvif->wmm_params); +++ if (ret) { +++ ath10k_warn(ar, "failed to set wmm params: %d\n", ret); +++ goto exit; +++ } ++ } ++ ++ ret = ath10k_conf_tx_uapsd(ar, vif, ac, params->uapsd); ++ if (ret) ++- ath10k_warn("failed to set sta uapsd: %d\n", ret); +++ ath10k_warn(ar, "failed to set sta uapsd: %d\n", ret); ++ ++ exit: ++ mutex_unlock(&ar->conf_mutex); ++@@ -3533,27 +4348,35 @@ static int ath10k_remain_on_channel(stru ++ struct ath10k *ar = hw->priv; ++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); ++ struct wmi_start_scan_arg arg; ++- int ret; +++ int ret = 0; ++ ++ mutex_lock(&ar->conf_mutex); ++ ++ spin_lock_bh(&ar->data_lock); ++- if (ar->scan.in_progress) { ++- spin_unlock_bh(&ar->data_lock); +++ switch (ar->scan.state) { +++ case ATH10K_SCAN_IDLE: +++ reinit_completion(&ar->scan.started); +++ reinit_completion(&ar->scan.completed); +++ reinit_completion(&ar->scan.on_channel); +++ ar->scan.state = ATH10K_SCAN_STARTING; +++ ar->scan.is_roc = true; +++ ar->scan.vdev_id = arvif->vdev_id; +++ ar->scan.roc_freq = chan->center_freq; +++ ret = 0; +++ break; +++ case ATH10K_SCAN_STARTING: +++ case ATH10K_SCAN_RUNNING: +++ case ATH10K_SCAN_ABORTING: ++ ret = -EBUSY; ++- goto exit; +++ break; ++ } ++- ++- reinit_completion(&ar->scan.started); ++- reinit_completion(&ar->scan.completed); ++- reinit_completion(&ar->scan.on_channel); ++- ar->scan.in_progress = true; ++- ar->scan.aborting = false; ++- ar->scan.is_roc = true; ++- ar->scan.vdev_id = arvif->vdev_id; ++- ar->scan.roc_freq = chan->center_freq; ++ spin_unlock_bh(&ar->data_lock); ++ +++ if (ret) +++ goto exit; +++ +++ duration = max(duration, WMI_SCAN_CHAN_MIN_TIME_MSEC); +++ ++ memset(&arg, 0, sizeof(arg)); ++ ath10k_wmi_start_scan_init(ar, &arg); ++ arg.vdev_id = arvif->vdev_id; ++@@ -3568,17 +4391,21 @@ static int ath10k_remain_on_channel(stru ++ ++ ret = ath10k_start_scan(ar, &arg); ++ if (ret) { ++- ath10k_warn("failed to start roc scan: %d\n", ret); +++ ath10k_warn(ar, "failed to start roc scan: %d\n", ret); ++ spin_lock_bh(&ar->data_lock); ++- ar->scan.in_progress = false; +++ ar->scan.state = ATH10K_SCAN_IDLE; ++ spin_unlock_bh(&ar->data_lock); ++ goto exit; ++ } ++ ++ ret = wait_for_completion_timeout(&ar->scan.on_channel, 3*HZ); ++ if (ret == 0) { ++- ath10k_warn("failed to switch to channel for roc scan\n"); ++- ath10k_abort_scan(ar); +++ ath10k_warn(ar, "failed to switch to channel for roc scan\n"); +++ +++ ret = ath10k_scan_stop(ar); +++ if (ret) +++ ath10k_warn(ar, "failed to stop scan: %d\n", ret); +++ ++ ret = -ETIMEDOUT; ++ goto exit; ++ } ++@@ -3594,9 +4421,11 @@ static int ath10k_cancel_remain_on_chann ++ struct ath10k *ar = hw->priv; ++ ++ mutex_lock(&ar->conf_mutex); ++- ath10k_abort_scan(ar); +++ ath10k_scan_abort(ar); ++ mutex_unlock(&ar->conf_mutex); ++ +++ cancel_delayed_work_sync(&ar->scan.timeout); +++ ++ return 0; ++ } ++ ++@@ -3613,35 +4442,12 @@ static int ath10k_set_rts_threshold(stru ++ ++ mutex_lock(&ar->conf_mutex); ++ list_for_each_entry(arvif, &ar->arvifs, list) { ++- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d rts threshold %d\n", ++- arvif->vdev_id, value); ++- ++- ret = ath10k_mac_set_rts(arvif, value); ++- if (ret) { ++- ath10k_warn("failed to set rts threshold for vdev %d: %d\n", ++- arvif->vdev_id, ret); ++- break; ++- } ++- } ++- mutex_unlock(&ar->conf_mutex); ++- ++- return ret; ++-} ++- ++-static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value) ++-{ ++- struct ath10k *ar = hw->priv; ++- struct ath10k_vif *arvif; ++- int ret = 0; ++- ++- mutex_lock(&ar->conf_mutex); ++- list_for_each_entry(arvif, &ar->arvifs, list) { ++- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n", +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d rts threshold %d\n", ++ arvif->vdev_id, value); ++ ++ ret = ath10k_mac_set_rts(arvif, value); ++ if (ret) { ++- ath10k_warn("failed to set fragmentation threshold for vdev %d: %d\n", +++ ath10k_warn(ar, "failed to set rts threshold for vdev %d: %d\n", ++ arvif->vdev_id, ret); ++ break; ++ } ++@@ -3675,13 +4481,15 @@ static void ath10k_flush(struct ieee8021 ++ empty = (ar->htt.num_pending_tx == 0); ++ spin_unlock_bh(&ar->htt.tx_lock); ++ ++- skip = (ar->state == ATH10K_STATE_WEDGED); +++ skip = (ar->state == ATH10K_STATE_WEDGED) || +++ test_bit(ATH10K_FLAG_CRASH_FLUSH, +++ &ar->dev_flags); ++ ++ (empty || skip); ++ }), ATH10K_FLUSH_TIMEOUT_HZ); ++ ++ if (ret <= 0 || skip) ++- ath10k_warn("failed to flush transmit queue (skip %i ar-state %i): %i\n", +++ ath10k_warn(ar, "failed to flush transmit queue (skip %i ar-state %i): %i\n", ++ skip, ar->state, ret); ++ ++ skip: ++@@ -3716,7 +4524,7 @@ static int ath10k_suspend(struct ieee802 ++ ++ ret = ath10k_hif_suspend(ar); ++ if (ret) { ++- ath10k_warn("failed to suspend hif: %d\n", ret); +++ ath10k_warn(ar, "failed to suspend hif: %d\n", ret); ++ goto resume; ++ } ++ ++@@ -3725,7 +4533,7 @@ static int ath10k_suspend(struct ieee802 ++ resume: ++ ret = ath10k_wmi_pdev_resume_target(ar); ++ if (ret) ++- ath10k_warn("failed to resume target: %d\n", ret); +++ ath10k_warn(ar, "failed to resume target: %d\n", ret); ++ ++ ret = 1; ++ exit: ++@@ -3742,14 +4550,14 @@ static int ath10k_resume(struct ieee8021 ++ ++ ret = ath10k_hif_resume(ar); ++ if (ret) { ++- ath10k_warn("failed to resume hif: %d\n", ret); +++ ath10k_warn(ar, "failed to resume hif: %d\n", ret); ++ ret = 1; ++ goto exit; ++ } ++ ++ ret = ath10k_wmi_pdev_resume_target(ar); ++ if (ret) { ++- ath10k_warn("failed to resume target: %d\n", ret); +++ ath10k_warn(ar, "failed to resume target: %d\n", ret); ++ ret = 1; ++ goto exit; ++ } ++@@ -3770,8 +4578,9 @@ static void ath10k_restart_complete(stru ++ /* If device failed to restart it will be in a different state, e.g. ++ * ATH10K_STATE_WEDGED */ ++ if (ar->state == ATH10K_STATE_RESTARTED) { ++- ath10k_info("device successfully recovered\n"); +++ ath10k_info(ar, "device successfully recovered\n"); ++ ar->state = ATH10K_STATE_ON; +++ ieee80211_wake_queues(ar->hw); ++ } ++ ++ mutex_unlock(&ar->conf_mutex); ++@@ -3807,6 +4616,9 @@ static int ath10k_get_survey(struct ieee ++ ++ survey->channel = &sband->channels[idx]; ++ +++ if (ar->rx_channel == survey->channel) +++ survey->filled |= SURVEY_INFO_IN_USE; +++ ++ exit: ++ mutex_unlock(&ar->conf_mutex); ++ return ret; ++@@ -3854,6 +4666,10 @@ ath10k_default_bitrate_mask(struct ath10 ++ u32 legacy = 0x00ff; ++ u8 ht = 0xff, i; ++ u16 vht = 0x3ff; +++ u16 nrf = ar->num_rf_chains; +++ +++ if (ar->cfg_tx_chainmask) +++ nrf = get_nss_from_chainmask(ar->cfg_tx_chainmask); ++ ++ switch (band) { ++ case IEEE80211_BAND_2GHZ: ++@@ -3869,11 +4685,11 @@ ath10k_default_bitrate_mask(struct ath10 ++ if (mask->control[band].legacy != legacy) ++ return false; ++ ++- for (i = 0; i < ar->num_rf_chains; i++) +++ for (i = 0; i < nrf; i++) ++ if (mask->control[band].ht_mcs[i] != ht) ++ return false; ++ ++- for (i = 0; i < ar->num_rf_chains; i++) +++ for (i = 0; i < nrf; i++) ++ if (mask->control[band].vht_mcs[i] != vht) ++ return false; ++ ++@@ -3897,8 +4713,8 @@ ath10k_bitrate_mask_nss(const struct cfg ++ continue; ++ else if (mask->control[band].ht_mcs[i] == 0x00) ++ break; ++- else ++- return false; +++ +++ return false; ++ } ++ ++ ht_nss = i; ++@@ -3909,8 +4725,8 @@ ath10k_bitrate_mask_nss(const struct cfg ++ continue; ++ else if (mask->control[band].vht_mcs[i] == 0x0000) ++ break; ++- else ++- return false; +++ +++ return false; ++ } ++ ++ vht_nss = i; ++@@ -3967,7 +4783,8 @@ ath10k_bitrate_mask_correct(const struct ++ } ++ ++ static bool ++-ath10k_bitrate_mask_rate(const struct cfg80211_bitrate_mask *mask, +++ath10k_bitrate_mask_rate(struct ath10k *ar, +++ const struct cfg80211_bitrate_mask *mask, ++ enum ieee80211_band band, ++ u8 *fixed_rate, ++ u8 *fixed_nss) ++@@ -4025,7 +4842,7 @@ ath10k_bitrate_mask_rate(const struct cf ++ nss <<= 4; ++ pream <<= 6; ++ ++- ath10k_dbg(ATH10K_DBG_MAC, "mac fixed rate pream 0x%02x nss 0x%02x rate 0x%02x\n", +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac fixed rate pream 0x%02x nss 0x%02x rate 0x%02x\n", ++ pream, nss, rate); ++ ++ *fixed_rate = pream | nss | rate; ++@@ -4033,7 +4850,8 @@ ath10k_bitrate_mask_rate(const struct cf ++ return true; ++ } ++ ++-static bool ath10k_get_fixed_rate_nss(const struct cfg80211_bitrate_mask *mask, +++static bool ath10k_get_fixed_rate_nss(struct ath10k *ar, +++ const struct cfg80211_bitrate_mask *mask, ++ enum ieee80211_band band, ++ u8 *fixed_rate, ++ u8 *fixed_nss) ++@@ -4043,7 +4861,7 @@ static bool ath10k_get_fixed_rate_nss(co ++ return true; ++ ++ /* Next Check single rate is set */ ++- return ath10k_bitrate_mask_rate(mask, band, fixed_rate, fixed_nss); +++ return ath10k_bitrate_mask_rate(ar, mask, band, fixed_rate, fixed_nss); ++ } ++ ++ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif, ++@@ -4063,16 +4881,16 @@ static int ath10k_set_fixed_rate_param(s ++ goto exit; ++ ++ if (fixed_rate == WMI_FIXED_RATE_NONE) ++- ath10k_dbg(ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n"); +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n"); ++ ++ if (force_sgi) ++- ath10k_dbg(ATH10K_DBG_MAC, "mac force sgi\n"); +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac force sgi\n"); ++ ++ vdev_param = ar->wmi.vdev_param->fixed_rate; ++ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, ++ vdev_param, fixed_rate); ++ if (ret) { ++- ath10k_warn("failed to set fixed rate param 0x%02x: %d\n", +++ ath10k_warn(ar, "failed to set fixed rate param 0x%02x: %d\n", ++ fixed_rate, ret); ++ ret = -EINVAL; ++ goto exit; ++@@ -4085,7 +4903,7 @@ static int ath10k_set_fixed_rate_param(s ++ vdev_param, fixed_nss); ++ ++ if (ret) { ++- ath10k_warn("failed to set fixed nss param %d: %d\n", +++ ath10k_warn(ar, "failed to set fixed nss param %d: %d\n", ++ fixed_nss, ret); ++ ret = -EINVAL; ++ goto exit; ++@@ -4098,7 +4916,7 @@ static int ath10k_set_fixed_rate_param(s ++ force_sgi); ++ ++ if (ret) { ++- ath10k_warn("failed to set sgi param %d: %d\n", +++ ath10k_warn(ar, "failed to set sgi param %d: %d\n", ++ force_sgi, ret); ++ ret = -EINVAL; ++ goto exit; ++@@ -4122,19 +4940,22 @@ static int ath10k_set_bitrate_mask(struc ++ u8 fixed_nss = ar->num_rf_chains; ++ u8 force_sgi; ++ +++ if (ar->cfg_tx_chainmask) +++ fixed_nss = get_nss_from_chainmask(ar->cfg_tx_chainmask); +++ ++ force_sgi = mask->control[band].gi; ++ if (force_sgi == NL80211_TXRATE_FORCE_LGI) ++ return -EINVAL; ++ ++ if (!ath10k_default_bitrate_mask(ar, band, mask)) { ++- if (!ath10k_get_fixed_rate_nss(mask, band, +++ if (!ath10k_get_fixed_rate_nss(ar, mask, band, ++ &fixed_rate, ++ &fixed_nss)) ++ return -EINVAL; ++ } ++ ++ if (fixed_rate == WMI_FIXED_RATE_NONE && force_sgi) { ++- ath10k_warn("failed to force SGI usage for default rate settings\n"); +++ ath10k_warn(ar, "failed to force SGI usage for default rate settings\n"); ++ return -EINVAL; ++ } ++ ++@@ -4153,7 +4974,7 @@ static void ath10k_sta_rc_update(struct ++ ++ spin_lock_bh(&ar->data_lock); ++ ++- ath10k_dbg(ATH10K_DBG_MAC, +++ ath10k_dbg(ar, ATH10K_DBG_MAC, ++ "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n", ++ sta->addr, changed, sta->bandwidth, sta->rx_nss, ++ sta->smps_mode); ++@@ -4172,7 +4993,7 @@ static void ath10k_sta_rc_update(struct ++ bw = WMI_PEER_CHWIDTH_80MHZ; ++ break; ++ case IEEE80211_STA_RX_BW_160: ++- ath10k_warn("Invalid bandwith %d in rc update for %pM\n", +++ ath10k_warn(ar, "Invalid bandwith %d in rc update for %pM\n", ++ sta->bandwidth, sta->addr); ++ bw = WMI_PEER_CHWIDTH_20MHZ; ++ break; ++@@ -4199,7 +5020,7 @@ static void ath10k_sta_rc_update(struct ++ smps = WMI_PEER_SMPS_DYNAMIC; ++ break; ++ case IEEE80211_SMPS_NUM_MODES: ++- ath10k_warn("Invalid smps %d in sta rc update for %pM\n", +++ ath10k_warn(ar, "Invalid smps %d in sta rc update for %pM\n", ++ sta->smps_mode, sta->addr); ++ smps = WMI_PEER_SMPS_PS_NONE; ++ break; ++@@ -4225,6 +5046,39 @@ static u64 ath10k_get_tsf(struct ieee802 ++ return 0; ++ } ++ +++static int ath10k_ampdu_action(struct ieee80211_hw *hw, +++ struct ieee80211_vif *vif, +++ enum ieee80211_ampdu_mlme_action action, +++ struct ieee80211_sta *sta, u16 tid, u16 *ssn, +++ u8 buf_size) +++{ +++ struct ath10k *ar = hw->priv; +++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); +++ +++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ampdu vdev_id %i sta %pM tid %hu action %d\n", +++ arvif->vdev_id, sta->addr, tid, action); +++ +++ switch (action) { +++ case IEEE80211_AMPDU_RX_START: +++ case IEEE80211_AMPDU_RX_STOP: +++ /* HTT AddBa/DelBa events trigger mac80211 Rx BA session +++ * creation/removal. Do we need to verify this? +++ */ +++ return 0; +++ case IEEE80211_AMPDU_TX_START: +++ case IEEE80211_AMPDU_TX_STOP_CONT: +++ case IEEE80211_AMPDU_TX_STOP_FLUSH: +++ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: +++ case IEEE80211_AMPDU_TX_OPERATIONAL: +++ /* Firmware offloads Tx aggregation entirely so deny mac80211 +++ * Tx aggregation requests. +++ */ +++ return -EOPNOTSUPP; +++ } +++ +++ return -EINVAL; +++} +++ ++ static const struct ieee80211_ops ath10k_ops = { ++ .tx = ath10k_tx, ++ .start = ath10k_start, ++@@ -4237,23 +5091,35 @@ static const struct ieee80211_ops ath10k ++ .hw_scan = ath10k_hw_scan, ++ .cancel_hw_scan = ath10k_cancel_hw_scan, ++ .set_key = ath10k_set_key, +++ .set_default_unicast_key = ath10k_set_default_unicast_key, ++ .sta_state = ath10k_sta_state, ++ .conf_tx = ath10k_conf_tx, ++ .remain_on_channel = ath10k_remain_on_channel, ++ .cancel_remain_on_channel = ath10k_cancel_remain_on_channel, ++ .set_rts_threshold = ath10k_set_rts_threshold, ++- .set_frag_threshold = ath10k_set_frag_threshold, ++ .flush = ath10k_flush, ++ .tx_last_beacon = ath10k_tx_last_beacon, +++ .set_antenna = ath10k_set_antenna, +++ .get_antenna = ath10k_get_antenna, ++ .restart_complete = ath10k_restart_complete, ++ .get_survey = ath10k_get_survey, ++ .set_bitrate_mask = ath10k_set_bitrate_mask, ++ .sta_rc_update = ath10k_sta_rc_update, ++ .get_tsf = ath10k_get_tsf, +++ .ampdu_action = ath10k_ampdu_action, +++ .get_et_sset_count = ath10k_debug_get_et_sset_count, +++ .get_et_stats = ath10k_debug_get_et_stats, +++ .get_et_strings = ath10k_debug_get_et_strings, +++ +++ CFG80211_TESTMODE_CMD(ath10k_tm_cmd) +++ ++ #ifdef CONFIG_PM ++ .suspend = ath10k_suspend, ++ .resume = ath10k_resume, ++ #endif +++#ifdef CPTCFG_MAC80211_DEBUGFS +++ .sta_add_debugfs = ath10k_sta_add_debugfs, +++#endif ++ }; ++ ++ #define RATETAB_ENT(_rate, _rateid, _flags) { \ ++@@ -4324,6 +5190,9 @@ static const struct ieee80211_channel at ++ CHAN5G(165, 5825, 0), ++ }; ++ +++/* Note: Be careful if you re-order these. There is code which depends on this +++ * ordering. +++ */ ++ static struct ieee80211_rate ath10k_rates[] = { ++ /* CCK */ ++ RATETAB_ENT(10, 0x82, 0), ++@@ -4346,12 +5215,12 @@ static struct ieee80211_rate ath10k_rate ++ #define ath10k_g_rates (ath10k_rates + 0) ++ #define ath10k_g_rates_size (ARRAY_SIZE(ath10k_rates)) ++ ++-struct ath10k *ath10k_mac_create(void) +++struct ath10k *ath10k_mac_create(size_t priv_size) ++ { ++ struct ieee80211_hw *hw; ++ struct ath10k *ar; ++ ++- hw = ieee80211_alloc_hw(sizeof(struct ath10k), &ath10k_ops); +++ hw = ieee80211_alloc_hw(sizeof(struct ath10k) + priv_size, &ath10k_ops); ++ if (!hw) ++ return NULL; ++ ++@@ -4377,6 +5246,10 @@ static const struct ieee80211_iface_limi ++ .types = BIT(NL80211_IFTYPE_P2P_GO) ++ }, ++ { +++ .max = 1, +++ .types = BIT(NL80211_IFTYPE_P2P_DEVICE) +++ }, +++ { ++ .max = 7, ++ .types = BIT(NL80211_IFTYPE_AP) ++ }, ++@@ -4501,7 +5374,6 @@ static struct ieee80211_sta_ht_cap ath10 ++ return ht_cap; ++ } ++ ++- ++ static void ath10k_get_arvif_iter(void *data, u8 *mac, ++ struct ieee80211_vif *vif) ++ { ++@@ -4526,7 +5398,7 @@ struct ath10k_vif *ath10k_get_arvif(stru ++ ath10k_get_arvif_iter, ++ &arvif_iter); ++ if (!arvif_iter.arvif) { ++- ath10k_warn("No VIF found for vdev %d\n", vdev_id); +++ ath10k_warn(ar, "No VIF found for vdev %d\n", vdev_id); ++ return NULL; ++ } ++ ++@@ -4564,7 +5436,8 @@ int ath10k_mac_register(struct ath10k *a ++ band->bitrates = ath10k_g_rates; ++ band->ht_cap = ht_cap; ++ ++- /* vht is not supported in 2.4 GHz */ +++ /* Enable the VHT support at 2.4 GHz */ +++ band->vht_cap = vht_cap; ++ ++ ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = band; ++ } ++@@ -4590,18 +5463,20 @@ int ath10k_mac_register(struct ath10k *a ++ ++ ar->hw->wiphy->interface_modes = ++ BIT(NL80211_IFTYPE_STATION) | ++- BIT(NL80211_IFTYPE_ADHOC) | ++ BIT(NL80211_IFTYPE_AP); ++ +++ ar->hw->wiphy->available_antennas_rx = ar->supp_rx_chainmask; +++ ar->hw->wiphy->available_antennas_tx = ar->supp_tx_chainmask; +++ ++ if (!test_bit(ATH10K_FW_FEATURE_NO_P2P, ar->fw_features)) ++ ar->hw->wiphy->interface_modes |= +++ BIT(NL80211_IFTYPE_P2P_DEVICE) | ++ BIT(NL80211_IFTYPE_P2P_CLIENT) | ++ BIT(NL80211_IFTYPE_P2P_GO); ++ ++ ar->hw->flags = IEEE80211_HW_SIGNAL_DBM | ++ IEEE80211_HW_SUPPORTS_PS | ++ IEEE80211_HW_SUPPORTS_DYNAMIC_PS | ++- IEEE80211_HW_SUPPORTS_UAPSD | ++ IEEE80211_HW_MFP_CAPABLE | ++ IEEE80211_HW_REPORTS_TX_ACK_STATUS | ++ IEEE80211_HW_HAS_RATE_CONTROL | ++@@ -4609,10 +5484,6 @@ int ath10k_mac_register(struct ath10k *a ++ IEEE80211_HW_AP_LINK_PS | ++ IEEE80211_HW_SPECTRUM_MGMT; ++ ++- /* MSDU can have HTT TX fragment pushed in front. The additional 4 ++- * bytes is used for padding/alignment if necessary. */ ++- ar->hw->extra_tx_headroom += sizeof(struct htt_data_tx_desc_frag)*2 + 4; ++- ++ if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS) ++ ar->hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS; ++ ++@@ -4629,25 +5500,52 @@ int ath10k_mac_register(struct ath10k *a ++ ++ ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL; ++ +++ if (test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map)) { +++ ar->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; +++ +++ /* Firmware delivers WPS/P2P Probe Requests frames to driver so +++ * that userspace (e.g. wpa_supplicant/hostapd) can generate +++ * correct Probe Responses. This is more of a hack advert.. +++ */ +++ ar->hw->wiphy->probe_resp_offload |= +++ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | +++ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | +++ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; +++ } +++ ++ ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; ++ ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; ++ ar->hw->wiphy->max_remain_on_channel_duration = 5000; ++ ++ ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; +++ ar->hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE; +++ ++ /* ++ * on LL hardware queues are managed entirely by the FW ++ * so we only advertise to mac we can do the queues thing ++ */ ++ ar->hw->queues = 4; ++ ++- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { ++- ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb; ++- ar->hw->wiphy->n_iface_combinations = ++- ARRAY_SIZE(ath10k_10x_if_comb); ++- } else { +++ switch (ar->wmi.op_version) { +++ case ATH10K_FW_WMI_OP_VERSION_MAIN: +++ case ATH10K_FW_WMI_OP_VERSION_TLV: ++ ar->hw->wiphy->iface_combinations = ath10k_if_comb; ++ ar->hw->wiphy->n_iface_combinations = ++ ARRAY_SIZE(ath10k_if_comb); +++ ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); +++ break; +++ case ATH10K_FW_WMI_OP_VERSION_10_1: +++ case ATH10K_FW_WMI_OP_VERSION_10_2: +++ case ATH10K_FW_WMI_OP_VERSION_10_2_4: +++ ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb; +++ ar->hw->wiphy->n_iface_combinations = +++ ARRAY_SIZE(ath10k_10x_if_comb); +++ break; +++ case ATH10K_FW_WMI_OP_VERSION_UNSET: +++ case ATH10K_FW_WMI_OP_VERSION_MAX: +++ WARN_ON(1); +++ ret = -EINVAL; +++ goto err_free; ++ } ++ ++ ar->hw->netdev_features = NETIF_F_HW_CSUM; ++@@ -4659,19 +5557,19 @@ int ath10k_mac_register(struct ath10k *a ++ NL80211_DFS_UNSET); ++ ++ if (!ar->dfs_detector) ++- ath10k_warn("failed to initialise DFS pattern detector\n"); +++ ath10k_warn(ar, "failed to initialise DFS pattern detector\n"); ++ } ++ ++ ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy, ++ ath10k_reg_notifier); ++ if (ret) { ++- ath10k_err("failed to initialise regulatory: %i\n", ret); +++ ath10k_err(ar, "failed to initialise regulatory: %i\n", ret); ++ goto err_free; ++ } ++ ++ ret = ieee80211_register_hw(ar->hw); ++ if (ret) { ++- ath10k_err("failed to register ieee80211: %d\n", ret); +++ ath10k_err(ar, "failed to register ieee80211: %d\n", ret); ++ goto err_free; ++ } ++ ++--- a/drivers/net/wireless/ath/ath10k/mac.h +++++ b/drivers/net/wireless/ath/ath10k/mac.h ++@@ -21,33 +21,41 @@ ++ #include ++ #include "core.h" ++ +++#define WEP_KEYID_SHIFT 6 +++ ++ struct ath10k_generic_iter { ++ struct ath10k *ar; ++ int ret; ++ }; ++ ++-struct ath10k *ath10k_mac_create(void); +++struct ath10k *ath10k_mac_create(size_t priv_size); ++ void ath10k_mac_destroy(struct ath10k *ar); ++ int ath10k_mac_register(struct ath10k *ar); ++ void ath10k_mac_unregister(struct ath10k *ar); ++ struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id); ++-void ath10k_reset_scan(unsigned long ptr); +++void __ath10k_scan_finish(struct ath10k *ar); +++void ath10k_scan_finish(struct ath10k *ar); +++void ath10k_scan_timeout_work(struct work_struct *work); ++ void ath10k_offchan_tx_purge(struct ath10k *ar); ++ void ath10k_offchan_tx_work(struct work_struct *work); ++ void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar); ++ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work); ++ void ath10k_halt(struct ath10k *ar); +++void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif); +++void ath10k_drain_tx(struct ath10k *ar); +++bool ath10k_mac_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr, +++ u8 keyidx); ++ ++ static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif) ++ { ++ return (struct ath10k_vif *)vif->drv_priv; ++ } ++ ++-static inline void ath10k_tx_h_seq_no(struct sk_buff *skb) +++static inline void ath10k_tx_h_seq_no(struct ieee80211_vif *vif, +++ struct sk_buff *skb) ++ { ++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; ++- struct ieee80211_vif *vif = info->control.vif; ++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); ++ ++ if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { ++--- a/drivers/net/wireless/ath/ath10k/pci.c +++++ b/drivers/net/wireless/ath/ath10k/pci.c ++@@ -44,13 +44,9 @@ enum ath10k_pci_reset_mode { ++ ATH10K_PCI_RESET_WARM_ONLY = 1, ++ }; ++ ++-static unsigned int ath10k_pci_target_ps; ++ static unsigned int ath10k_pci_irq_mode = ATH10K_PCI_IRQ_AUTO; ++ static unsigned int ath10k_pci_reset_mode = ATH10K_PCI_RESET_AUTO; ++ ++-module_param_named(target_ps, ath10k_pci_target_ps, uint, 0644); ++-MODULE_PARM_DESC(target_ps, "Enable ath10k Target (SoC) PS option"); ++- ++ module_param_named(irq_mode, ath10k_pci_irq_mode, uint, 0644); ++ MODULE_PARM_DESC(irq_mode, "0: auto, 1: legacy, 2: msi (default: 0)"); ++ ++@@ -59,21 +55,31 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1 ++ ++ /* how long wait to wait for target to initialise, in ms */ ++ #define ATH10K_PCI_TARGET_WAIT 3000 +++#define ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS 3 ++ ++ #define QCA988X_2_0_DEVICE_ID (0x003c) +++#define QCA6174_2_1_DEVICE_ID (0x003e) ++ ++-static DEFINE_PCI_DEVICE_TABLE(ath10k_pci_id_table) = { +++static const struct pci_device_id ath10k_pci_id_table[] = { ++ { PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */ +++ { PCI_VDEVICE(ATHEROS, QCA6174_2_1_DEVICE_ID) }, /* PCI-E QCA6174 V2.1 */ ++ {0} ++ }; ++ ++-static int ath10k_pci_diag_read_access(struct ath10k *ar, u32 address, ++- u32 *data); +++static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = { +++ /* QCA988X pre 2.0 chips are not supported because they need some nasty +++ * hacks. ath10k doesn't have them and these devices crash horribly +++ * because of that. +++ */ +++ { QCA988X_2_0_DEVICE_ID, QCA988X_HW_2_0_CHIP_ID_REV }, +++ { QCA6174_2_1_DEVICE_ID, QCA6174_HW_2_1_CHIP_ID_REV }, +++ { QCA6174_2_1_DEVICE_ID, QCA6174_HW_2_2_CHIP_ID_REV }, +++ { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_0_CHIP_ID_REV }, +++ { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_1_CHIP_ID_REV }, +++ { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_2_CHIP_ID_REV }, +++}; ++ ++-static int ath10k_pci_post_rx(struct ath10k *ar); ++-static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info, ++- int num); ++-static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info); +++static void ath10k_pci_buffer_cleanup(struct ath10k *ar); ++ static int ath10k_pci_cold_reset(struct ath10k *ar); ++ static int ath10k_pci_warm_reset(struct ath10k *ar); ++ static int ath10k_pci_wait_for_target_init(struct ath10k *ar); ++@@ -98,7 +104,7 @@ static const struct ce_attr host_ce_conf ++ { ++ .flags = CE_ATTR_FLAGS, ++ .src_nentries = 0, ++- .src_sz_max = 512, +++ .src_sz_max = 2048, ++ .dest_nentries = 512, ++ }, ++ ++@@ -155,79 +161,175 @@ static const struct ce_attr host_ce_conf ++ static const struct ce_pipe_config target_ce_config_wlan[] = { ++ /* CE0: host->target HTC control and raw streams */ ++ { ++- .pipenum = 0, ++- .pipedir = PIPEDIR_OUT, ++- .nentries = 32, ++- .nbytes_max = 256, ++- .flags = CE_ATTR_FLAGS, ++- .reserved = 0, +++ .pipenum = __cpu_to_le32(0), +++ .pipedir = __cpu_to_le32(PIPEDIR_OUT), +++ .nentries = __cpu_to_le32(32), +++ .nbytes_max = __cpu_to_le32(256), +++ .flags = __cpu_to_le32(CE_ATTR_FLAGS), +++ .reserved = __cpu_to_le32(0), ++ }, ++ ++ /* CE1: target->host HTT + HTC control */ ++ { ++- .pipenum = 1, ++- .pipedir = PIPEDIR_IN, ++- .nentries = 32, ++- .nbytes_max = 512, ++- .flags = CE_ATTR_FLAGS, ++- .reserved = 0, +++ .pipenum = __cpu_to_le32(1), +++ .pipedir = __cpu_to_le32(PIPEDIR_IN), +++ .nentries = __cpu_to_le32(32), +++ .nbytes_max = __cpu_to_le32(2048), +++ .flags = __cpu_to_le32(CE_ATTR_FLAGS), +++ .reserved = __cpu_to_le32(0), ++ }, ++ ++ /* CE2: target->host WMI */ ++ { ++- .pipenum = 2, ++- .pipedir = PIPEDIR_IN, ++- .nentries = 32, ++- .nbytes_max = 2048, ++- .flags = CE_ATTR_FLAGS, ++- .reserved = 0, +++ .pipenum = __cpu_to_le32(2), +++ .pipedir = __cpu_to_le32(PIPEDIR_IN), +++ .nentries = __cpu_to_le32(32), +++ .nbytes_max = __cpu_to_le32(2048), +++ .flags = __cpu_to_le32(CE_ATTR_FLAGS), +++ .reserved = __cpu_to_le32(0), ++ }, ++ ++ /* CE3: host->target WMI */ ++ { ++- .pipenum = 3, ++- .pipedir = PIPEDIR_OUT, ++- .nentries = 32, ++- .nbytes_max = 2048, ++- .flags = CE_ATTR_FLAGS, ++- .reserved = 0, +++ .pipenum = __cpu_to_le32(3), +++ .pipedir = __cpu_to_le32(PIPEDIR_OUT), +++ .nentries = __cpu_to_le32(32), +++ .nbytes_max = __cpu_to_le32(2048), +++ .flags = __cpu_to_le32(CE_ATTR_FLAGS), +++ .reserved = __cpu_to_le32(0), ++ }, ++ ++ /* CE4: host->target HTT */ ++ { ++- .pipenum = 4, ++- .pipedir = PIPEDIR_OUT, ++- .nentries = 256, ++- .nbytes_max = 256, ++- .flags = CE_ATTR_FLAGS, ++- .reserved = 0, +++ .pipenum = __cpu_to_le32(4), +++ .pipedir = __cpu_to_le32(PIPEDIR_OUT), +++ .nentries = __cpu_to_le32(256), +++ .nbytes_max = __cpu_to_le32(256), +++ .flags = __cpu_to_le32(CE_ATTR_FLAGS), +++ .reserved = __cpu_to_le32(0), ++ }, ++ ++ /* NB: 50% of src nentries, since tx has 2 frags */ ++ ++ /* CE5: unused */ ++ { ++- .pipenum = 5, ++- .pipedir = PIPEDIR_OUT, ++- .nentries = 32, ++- .nbytes_max = 2048, ++- .flags = CE_ATTR_FLAGS, ++- .reserved = 0, +++ .pipenum = __cpu_to_le32(5), +++ .pipedir = __cpu_to_le32(PIPEDIR_OUT), +++ .nentries = __cpu_to_le32(32), +++ .nbytes_max = __cpu_to_le32(2048), +++ .flags = __cpu_to_le32(CE_ATTR_FLAGS), +++ .reserved = __cpu_to_le32(0), ++ }, ++ ++ /* CE6: Reserved for target autonomous hif_memcpy */ ++ { ++- .pipenum = 6, ++- .pipedir = PIPEDIR_INOUT, ++- .nentries = 32, ++- .nbytes_max = 4096, ++- .flags = CE_ATTR_FLAGS, ++- .reserved = 0, +++ .pipenum = __cpu_to_le32(6), +++ .pipedir = __cpu_to_le32(PIPEDIR_INOUT), +++ .nentries = __cpu_to_le32(32), +++ .nbytes_max = __cpu_to_le32(4096), +++ .flags = __cpu_to_le32(CE_ATTR_FLAGS), +++ .reserved = __cpu_to_le32(0), ++ }, ++ ++ /* CE7 used only by Host */ ++ }; ++ +++/* +++ * Map from service/endpoint to Copy Engine. +++ * This table is derived from the CE_PCI TABLE, above. +++ * It is passed to the Target at startup for use by firmware. +++ */ +++static const struct service_to_pipe target_service_to_ce_map_wlan[] = { +++ { +++ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO), +++ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ +++ __cpu_to_le32(3), +++ }, +++ { +++ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO), +++ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ +++ __cpu_to_le32(2), +++ }, +++ { +++ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK), +++ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ +++ __cpu_to_le32(3), +++ }, +++ { +++ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK), +++ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ +++ __cpu_to_le32(2), +++ }, +++ { +++ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE), +++ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ +++ __cpu_to_le32(3), +++ }, +++ { +++ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE), +++ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ +++ __cpu_to_le32(2), +++ }, +++ { +++ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI), +++ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ +++ __cpu_to_le32(3), +++ }, +++ { +++ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI), +++ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ +++ __cpu_to_le32(2), +++ }, +++ { +++ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL), +++ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ +++ __cpu_to_le32(3), +++ }, +++ { +++ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL), +++ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ +++ __cpu_to_le32(2), +++ }, +++ { +++ __cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL), +++ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ +++ __cpu_to_le32(0), +++ }, +++ { +++ __cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL), +++ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ +++ __cpu_to_le32(1), +++ }, +++ { /* not used */ +++ __cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS), +++ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ +++ __cpu_to_le32(0), +++ }, +++ { /* not used */ +++ __cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS), +++ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ +++ __cpu_to_le32(1), +++ }, +++ { +++ __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG), +++ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ +++ __cpu_to_le32(4), +++ }, +++ { +++ __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG), +++ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ +++ __cpu_to_le32(1), +++ }, +++ +++ /* (Additions here) */ +++ +++ { /* must be last */ +++ __cpu_to_le32(0), +++ __cpu_to_le32(0), +++ __cpu_to_le32(0), +++ }, +++}; +++ ++ static bool ath10k_pci_irq_pending(struct ath10k *ar) ++ { ++ u32 cause; ++@@ -253,8 +355,8 @@ static void ath10k_pci_disable_and_clear ++ ++ /* IMPORTANT: this extra read transaction is required to ++ * flush the posted write buffer. */ ++- (void) ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + ++- PCIE_INTR_ENABLE_ADDRESS); +++ (void)ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + +++ PCIE_INTR_ENABLE_ADDRESS); ++ } ++ ++ static void ath10k_pci_enable_legacy_irq(struct ath10k *ar) ++@@ -265,48 +367,116 @@ static void ath10k_pci_enable_legacy_irq ++ ++ /* IMPORTANT: this extra read transaction is required to ++ * flush the posted write buffer. */ ++- (void) ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + ++- PCIE_INTR_ENABLE_ADDRESS); +++ (void)ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + +++ PCIE_INTR_ENABLE_ADDRESS); ++ } ++ ++-static irqreturn_t ath10k_pci_early_irq_handler(int irq, void *arg) +++static inline const char *ath10k_pci_get_irq_method(struct ath10k *ar) ++ { ++- struct ath10k *ar = arg; ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++ ++- if (ar_pci->num_msi_intrs == 0) { ++- if (!ath10k_pci_irq_pending(ar)) ++- return IRQ_NONE; ++- ++- ath10k_pci_disable_and_clear_legacy_irq(ar); ++- } +++ if (ar_pci->num_msi_intrs > 1) +++ return "msi-x"; ++ ++- tasklet_schedule(&ar_pci->early_irq_tasklet); +++ if (ar_pci->num_msi_intrs == 1) +++ return "msi"; ++ ++- return IRQ_HANDLED; +++ return "legacy"; ++ } ++ ++-static int ath10k_pci_request_early_irq(struct ath10k *ar) +++static int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe) ++ { +++ struct ath10k *ar = pipe->hif_ce_state; ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); +++ struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl; +++ struct sk_buff *skb; +++ dma_addr_t paddr; ++ int ret; ++ ++- /* Regardless whether MSI-X/MSI/legacy irqs have been set up the first ++- * interrupt from irq vector is triggered in all cases for FW ++- * indication/errors */ ++- ret = request_irq(ar_pci->pdev->irq, ath10k_pci_early_irq_handler, ++- IRQF_SHARED, "ath10k_pci (early)", ar); +++ lockdep_assert_held(&ar_pci->ce_lock); +++ +++ skb = dev_alloc_skb(pipe->buf_sz); +++ if (!skb) +++ return -ENOMEM; +++ +++ WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb"); +++ +++ paddr = dma_map_single(ar->dev, skb->data, +++ skb->len + skb_tailroom(skb), +++ DMA_FROM_DEVICE); +++ if (unlikely(dma_mapping_error(ar->dev, paddr))) { +++ ath10k_warn(ar, "failed to dma map pci rx buf\n"); +++ dev_kfree_skb_any(skb); +++ return -EIO; +++ } +++ +++ ATH10K_SKB_RXCB(skb)->paddr = paddr; +++ +++ ret = __ath10k_ce_rx_post_buf(ce_pipe, skb, paddr); ++ if (ret) { ++- ath10k_warn("failed to request early irq: %d\n", ret); +++ ath10k_warn(ar, "failed to post pci rx buf: %d\n", ret); +++ dma_unmap_single(ar->dev, paddr, skb->len + skb_tailroom(skb), +++ DMA_FROM_DEVICE); +++ dev_kfree_skb_any(skb); ++ return ret; ++ } ++ ++ return 0; ++ } ++ ++-static void ath10k_pci_free_early_irq(struct ath10k *ar) +++static void __ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe) +++{ +++ struct ath10k *ar = pipe->hif_ce_state; +++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); +++ struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl; +++ int ret, num; +++ +++ lockdep_assert_held(&ar_pci->ce_lock); +++ +++ if (pipe->buf_sz == 0) +++ return; +++ +++ if (!ce_pipe->dest_ring) +++ return; +++ +++ num = __ath10k_ce_rx_num_free_bufs(ce_pipe); +++ while (num--) { +++ ret = __ath10k_pci_rx_post_buf(pipe); +++ if (ret) { +++ ath10k_warn(ar, "failed to post pci rx buf: %d\n", ret); +++ mod_timer(&ar_pci->rx_post_retry, jiffies + +++ ATH10K_PCI_RX_POST_RETRY_MS); +++ break; +++ } +++ } +++} +++ +++static void ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe) +++{ +++ struct ath10k *ar = pipe->hif_ce_state; +++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); +++ +++ spin_lock_bh(&ar_pci->ce_lock); +++ __ath10k_pci_rx_post_pipe(pipe); +++ spin_unlock_bh(&ar_pci->ce_lock); +++} +++ +++static void ath10k_pci_rx_post(struct ath10k *ar) +++{ +++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); +++ int i; +++ +++ spin_lock_bh(&ar_pci->ce_lock); +++ for (i = 0; i < CE_COUNT; i++) +++ __ath10k_pci_rx_post_pipe(&ar_pci->pipe_info[i]); +++ spin_unlock_bh(&ar_pci->ce_lock); +++} +++ +++static void ath10k_pci_rx_replenish_retry(unsigned long ptr) ++ { ++- free_irq(ath10k_pci_priv(ar)->pdev->irq, ar); +++ struct ath10k *ar = (void *)ptr; +++ +++ ath10k_pci_rx_post(ar); ++ } ++ ++ /* ++@@ -330,24 +500,7 @@ static int ath10k_pci_diag_read_mem(stru ++ void *data_buf = NULL; ++ int i; ++ ++- /* ++- * This code cannot handle reads to non-memory space. Redirect to the ++- * register read fn but preserve the multi word read capability of ++- * this fn ++- */ ++- if (address < DRAM_BASE_ADDRESS) { ++- if (!IS_ALIGNED(address, 4) || ++- !IS_ALIGNED((unsigned long)data, 4)) ++- return -EIO; ++- ++- while ((nbytes >= 4) && ((ret = ath10k_pci_diag_read_access( ++- ar, address, (u32 *)data)) == 0)) { ++- nbytes -= sizeof(u32); ++- address += sizeof(u32); ++- data += sizeof(u32); ++- } ++- return ret; ++- } +++ spin_lock_bh(&ar_pci->ce_lock); ++ ++ ce_diag = ar_pci->ce_diag; ++ ++@@ -375,7 +528,7 @@ static int ath10k_pci_diag_read_mem(stru ++ nbytes = min_t(unsigned int, remaining_bytes, ++ DIAG_TRANSFER_LIMIT); ++ ++- ret = ath10k_ce_recv_buf_enqueue(ce_diag, NULL, ce_data); +++ ret = __ath10k_ce_rx_post_buf(ce_diag, NULL, ce_data); ++ if (ret != 0) ++ goto done; ++ ++@@ -388,20 +541,18 @@ static int ath10k_pci_diag_read_mem(stru ++ * convert it from Target CPU virtual address space ++ * to CE address space ++ */ ++- ath10k_pci_wake(ar); ++ address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem, ++ address); ++- ath10k_pci_sleep(ar); ++ ++- ret = ath10k_ce_send(ce_diag, NULL, (u32)address, nbytes, 0, ++- 0); +++ ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)address, nbytes, 0, +++ 0); ++ if (ret) ++ goto done; ++ ++ i = 0; ++- while (ath10k_ce_completed_send_next(ce_diag, NULL, &buf, ++- &completed_nbytes, ++- &id) != 0) { +++ while (ath10k_ce_completed_send_next_nolock(ce_diag, NULL, &buf, +++ &completed_nbytes, +++ &id) != 0) { ++ mdelay(1); ++ if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) { ++ ret = -EBUSY; ++@@ -414,15 +565,15 @@ static int ath10k_pci_diag_read_mem(stru ++ goto done; ++ } ++ ++- if (buf != (u32) address) { +++ if (buf != (u32)address) { ++ ret = -EIO; ++ goto done; ++ } ++ ++ i = 0; ++- while (ath10k_ce_completed_recv_next(ce_diag, NULL, &buf, ++- &completed_nbytes, ++- &id, &flags) != 0) { +++ while (ath10k_ce_completed_recv_next_nolock(ce_diag, NULL, &buf, +++ &completed_nbytes, +++ &id, &flags) != 0) { ++ mdelay(1); ++ ++ if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) { ++@@ -447,38 +598,60 @@ static int ath10k_pci_diag_read_mem(stru ++ } ++ ++ done: ++- if (ret == 0) { ++- /* Copy data from allocated DMA buf to caller's buf */ ++- WARN_ON_ONCE(orig_nbytes & 3); ++- for (i = 0; i < orig_nbytes / sizeof(__le32); i++) { ++- ((u32 *)data)[i] = ++- __le32_to_cpu(((__le32 *)data_buf)[i]); ++- } ++- } else ++- ath10k_warn("failed to read diag value at 0x%x: %d\n", +++ if (ret == 0) +++ memcpy(data, data_buf, orig_nbytes); +++ else +++ ath10k_warn(ar, "failed to read diag value at 0x%x: %d\n", ++ address, ret); ++ ++ if (data_buf) ++ dma_free_coherent(ar->dev, orig_nbytes, data_buf, ++ ce_data_base); ++ +++ spin_unlock_bh(&ar_pci->ce_lock); +++ ++ return ret; ++ } ++ ++-/* Read 4-byte aligned data from Target memory or register */ ++-static int ath10k_pci_diag_read_access(struct ath10k *ar, u32 address, ++- u32 *data) ++-{ ++- /* Assume range doesn't cross this boundary */ ++- if (address >= DRAM_BASE_ADDRESS) ++- return ath10k_pci_diag_read_mem(ar, address, data, sizeof(u32)); +++static int ath10k_pci_diag_read32(struct ath10k *ar, u32 address, u32 *value) +++{ +++ __le32 val = 0; +++ int ret; +++ +++ ret = ath10k_pci_diag_read_mem(ar, address, &val, sizeof(val)); +++ *value = __le32_to_cpu(val); +++ +++ return ret; +++} +++ +++static int __ath10k_pci_diag_read_hi(struct ath10k *ar, void *dest, +++ u32 src, u32 len) +++{ +++ u32 host_addr, addr; +++ int ret; +++ +++ host_addr = host_interest_item_address(src); +++ +++ ret = ath10k_pci_diag_read32(ar, host_addr, &addr); +++ if (ret != 0) { +++ ath10k_warn(ar, "failed to get memcpy hi address for firmware address %d: %d\n", +++ src, ret); +++ return ret; +++ } +++ +++ ret = ath10k_pci_diag_read_mem(ar, addr, dest, len); +++ if (ret != 0) { +++ ath10k_warn(ar, "failed to memcpy firmware memory from %d (%d B): %d\n", +++ addr, len, ret); +++ return ret; +++ } ++ ++- ath10k_pci_wake(ar); ++- *data = ath10k_pci_read32(ar, address); ++- ath10k_pci_sleep(ar); ++ return 0; ++ } ++ +++#define ath10k_pci_diag_read_hi(ar, dest, src, len) \ +++ __ath10k_pci_diag_read_hi(ar, dest, HI_ITEM(src), len) +++ ++ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, ++ const void *data, int nbytes) ++ { ++@@ -494,6 +667,8 @@ static int ath10k_pci_diag_write_mem(str ++ dma_addr_t ce_data_base = 0; ++ int i; ++ +++ spin_lock_bh(&ar_pci->ce_lock); +++ ++ ce_diag = ar_pci->ce_diag; ++ ++ /* ++@@ -513,9 +688,7 @@ static int ath10k_pci_diag_write_mem(str ++ } ++ ++ /* Copy caller's data to allocated DMA buf */ ++- WARN_ON_ONCE(orig_nbytes & 3); ++- for (i = 0; i < orig_nbytes / sizeof(__le32); i++) ++- ((__le32 *)data_buf)[i] = __cpu_to_le32(((u32 *)data)[i]); +++ memcpy(data_buf, data, orig_nbytes); ++ ++ /* ++ * The address supplied by the caller is in the ++@@ -527,9 +700,7 @@ static int ath10k_pci_diag_write_mem(str ++ * to ++ * CE address space ++ */ ++- ath10k_pci_wake(ar); ++ address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem, address); ++- ath10k_pci_sleep(ar); ++ ++ remaining_bytes = orig_nbytes; ++ ce_data = ce_data_base; ++@@ -538,7 +709,7 @@ static int ath10k_pci_diag_write_mem(str ++ nbytes = min_t(int, remaining_bytes, DIAG_TRANSFER_LIMIT); ++ ++ /* Set up to receive directly into Target(!) address */ ++- ret = ath10k_ce_recv_buf_enqueue(ce_diag, NULL, address); +++ ret = __ath10k_ce_rx_post_buf(ce_diag, NULL, address); ++ if (ret != 0) ++ goto done; ++ ++@@ -546,15 +717,15 @@ static int ath10k_pci_diag_write_mem(str ++ * Request CE to send caller-supplied data that ++ * was copied to bounce buffer to Target(!) address. ++ */ ++- ret = ath10k_ce_send(ce_diag, NULL, (u32) ce_data, ++- nbytes, 0, 0); +++ ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)ce_data, +++ nbytes, 0, 0); ++ if (ret != 0) ++ goto done; ++ ++ i = 0; ++- while (ath10k_ce_completed_send_next(ce_diag, NULL, &buf, ++- &completed_nbytes, ++- &id) != 0) { +++ while (ath10k_ce_completed_send_next_nolock(ce_diag, NULL, &buf, +++ &completed_nbytes, +++ &id) != 0) { ++ mdelay(1); ++ ++ if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) { ++@@ -574,9 +745,9 @@ static int ath10k_pci_diag_write_mem(str ++ } ++ ++ i = 0; ++- while (ath10k_ce_completed_recv_next(ce_diag, NULL, &buf, ++- &completed_nbytes, ++- &id, &flags) != 0) { +++ while (ath10k_ce_completed_recv_next_nolock(ce_diag, NULL, &buf, +++ &completed_nbytes, +++ &id, &flags) != 0) { ++ mdelay(1); ++ ++ if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) { ++@@ -607,66 +778,36 @@ done: ++ } ++ ++ if (ret != 0) ++- ath10k_warn("failed to write diag value at 0x%x: %d\n", +++ ath10k_warn(ar, "failed to write diag value at 0x%x: %d\n", ++ address, ret); ++ +++ spin_unlock_bh(&ar_pci->ce_lock); +++ ++ return ret; ++ } ++ ++-/* Write 4B data to Target memory or register */ ++-static int ath10k_pci_diag_write_access(struct ath10k *ar, u32 address, ++- u32 data) ++-{ ++- /* Assume range doesn't cross this boundary */ ++- if (address >= DRAM_BASE_ADDRESS) ++- return ath10k_pci_diag_write_mem(ar, address, &data, ++- sizeof(u32)); +++static int ath10k_pci_diag_write32(struct ath10k *ar, u32 address, u32 value) +++{ +++ __le32 val = __cpu_to_le32(value); ++ ++- ath10k_pci_wake(ar); ++- ath10k_pci_write32(ar, address, data); ++- ath10k_pci_sleep(ar); ++- return 0; +++ return ath10k_pci_diag_write_mem(ar, address, &val, sizeof(val)); ++ } ++ ++-static bool ath10k_pci_target_is_awake(struct ath10k *ar) +++static bool ath10k_pci_is_awake(struct ath10k *ar) ++ { ++- void __iomem *mem = ath10k_pci_priv(ar)->mem; ++- u32 val; ++- val = ioread32(mem + PCIE_LOCAL_BASE_ADDRESS + ++- RTC_STATE_ADDRESS); ++- return (RTC_STATE_V_GET(val) == RTC_STATE_V_ON); +++ u32 val = ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS); +++ +++ return RTC_STATE_V_GET(val) == RTC_STATE_V_ON; ++ } ++ ++-int ath10k_do_pci_wake(struct ath10k *ar) +++static int ath10k_pci_wake_wait(struct ath10k *ar) ++ { ++- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++- void __iomem *pci_addr = ar_pci->mem; ++ int tot_delay = 0; ++ int curr_delay = 5; ++ ++- if (atomic_read(&ar_pci->keep_awake_count) == 0) { ++- /* Force AWAKE */ ++- iowrite32(PCIE_SOC_WAKE_V_MASK, ++- pci_addr + PCIE_LOCAL_BASE_ADDRESS + ++- PCIE_SOC_WAKE_ADDRESS); ++- } ++- atomic_inc(&ar_pci->keep_awake_count); ++- ++- if (ar_pci->verified_awake) ++- return 0; ++- ++- for (;;) { ++- if (ath10k_pci_target_is_awake(ar)) { ++- ar_pci->verified_awake = true; +++ while (tot_delay < PCIE_WAKE_TIMEOUT) { +++ if (ath10k_pci_is_awake(ar)) ++ return 0; ++- } ++- ++- if (tot_delay > PCIE_WAKE_TIMEOUT) { ++- ath10k_warn("target took longer %d us to wake up (awake count %d)\n", ++- PCIE_WAKE_TIMEOUT, ++- atomic_read(&ar_pci->keep_awake_count)); ++- return -ETIMEDOUT; ++- } ++ ++ udelay(curr_delay); ++ tot_delay += curr_delay; ++@@ -674,20 +815,21 @@ int ath10k_do_pci_wake(struct ath10k *ar ++ if (curr_delay < 50) ++ curr_delay += 5; ++ } +++ +++ return -ETIMEDOUT; ++ } ++ ++-void ath10k_do_pci_sleep(struct ath10k *ar) +++static int ath10k_pci_wake(struct ath10k *ar) ++ { ++- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++- void __iomem *pci_addr = ar_pci->mem; +++ ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS, +++ PCIE_SOC_WAKE_V_MASK); +++ return ath10k_pci_wake_wait(ar); +++} ++ ++- if (atomic_dec_and_test(&ar_pci->keep_awake_count)) { ++- /* Allow sleep */ ++- ar_pci->verified_awake = false; ++- iowrite32(PCIE_SOC_WAKE_RESET, ++- pci_addr + PCIE_LOCAL_BASE_ADDRESS + ++- PCIE_SOC_WAKE_ADDRESS); ++- } +++static void ath10k_pci_sleep(struct ath10k *ar) +++{ +++ ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS, +++ PCIE_SOC_WAKE_RESET); ++ } ++ ++ /* Called by lower (CE) layer when a send to Target completes. */ ++@@ -696,20 +838,24 @@ static void ath10k_pci_ce_send_done(stru ++ struct ath10k *ar = ce_state->ar; ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++ struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current; ++- void *transfer_context; +++ struct sk_buff_head list; +++ struct sk_buff *skb; ++ u32 ce_data; ++ unsigned int nbytes; ++ unsigned int transfer_id; ++ ++- while (ath10k_ce_completed_send_next(ce_state, &transfer_context, ++- &ce_data, &nbytes, ++- &transfer_id) == 0) { +++ __skb_queue_head_init(&list); +++ while (ath10k_ce_completed_send_next(ce_state, (void **)&skb, &ce_data, +++ &nbytes, &transfer_id) == 0) { ++ /* no need to call tx completion for NULL pointers */ ++- if (transfer_context == NULL) +++ if (skb == NULL) ++ continue; ++ ++- cb->tx_completion(ar, transfer_context, transfer_id); +++ __skb_queue_tail(&list, skb); ++ } +++ +++ while ((skb = __skb_dequeue(&list))) +++ cb->tx_completion(ar, skb); ++ } ++ ++ /* Called by lower (CE) layer when data is received from the Target. */ ++@@ -720,38 +866,43 @@ static void ath10k_pci_ce_recv_data(stru ++ struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id]; ++ struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current; ++ struct sk_buff *skb; +++ struct sk_buff_head list; ++ void *transfer_context; ++ u32 ce_data; ++ unsigned int nbytes, max_nbytes; ++ unsigned int transfer_id; ++ unsigned int flags; ++- int err; ++ +++ __skb_queue_head_init(&list); ++ while (ath10k_ce_completed_recv_next(ce_state, &transfer_context, ++ &ce_data, &nbytes, &transfer_id, ++ &flags) == 0) { ++- err = ath10k_pci_post_rx_pipe(pipe_info, 1); ++- if (unlikely(err)) { ++- /* FIXME: retry */ ++- ath10k_warn("failed to replenish CE rx ring %d: %d\n", ++- pipe_info->pipe_num, err); ++- } ++- ++ skb = transfer_context; ++ max_nbytes = skb->len + skb_tailroom(skb); ++- dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr, +++ dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr, ++ max_nbytes, DMA_FROM_DEVICE); ++ ++ if (unlikely(max_nbytes < nbytes)) { ++- ath10k_warn("rxed more than expected (nbytes %d, max %d)", +++ ath10k_warn(ar, "rxed more than expected (nbytes %d, max %d)", ++ nbytes, max_nbytes); ++ dev_kfree_skb_any(skb); ++ continue; ++ } ++ ++ skb_put(skb, nbytes); ++- cb->rx_completion(ar, skb, pipe_info->pipe_num); +++ __skb_queue_tail(&list, skb); +++ } +++ +++ while ((skb = __skb_dequeue(&list))) { +++ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci rx ce pipe %d len %d\n", +++ ce_state->id, skb->len); +++ ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci rx: ", +++ skb->data, skb->len); +++ +++ cb->rx_completion(ar, skb); ++ } +++ +++ ath10k_pci_rx_post_pipe(pipe_info); ++ } ++ ++ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, ++@@ -761,24 +912,28 @@ static int ath10k_pci_hif_tx_sg(struct a ++ struct ath10k_pci_pipe *pci_pipe = &ar_pci->pipe_info[pipe_id]; ++ struct ath10k_ce_pipe *ce_pipe = pci_pipe->ce_hdl; ++ struct ath10k_ce_ring *src_ring = ce_pipe->src_ring; ++- unsigned int nentries_mask = src_ring->nentries_mask; ++- unsigned int sw_index = src_ring->sw_index; ++- unsigned int write_index = src_ring->write_index; ++- int err, i; +++ unsigned int nentries_mask; +++ unsigned int sw_index; +++ unsigned int write_index; +++ int err, i = 0; ++ ++ spin_lock_bh(&ar_pci->ce_lock); ++ +++ nentries_mask = src_ring->nentries_mask; +++ sw_index = src_ring->sw_index; +++ write_index = src_ring->write_index; +++ ++ if (unlikely(CE_RING_DELTA(nentries_mask, ++ write_index, sw_index - 1) < n_items)) { ++ err = -ENOBUFS; ++- goto unlock; +++ goto err; ++ } ++ ++ for (i = 0; i < n_items - 1; i++) { ++- ath10k_dbg(ATH10K_DBG_PCI, +++ ath10k_dbg(ar, ATH10K_DBG_PCI, ++ "pci tx item %d paddr 0x%08x len %d n_items %d\n", ++ i, items[i].paddr, items[i].len, n_items); ++- ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, "item data: ", +++ ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci tx data: ", ++ items[i].vaddr, items[i].len); ++ ++ err = ath10k_ce_send_nolock(ce_pipe, ++@@ -788,15 +943,15 @@ static int ath10k_pci_hif_tx_sg(struct a ++ items[i].transfer_id, ++ CE_SEND_FLAG_GATHER); ++ if (err) ++- goto unlock; +++ goto err; ++ } ++ ++ /* `i` is equal to `n_items -1` after for() */ ++ ++- ath10k_dbg(ATH10K_DBG_PCI, +++ ath10k_dbg(ar, ATH10K_DBG_PCI, ++ "pci tx item %d paddr 0x%08x len %d n_items %d\n", ++ i, items[i].paddr, items[i].len, n_items); ++- ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, "item data: ", +++ ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci tx data: ", ++ items[i].vaddr, items[i].len); ++ ++ err = ath10k_ce_send_nolock(ce_pipe, ++@@ -806,64 +961,89 @@ static int ath10k_pci_hif_tx_sg(struct a ++ items[i].transfer_id, ++ 0); ++ if (err) ++- goto unlock; +++ goto err; +++ +++ spin_unlock_bh(&ar_pci->ce_lock); +++ return 0; +++ +++err: +++ for (; i > 0; i--) +++ __ath10k_ce_send_revert(ce_pipe); ++ ++- err = 0; ++-unlock: ++ spin_unlock_bh(&ar_pci->ce_lock); ++ return err; ++ } ++ +++static int ath10k_pci_hif_diag_read(struct ath10k *ar, u32 address, void *buf, +++ size_t buf_len) +++{ +++ return ath10k_pci_diag_read_mem(ar, address, buf, buf_len); +++} +++ ++ static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe) ++ { ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++ ++- ath10k_dbg(ATH10K_DBG_PCI, "pci hif get free queue number\n"); +++ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get free queue number\n"); ++ ++ return ath10k_ce_num_free_src_entries(ar_pci->pipe_info[pipe].ce_hdl); ++ } ++ ++-static void ath10k_pci_hif_dump_area(struct ath10k *ar) +++static void ath10k_pci_dump_registers(struct ath10k *ar, +++ struct ath10k_fw_crash_data *crash_data) ++ { ++- u32 reg_dump_area = 0; ++- u32 reg_dump_values[REG_DUMP_COUNT_QCA988X] = {}; ++- u32 host_addr; ++- int ret; ++- u32 i; ++- ++- ath10k_err("firmware crashed!\n"); ++- ath10k_err("hardware name %s version 0x%x\n", ++- ar->hw_params.name, ar->target_version); ++- ath10k_err("firmware version: %s\n", ar->hw->wiphy->fw_version); ++- ++- host_addr = host_interest_item_address(HI_ITEM(hi_failure_state)); ++- ret = ath10k_pci_diag_read_mem(ar, host_addr, ++- ®_dump_area, sizeof(u32)); ++- if (ret) { ++- ath10k_err("failed to read FW dump area address: %d\n", ret); ++- return; ++- } +++ __le32 reg_dump_values[REG_DUMP_COUNT_QCA988X] = {}; +++ int i, ret; ++ ++- ath10k_err("target register Dump Location: 0x%08X\n", reg_dump_area); +++ lockdep_assert_held(&ar->data_lock); ++ ++- ret = ath10k_pci_diag_read_mem(ar, reg_dump_area, ++- ®_dump_values[0], ++- REG_DUMP_COUNT_QCA988X * sizeof(u32)); ++- if (ret != 0) { ++- ath10k_err("failed to read FW dump area: %d\n", ret); +++ ret = ath10k_pci_diag_read_hi(ar, ®_dump_values[0], +++ hi_failure_state, +++ REG_DUMP_COUNT_QCA988X * sizeof(__le32)); +++ if (ret) { +++ ath10k_err(ar, "failed to read firmware dump area: %d\n", ret); ++ return; ++ } ++ ++ BUILD_BUG_ON(REG_DUMP_COUNT_QCA988X % 4); ++ ++- ath10k_err("target Register Dump\n"); +++ ath10k_err(ar, "firmware register dump:\n"); ++ for (i = 0; i < REG_DUMP_COUNT_QCA988X; i += 4) ++- ath10k_err("[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X\n", +++ ath10k_err(ar, "[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X\n", ++ i, ++- reg_dump_values[i], ++- reg_dump_values[i + 1], ++- reg_dump_values[i + 2], ++- reg_dump_values[i + 3]); +++ __le32_to_cpu(reg_dump_values[i]), +++ __le32_to_cpu(reg_dump_values[i + 1]), +++ __le32_to_cpu(reg_dump_values[i + 2]), +++ __le32_to_cpu(reg_dump_values[i + 3])); +++ +++ if (!crash_data) +++ return; +++ +++ for (i = 0; i < REG_DUMP_COUNT_QCA988X; i++) +++ crash_data->registers[i] = reg_dump_values[i]; +++} +++ +++static void ath10k_pci_fw_crashed_dump(struct ath10k *ar) +++{ +++ struct ath10k_fw_crash_data *crash_data; +++ char uuid[50]; +++ +++ spin_lock_bh(&ar->data_lock); +++ +++ ar->stats.fw_crash_counter++; +++ +++ crash_data = ath10k_debug_get_new_fw_crash_data(ar); +++ +++ if (crash_data) +++ scnprintf(uuid, sizeof(uuid), "%pUl", &crash_data->uuid); +++ else +++ scnprintf(uuid, sizeof(uuid), "n/a"); +++ +++ ath10k_err(ar, "firmware crashed! (uuid %s)\n", uuid); +++ ath10k_print_driver_info(ar); +++ ath10k_pci_dump_registers(ar, crash_data); +++ +++ spin_unlock_bh(&ar->data_lock); ++ ++ queue_work(ar->workqueue, &ar->restart_work); ++ } ++@@ -871,7 +1051,7 @@ static void ath10k_pci_hif_dump_area(str ++ static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe, ++ int force) ++ { ++- ath10k_dbg(ATH10K_DBG_PCI, "pci hif send complete check\n"); +++ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif send complete check\n"); ++ ++ if (!force) { ++ int resources; ++@@ -899,43 +1079,12 @@ static void ath10k_pci_hif_set_callbacks ++ { ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++ ++- ath10k_dbg(ATH10K_DBG_PCI, "pci hif set callbacks\n"); +++ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif set callbacks\n"); ++ ++ memcpy(&ar_pci->msg_callbacks_current, callbacks, ++ sizeof(ar_pci->msg_callbacks_current)); ++ } ++ ++-static int ath10k_pci_setup_ce_irq(struct ath10k *ar) ++-{ ++- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++- const struct ce_attr *attr; ++- struct ath10k_pci_pipe *pipe_info; ++- int pipe_num, disable_interrupts; ++- ++- for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { ++- pipe_info = &ar_pci->pipe_info[pipe_num]; ++- ++- /* Handle Diagnostic CE specially */ ++- if (pipe_info->ce_hdl == ar_pci->ce_diag) ++- continue; ++- ++- attr = &host_ce_config_wlan[pipe_num]; ++- ++- if (attr->src_nentries) { ++- disable_interrupts = attr->flags & CE_ATTR_DIS_INTR; ++- ath10k_ce_send_cb_register(pipe_info->ce_hdl, ++- ath10k_pci_ce_send_done, ++- disable_interrupts); ++- } ++- ++- if (attr->dest_nentries) ++- ath10k_ce_recv_cb_register(pipe_info->ce_hdl, ++- ath10k_pci_ce_recv_data); ++- } ++- ++- return 0; ++-} ++- ++ static void ath10k_pci_kill_tasklet(struct ath10k *ar) ++ { ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++@@ -943,82 +1092,72 @@ static void ath10k_pci_kill_tasklet(stru ++ ++ tasklet_kill(&ar_pci->intr_tq); ++ tasklet_kill(&ar_pci->msi_fw_err); ++- tasklet_kill(&ar_pci->early_irq_tasklet); ++ ++ for (i = 0; i < CE_COUNT; i++) ++ tasklet_kill(&ar_pci->pipe_info[i].intr); +++ +++ del_timer_sync(&ar_pci->rx_post_retry); ++ } ++ ++-/* TODO - temporary mapping while we have too few CE's */ ++ static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, ++ u16 service_id, u8 *ul_pipe, ++ u8 *dl_pipe, int *ul_is_polled, ++ int *dl_is_polled) ++ { ++- int ret = 0; +++ const struct service_to_pipe *entry; +++ bool ul_set = false, dl_set = false; +++ int i; ++ ++- ath10k_dbg(ATH10K_DBG_PCI, "pci hif map service\n"); +++ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif map service\n"); ++ ++ /* polling for received messages not supported */ ++ *dl_is_polled = 0; ++ ++- switch (service_id) { ++- case ATH10K_HTC_SVC_ID_HTT_DATA_MSG: ++- /* ++- * Host->target HTT gets its own pipe, so it can be polled ++- * while other pipes are interrupt driven. ++- */ ++- *ul_pipe = 4; ++- /* ++- * Use the same target->host pipe for HTC ctrl, HTC raw ++- * streams, and HTT. ++- */ ++- *dl_pipe = 1; ++- break; +++ for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) { +++ entry = &target_service_to_ce_map_wlan[i]; ++ ++- case ATH10K_HTC_SVC_ID_RSVD_CTRL: ++- case ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS: ++- /* ++- * Note: HTC_RAW_STREAMS_SVC is currently unused, and ++- * HTC_CTRL_RSVD_SVC could share the same pipe as the ++- * WMI services. So, if another CE is needed, change ++- * this to *ul_pipe = 3, which frees up CE 0. ++- */ ++- /* *ul_pipe = 3; */ ++- *ul_pipe = 0; ++- *dl_pipe = 1; ++- break; +++ if (__le32_to_cpu(entry->service_id) != service_id) +++ continue; ++ ++- case ATH10K_HTC_SVC_ID_WMI_DATA_BK: ++- case ATH10K_HTC_SVC_ID_WMI_DATA_BE: ++- case ATH10K_HTC_SVC_ID_WMI_DATA_VI: ++- case ATH10K_HTC_SVC_ID_WMI_DATA_VO: ++- ++- case ATH10K_HTC_SVC_ID_WMI_CONTROL: ++- *ul_pipe = 3; ++- *dl_pipe = 2; ++- break; +++ switch (__le32_to_cpu(entry->pipedir)) { +++ case PIPEDIR_NONE: +++ break; +++ case PIPEDIR_IN: +++ WARN_ON(dl_set); +++ *dl_pipe = __le32_to_cpu(entry->pipenum); +++ dl_set = true; +++ break; +++ case PIPEDIR_OUT: +++ WARN_ON(ul_set); +++ *ul_pipe = __le32_to_cpu(entry->pipenum); +++ ul_set = true; +++ break; +++ case PIPEDIR_INOUT: +++ WARN_ON(dl_set); +++ WARN_ON(ul_set); +++ *dl_pipe = __le32_to_cpu(entry->pipenum); +++ *ul_pipe = __le32_to_cpu(entry->pipenum); +++ dl_set = true; +++ ul_set = true; +++ break; +++ } +++ } ++ ++- /* pipe 5 unused */ ++- /* pipe 6 reserved */ ++- /* pipe 7 reserved */ +++ if (WARN_ON(!ul_set || !dl_set)) +++ return -ENOENT; ++ ++- default: ++- ret = -1; ++- break; ++- } ++ *ul_is_polled = ++ (host_ce_config_wlan[*ul_pipe].flags & CE_ATTR_DIS_INTR) != 0; ++ ++- return ret; +++ return 0; ++ } ++ ++ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar, ++- u8 *ul_pipe, u8 *dl_pipe) +++ u8 *ul_pipe, u8 *dl_pipe) ++ { ++ int ul_is_polled, dl_is_polled; ++ ++- ath10k_dbg(ATH10K_DBG_PCI, "pci hif get default pipe\n"); +++ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get default pipe\n"); ++ ++ (void)ath10k_pci_hif_map_service_to_pipe(ar, ++ ATH10K_HTC_SVC_ID_RSVD_CTRL, ++@@ -1028,209 +1167,127 @@ static void ath10k_pci_hif_get_default_p ++ &dl_is_polled); ++ } ++ ++-static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info, ++- int num) +++static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar) ++ { ++- struct ath10k *ar = pipe_info->hif_ce_state; ++- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++- struct ath10k_ce_pipe *ce_state = pipe_info->ce_hdl; ++- struct sk_buff *skb; ++- dma_addr_t ce_data; ++- int i, ret = 0; +++ u32 val; ++ ++- if (pipe_info->buf_sz == 0) ++- return 0; +++ val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS); +++ val &= ~CORE_CTRL_PCIE_REG_31_MASK; ++ ++- for (i = 0; i < num; i++) { ++- skb = dev_alloc_skb(pipe_info->buf_sz); ++- if (!skb) { ++- ath10k_warn("failed to allocate skbuff for pipe %d\n", ++- num); ++- ret = -ENOMEM; ++- goto err; ++- } +++ ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val); +++} ++ ++- WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb"); +++static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar) +++{ +++ u32 val; ++ ++- ce_data = dma_map_single(ar->dev, skb->data, ++- skb->len + skb_tailroom(skb), ++- DMA_FROM_DEVICE); +++ val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS); +++ val |= CORE_CTRL_PCIE_REG_31_MASK; ++ ++- if (unlikely(dma_mapping_error(ar->dev, ce_data))) { ++- ath10k_warn("failed to DMA map sk_buff\n"); ++- dev_kfree_skb_any(skb); ++- ret = -EIO; ++- goto err; ++- } +++ ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val); +++} ++ ++- ATH10K_SKB_CB(skb)->paddr = ce_data; +++static void ath10k_pci_irq_disable(struct ath10k *ar) +++{ +++ ath10k_ce_disable_interrupts(ar); +++ ath10k_pci_disable_and_clear_legacy_irq(ar); +++ ath10k_pci_irq_msi_fw_mask(ar); +++} ++ ++- pci_dma_sync_single_for_device(ar_pci->pdev, ce_data, ++- pipe_info->buf_sz, ++- PCI_DMA_FROMDEVICE); ++- ++- ret = ath10k_ce_recv_buf_enqueue(ce_state, (void *)skb, ++- ce_data); ++- if (ret) { ++- ath10k_warn("failed to enqueue to pipe %d: %d\n", ++- num, ret); ++- goto err; ++- } ++- } ++- ++- return ret; ++- ++-err: ++- ath10k_pci_rx_pipe_cleanup(pipe_info); ++- return ret; ++-} ++- ++-static int ath10k_pci_post_rx(struct ath10k *ar) +++static void ath10k_pci_irq_sync(struct ath10k *ar) ++ { ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++- struct ath10k_pci_pipe *pipe_info; ++- const struct ce_attr *attr; ++- int pipe_num, ret = 0; ++- ++- for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { ++- pipe_info = &ar_pci->pipe_info[pipe_num]; ++- attr = &host_ce_config_wlan[pipe_num]; ++- ++- if (attr->dest_nentries == 0) ++- continue; ++- ++- ret = ath10k_pci_post_rx_pipe(pipe_info, ++- attr->dest_nentries - 1); ++- if (ret) { ++- ath10k_warn("failed to post RX buffer for pipe %d: %d\n", ++- pipe_num, ret); +++ int i; ++ ++- for (; pipe_num >= 0; pipe_num--) { ++- pipe_info = &ar_pci->pipe_info[pipe_num]; ++- ath10k_pci_rx_pipe_cleanup(pipe_info); ++- } ++- return ret; ++- } ++- } +++ for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++) +++ synchronize_irq(ar_pci->pdev->irq + i); +++} ++ ++- return 0; +++static void ath10k_pci_irq_enable(struct ath10k *ar) +++{ +++ ath10k_ce_enable_interrupts(ar); +++ ath10k_pci_enable_legacy_irq(ar); +++ ath10k_pci_irq_msi_fw_unmask(ar); ++ } ++ ++ static int ath10k_pci_hif_start(struct ath10k *ar) ++ { ++- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++- int ret, ret_early; ++- ++- ath10k_dbg(ATH10K_DBG_BOOT, "boot hif start\n"); ++- ++- ath10k_pci_free_early_irq(ar); ++- ath10k_pci_kill_tasklet(ar); ++- ++- ret = ath10k_pci_request_irq(ar); ++- if (ret) { ++- ath10k_warn("failed to post RX buffers for all pipes: %d\n", ++- ret); ++- goto err_early_irq; ++- } ++- ++- ret = ath10k_pci_setup_ce_irq(ar); ++- if (ret) { ++- ath10k_warn("failed to setup CE interrupts: %d\n", ret); ++- goto err_stop; ++- } +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n"); ++ ++- /* Post buffers once to start things off. */ ++- ret = ath10k_pci_post_rx(ar); ++- if (ret) { ++- ath10k_warn("failed to post RX buffers for all pipes: %d\n", ++- ret); ++- goto err_stop; ++- } +++ ath10k_pci_irq_enable(ar); +++ ath10k_pci_rx_post(ar); ++ ++- ar_pci->started = 1; ++ return 0; ++- ++-err_stop: ++- ath10k_ce_disable_interrupts(ar); ++- ath10k_pci_free_irq(ar); ++- ath10k_pci_kill_tasklet(ar); ++-err_early_irq: ++- /* Though there should be no interrupts (device was reset) ++- * power_down() expects the early IRQ to be installed as per the ++- * driver lifecycle. */ ++- ret_early = ath10k_pci_request_early_irq(ar); ++- if (ret_early) ++- ath10k_warn("failed to re-enable early irq: %d\n", ret_early); ++- ++- return ret; ++ } ++ ++-static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info) +++static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe) ++ { ++ struct ath10k *ar; ++- struct ath10k_pci *ar_pci; ++- struct ath10k_ce_pipe *ce_hdl; ++- u32 buf_sz; ++- struct sk_buff *netbuf; ++- u32 ce_data; +++ struct ath10k_ce_pipe *ce_pipe; +++ struct ath10k_ce_ring *ce_ring; +++ struct sk_buff *skb; +++ int i; ++ ++- buf_sz = pipe_info->buf_sz; +++ ar = pci_pipe->hif_ce_state; +++ ce_pipe = pci_pipe->ce_hdl; +++ ce_ring = ce_pipe->dest_ring; ++ ++- /* Unused Copy Engine */ ++- if (buf_sz == 0) +++ if (!ce_ring) ++ return; ++ ++- ar = pipe_info->hif_ce_state; ++- ar_pci = ath10k_pci_priv(ar); ++- ++- if (!ar_pci->started) +++ if (!pci_pipe->buf_sz) ++ return; ++ ++- ce_hdl = pipe_info->ce_hdl; +++ for (i = 0; i < ce_ring->nentries; i++) { +++ skb = ce_ring->per_transfer_context[i]; +++ if (!skb) +++ continue; +++ +++ ce_ring->per_transfer_context[i] = NULL; ++ ++- while (ath10k_ce_revoke_recv_next(ce_hdl, (void **)&netbuf, ++- &ce_data) == 0) { ++- dma_unmap_single(ar->dev, ATH10K_SKB_CB(netbuf)->paddr, ++- netbuf->len + skb_tailroom(netbuf), +++ dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr, +++ skb->len + skb_tailroom(skb), ++ DMA_FROM_DEVICE); ++- dev_kfree_skb_any(netbuf); +++ dev_kfree_skb_any(skb); ++ } ++ } ++ ++-static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info) +++static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe) ++ { ++ struct ath10k *ar; ++ struct ath10k_pci *ar_pci; ++- struct ath10k_ce_pipe *ce_hdl; ++- struct sk_buff *netbuf; ++- u32 ce_data; ++- unsigned int nbytes; +++ struct ath10k_ce_pipe *ce_pipe; +++ struct ath10k_ce_ring *ce_ring; +++ struct ce_desc *ce_desc; +++ struct sk_buff *skb; ++ unsigned int id; ++- u32 buf_sz; +++ int i; ++ ++- buf_sz = pipe_info->buf_sz; +++ ar = pci_pipe->hif_ce_state; +++ ar_pci = ath10k_pci_priv(ar); +++ ce_pipe = pci_pipe->ce_hdl; +++ ce_ring = ce_pipe->src_ring; ++ ++- /* Unused Copy Engine */ ++- if (buf_sz == 0) +++ if (!ce_ring) ++ return; ++ ++- ar = pipe_info->hif_ce_state; ++- ar_pci = ath10k_pci_priv(ar); ++- ++- if (!ar_pci->started) +++ if (!pci_pipe->buf_sz) ++ return; ++ ++- ce_hdl = pipe_info->ce_hdl; +++ ce_desc = ce_ring->shadow_base; +++ if (WARN_ON(!ce_desc)) +++ return; ++ ++- while (ath10k_ce_cancel_send_next(ce_hdl, (void **)&netbuf, ++- &ce_data, &nbytes, &id) == 0) { ++- /* no need to call tx completion for NULL pointers */ ++- if (!netbuf) +++ for (i = 0; i < ce_ring->nentries; i++) { +++ skb = ce_ring->per_transfer_context[i]; +++ if (!skb) ++ continue; ++ ++- ar_pci->msg_callbacks_current.tx_completion(ar, ++- netbuf, ++- id); +++ ce_ring->per_transfer_context[i] = NULL; +++ id = MS(__le16_to_cpu(ce_desc[i].flags), +++ CE_DESC_FLAGS_META_DATA); +++ +++ ar_pci->msg_callbacks_current.tx_completion(ar, skb); ++ } ++ } ++ ++@@ -1264,38 +1321,32 @@ static void ath10k_pci_ce_deinit(struct ++ ath10k_ce_deinit_pipe(ar, i); ++ } ++ ++-static void ath10k_pci_hif_stop(struct ath10k *ar) +++static void ath10k_pci_flush(struct ath10k *ar) ++ { ++- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++- int ret; ++- ++- ath10k_dbg(ATH10K_DBG_BOOT, "boot hif stop\n"); ++- ++- ret = ath10k_ce_disable_interrupts(ar); ++- if (ret) ++- ath10k_warn("failed to disable CE interrupts: %d\n", ret); ++- ++- ath10k_pci_free_irq(ar); ++ ath10k_pci_kill_tasklet(ar); ++- ++- ret = ath10k_pci_request_early_irq(ar); ++- if (ret) ++- ath10k_warn("failed to re-enable early irq: %d\n", ret); ++- ++- /* At this point, asynchronous threads are stopped, the target should ++- * not DMA nor interrupt. We process the leftovers and then free ++- * everything else up. */ ++- ++ ath10k_pci_buffer_cleanup(ar); +++} ++ ++- /* Make the sure the device won't access any structures on the host by ++- * resetting it. The device was fed with PCI CE ringbuffer ++- * configuration during init. If ringbuffers are freed and the device ++- * were to access them this could lead to memory corruption on the ++- * host. */ +++static void ath10k_pci_hif_stop(struct ath10k *ar) +++{ +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n"); +++ +++ /* Most likely the device has HTT Rx ring configured. The only way to +++ * prevent the device from accessing (and possible corrupting) host +++ * memory is to reset the chip now. +++ * +++ * There's also no known way of masking MSI interrupts on the device. +++ * For ranged MSI the CE-related interrupts can be masked. However +++ * regardless how many MSI interrupts are assigned the first one +++ * is always used for firmware indications (crashes) and cannot be +++ * masked. To prevent the device from asserting the interrupt reset it +++ * before proceeding with cleanup. +++ */ ++ ath10k_pci_warm_reset(ar); ++ ++- ar_pci->started = 0; +++ ath10k_pci_irq_disable(ar); +++ ath10k_pci_irq_sync(ar); +++ ath10k_pci_flush(ar); ++ } ++ ++ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, ++@@ -1346,11 +1397,9 @@ static int ath10k_pci_hif_exchange_bmi_m ++ xfer.wait_for_resp = true; ++ xfer.resp_len = 0; ++ ++- ath10k_ce_recv_buf_enqueue(ce_rx, &xfer, resp_paddr); +++ ath10k_ce_rx_post_buf(ce_rx, &xfer, resp_paddr); ++ } ++ ++- init_completion(&xfer.done); ++- ++ ret = ath10k_ce_send(ce_tx, &xfer, req_paddr, req_len, -1, 0); ++ if (ret) ++ goto err_resp; ++@@ -1401,14 +1450,12 @@ static void ath10k_pci_bmi_send_done(str ++ &nbytes, &transfer_id)) ++ return; ++ ++- if (xfer->wait_for_resp) ++- return; ++- ++- complete(&xfer->done); +++ xfer->tx_done = true; ++ } ++ ++ static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state) ++ { +++ struct ath10k *ar = ce_state->ar; ++ struct bmi_xfer *xfer; ++ u32 ce_data; ++ unsigned int nbytes; ++@@ -1419,13 +1466,16 @@ static void ath10k_pci_bmi_recv_data(str ++ &nbytes, &transfer_id, &flags)) ++ return; ++ +++ if (WARN_ON_ONCE(!xfer)) +++ return; +++ ++ if (!xfer->wait_for_resp) { ++- ath10k_warn("unexpected: BMI data received; ignoring\n"); +++ ath10k_warn(ar, "unexpected: BMI data received; ignoring\n"); ++ return; ++ } ++ ++ xfer->resp_len = nbytes; ++- complete(&xfer->done); +++ xfer->rx_done = true; ++ } ++ ++ static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, ++@@ -1438,7 +1488,7 @@ static int ath10k_pci_bmi_wait(struct at ++ ath10k_pci_bmi_send_done(tx_pipe); ++ ath10k_pci_bmi_recv_data(rx_pipe); ++ ++- if (completion_done(&xfer->done)) +++ if (xfer->tx_done && (xfer->rx_done == xfer->wait_for_resp)) ++ return 0; ++ ++ schedule(); ++@@ -1448,131 +1498,48 @@ static int ath10k_pci_bmi_wait(struct at ++ } ++ ++ /* ++- * Map from service/endpoint to Copy Engine. ++- * This table is derived from the CE_PCI TABLE, above. ++- * It is passed to the Target at startup for use by firmware. ++- */ ++-static const struct service_to_pipe target_service_to_ce_map_wlan[] = { ++- { ++- ATH10K_HTC_SVC_ID_WMI_DATA_VO, ++- PIPEDIR_OUT, /* out = UL = host -> target */ ++- 3, ++- }, ++- { ++- ATH10K_HTC_SVC_ID_WMI_DATA_VO, ++- PIPEDIR_IN, /* in = DL = target -> host */ ++- 2, ++- }, ++- { ++- ATH10K_HTC_SVC_ID_WMI_DATA_BK, ++- PIPEDIR_OUT, /* out = UL = host -> target */ ++- 3, ++- }, ++- { ++- ATH10K_HTC_SVC_ID_WMI_DATA_BK, ++- PIPEDIR_IN, /* in = DL = target -> host */ ++- 2, ++- }, ++- { ++- ATH10K_HTC_SVC_ID_WMI_DATA_BE, ++- PIPEDIR_OUT, /* out = UL = host -> target */ ++- 3, ++- }, ++- { ++- ATH10K_HTC_SVC_ID_WMI_DATA_BE, ++- PIPEDIR_IN, /* in = DL = target -> host */ ++- 2, ++- }, ++- { ++- ATH10K_HTC_SVC_ID_WMI_DATA_VI, ++- PIPEDIR_OUT, /* out = UL = host -> target */ ++- 3, ++- }, ++- { ++- ATH10K_HTC_SVC_ID_WMI_DATA_VI, ++- PIPEDIR_IN, /* in = DL = target -> host */ ++- 2, ++- }, ++- { ++- ATH10K_HTC_SVC_ID_WMI_CONTROL, ++- PIPEDIR_OUT, /* out = UL = host -> target */ ++- 3, ++- }, ++- { ++- ATH10K_HTC_SVC_ID_WMI_CONTROL, ++- PIPEDIR_IN, /* in = DL = target -> host */ ++- 2, ++- }, ++- { ++- ATH10K_HTC_SVC_ID_RSVD_CTRL, ++- PIPEDIR_OUT, /* out = UL = host -> target */ ++- 0, /* could be moved to 3 (share with WMI) */ ++- }, ++- { ++- ATH10K_HTC_SVC_ID_RSVD_CTRL, ++- PIPEDIR_IN, /* in = DL = target -> host */ ++- 1, ++- }, ++- { ++- ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS, /* not currently used */ ++- PIPEDIR_OUT, /* out = UL = host -> target */ ++- 0, ++- }, ++- { ++- ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS, /* not currently used */ ++- PIPEDIR_IN, /* in = DL = target -> host */ ++- 1, ++- }, ++- { ++- ATH10K_HTC_SVC_ID_HTT_DATA_MSG, ++- PIPEDIR_OUT, /* out = UL = host -> target */ ++- 4, ++- }, ++- { ++- ATH10K_HTC_SVC_ID_HTT_DATA_MSG, ++- PIPEDIR_IN, /* in = DL = target -> host */ ++- 1, ++- }, ++- ++- /* (Additions here) */ ++- ++- { /* Must be last */ ++- 0, ++- 0, ++- 0, ++- }, ++-}; ++- ++-/* ++ * Send an interrupt to the device to wake up the Target CPU ++ * so it has an opportunity to notice any changed state. ++ */ ++ static int ath10k_pci_wake_target_cpu(struct ath10k *ar) ++ { ++- int ret; ++- u32 core_ctrl; +++ u32 addr, val; ++ ++- ret = ath10k_pci_diag_read_access(ar, SOC_CORE_BASE_ADDRESS | ++- CORE_CTRL_ADDRESS, ++- &core_ctrl); ++- if (ret) { ++- ath10k_warn("failed to read core_ctrl: %d\n", ret); ++- return ret; ++- } +++ addr = SOC_CORE_BASE_ADDRESS | CORE_CTRL_ADDRESS; +++ val = ath10k_pci_read32(ar, addr); +++ val |= CORE_CTRL_CPU_INTR_MASK; +++ ath10k_pci_write32(ar, addr, val); ++ ++- /* A_INUM_FIRMWARE interrupt to Target CPU */ ++- core_ctrl |= CORE_CTRL_CPU_INTR_MASK; +++ return 0; +++} ++ ++- ret = ath10k_pci_diag_write_access(ar, SOC_CORE_BASE_ADDRESS | ++- CORE_CTRL_ADDRESS, ++- core_ctrl); ++- if (ret) { ++- ath10k_warn("failed to set target CPU interrupt mask: %d\n", ++- ret); ++- return ret; +++static int ath10k_pci_get_num_banks(struct ath10k *ar) +++{ +++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); +++ +++ switch (ar_pci->pdev->device) { +++ case QCA988X_2_0_DEVICE_ID: +++ return 1; +++ case QCA6174_2_1_DEVICE_ID: +++ switch (MS(ar->chip_id, SOC_CHIP_ID_REV)) { +++ case QCA6174_HW_1_0_CHIP_ID_REV: +++ case QCA6174_HW_1_1_CHIP_ID_REV: +++ return 3; +++ case QCA6174_HW_1_3_CHIP_ID_REV: +++ return 2; +++ case QCA6174_HW_2_1_CHIP_ID_REV: +++ case QCA6174_HW_2_2_CHIP_ID_REV: +++ return 6; +++ case QCA6174_HW_3_0_CHIP_ID_REV: +++ case QCA6174_HW_3_1_CHIP_ID_REV: +++ case QCA6174_HW_3_2_CHIP_ID_REV: +++ return 9; +++ } +++ break; ++ } ++ ++- return 0; +++ ath10k_warn(ar, "unknown number of banks, assuming 1\n"); +++ return 1; ++ } ++ ++ static int ath10k_pci_init_config(struct ath10k *ar) ++@@ -1593,144 +1560,162 @@ static int ath10k_pci_init_config(struct ++ host_interest_item_address(HI_ITEM(hi_interconnect_state)); ++ ++ /* Supply Target-side CE configuration */ ++- ret = ath10k_pci_diag_read_access(ar, interconnect_targ_addr, ++- &pcie_state_targ_addr); +++ ret = ath10k_pci_diag_read32(ar, interconnect_targ_addr, +++ &pcie_state_targ_addr); ++ if (ret != 0) { ++- ath10k_err("Failed to get pcie state addr: %d\n", ret); +++ ath10k_err(ar, "Failed to get pcie state addr: %d\n", ret); ++ return ret; ++ } ++ ++ if (pcie_state_targ_addr == 0) { ++ ret = -EIO; ++- ath10k_err("Invalid pcie state addr\n"); +++ ath10k_err(ar, "Invalid pcie state addr\n"); ++ return ret; ++ } ++ ++- ret = ath10k_pci_diag_read_access(ar, pcie_state_targ_addr + +++ ret = ath10k_pci_diag_read32(ar, (pcie_state_targ_addr + ++ offsetof(struct pcie_state, ++- pipe_cfg_addr), ++- &pipe_cfg_targ_addr); +++ pipe_cfg_addr)), +++ &pipe_cfg_targ_addr); ++ if (ret != 0) { ++- ath10k_err("Failed to get pipe cfg addr: %d\n", ret); +++ ath10k_err(ar, "Failed to get pipe cfg addr: %d\n", ret); ++ return ret; ++ } ++ ++ if (pipe_cfg_targ_addr == 0) { ++ ret = -EIO; ++- ath10k_err("Invalid pipe cfg addr\n"); +++ ath10k_err(ar, "Invalid pipe cfg addr\n"); ++ return ret; ++ } ++ ++ ret = ath10k_pci_diag_write_mem(ar, pipe_cfg_targ_addr, ++- target_ce_config_wlan, ++- sizeof(target_ce_config_wlan)); +++ target_ce_config_wlan, +++ sizeof(target_ce_config_wlan)); ++ ++ if (ret != 0) { ++- ath10k_err("Failed to write pipe cfg: %d\n", ret); +++ ath10k_err(ar, "Failed to write pipe cfg: %d\n", ret); ++ return ret; ++ } ++ ++- ret = ath10k_pci_diag_read_access(ar, pcie_state_targ_addr + +++ ret = ath10k_pci_diag_read32(ar, (pcie_state_targ_addr + ++ offsetof(struct pcie_state, ++- svc_to_pipe_map), ++- &svc_to_pipe_map); +++ svc_to_pipe_map)), +++ &svc_to_pipe_map); ++ if (ret != 0) { ++- ath10k_err("Failed to get svc/pipe map: %d\n", ret); +++ ath10k_err(ar, "Failed to get svc/pipe map: %d\n", ret); ++ return ret; ++ } ++ ++ if (svc_to_pipe_map == 0) { ++ ret = -EIO; ++- ath10k_err("Invalid svc_to_pipe map\n"); +++ ath10k_err(ar, "Invalid svc_to_pipe map\n"); ++ return ret; ++ } ++ ++ ret = ath10k_pci_diag_write_mem(ar, svc_to_pipe_map, ++- target_service_to_ce_map_wlan, ++- sizeof(target_service_to_ce_map_wlan)); +++ target_service_to_ce_map_wlan, +++ sizeof(target_service_to_ce_map_wlan)); ++ if (ret != 0) { ++- ath10k_err("Failed to write svc/pipe map: %d\n", ret); +++ ath10k_err(ar, "Failed to write svc/pipe map: %d\n", ret); ++ return ret; ++ } ++ ++- ret = ath10k_pci_diag_read_access(ar, pcie_state_targ_addr + +++ ret = ath10k_pci_diag_read32(ar, (pcie_state_targ_addr + ++ offsetof(struct pcie_state, ++- config_flags), ++- &pcie_config_flags); +++ config_flags)), +++ &pcie_config_flags); ++ if (ret != 0) { ++- ath10k_err("Failed to get pcie config_flags: %d\n", ret); +++ ath10k_err(ar, "Failed to get pcie config_flags: %d\n", ret); ++ return ret; ++ } ++ ++ pcie_config_flags &= ~PCIE_CONFIG_FLAG_ENABLE_L1; ++ ++- ret = ath10k_pci_diag_write_mem(ar, pcie_state_targ_addr + ++- offsetof(struct pcie_state, config_flags), ++- &pcie_config_flags, ++- sizeof(pcie_config_flags)); +++ ret = ath10k_pci_diag_write32(ar, (pcie_state_targ_addr + +++ offsetof(struct pcie_state, +++ config_flags)), +++ pcie_config_flags); ++ if (ret != 0) { ++- ath10k_err("Failed to write pcie config_flags: %d\n", ret); +++ ath10k_err(ar, "Failed to write pcie config_flags: %d\n", ret); ++ return ret; ++ } ++ ++ /* configure early allocation */ ++ ealloc_targ_addr = host_interest_item_address(HI_ITEM(hi_early_alloc)); ++ ++- ret = ath10k_pci_diag_read_access(ar, ealloc_targ_addr, &ealloc_value); +++ ret = ath10k_pci_diag_read32(ar, ealloc_targ_addr, &ealloc_value); ++ if (ret != 0) { ++- ath10k_err("Faile to get early alloc val: %d\n", ret); +++ ath10k_err(ar, "Faile to get early alloc val: %d\n", ret); ++ return ret; ++ } ++ ++ /* first bank is switched to IRAM */ ++ ealloc_value |= ((HI_EARLY_ALLOC_MAGIC << HI_EARLY_ALLOC_MAGIC_SHIFT) & ++ HI_EARLY_ALLOC_MAGIC_MASK); ++- ealloc_value |= ((1 << HI_EARLY_ALLOC_IRAM_BANKS_SHIFT) & +++ ealloc_value |= ((ath10k_pci_get_num_banks(ar) << +++ HI_EARLY_ALLOC_IRAM_BANKS_SHIFT) & ++ HI_EARLY_ALLOC_IRAM_BANKS_MASK); ++ ++- ret = ath10k_pci_diag_write_access(ar, ealloc_targ_addr, ealloc_value); +++ ret = ath10k_pci_diag_write32(ar, ealloc_targ_addr, ealloc_value); ++ if (ret != 0) { ++- ath10k_err("Failed to set early alloc val: %d\n", ret); +++ ath10k_err(ar, "Failed to set early alloc val: %d\n", ret); ++ return ret; ++ } ++ ++ /* Tell Target to proceed with initialization */ ++ flag2_targ_addr = host_interest_item_address(HI_ITEM(hi_option_flag2)); ++ ++- ret = ath10k_pci_diag_read_access(ar, flag2_targ_addr, &flag2_value); +++ ret = ath10k_pci_diag_read32(ar, flag2_targ_addr, &flag2_value); ++ if (ret != 0) { ++- ath10k_err("Failed to get option val: %d\n", ret); +++ ath10k_err(ar, "Failed to get option val: %d\n", ret); ++ return ret; ++ } ++ ++ flag2_value |= HI_OPTION_EARLY_CFG_DONE; ++ ++- ret = ath10k_pci_diag_write_access(ar, flag2_targ_addr, flag2_value); +++ ret = ath10k_pci_diag_write32(ar, flag2_targ_addr, flag2_value); ++ if (ret != 0) { ++- ath10k_err("Failed to set option val: %d\n", ret); +++ ath10k_err(ar, "Failed to set option val: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++ } ++ ++-static int ath10k_pci_alloc_ce(struct ath10k *ar) +++static int ath10k_pci_alloc_pipes(struct ath10k *ar) ++ { +++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); +++ struct ath10k_pci_pipe *pipe; ++ int i, ret; ++ ++ for (i = 0; i < CE_COUNT; i++) { ++- ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]); +++ pipe = &ar_pci->pipe_info[i]; +++ pipe->ce_hdl = &ar_pci->ce_states[i]; +++ pipe->pipe_num = i; +++ pipe->hif_ce_state = ar; +++ +++ ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i], +++ ath10k_pci_ce_send_done, +++ ath10k_pci_ce_recv_data); ++ if (ret) { ++- ath10k_err("failed to allocate copy engine pipe %d: %d\n", +++ ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n", ++ i, ret); ++ return ret; ++ } +++ +++ /* Last CE is Diagnostic Window */ +++ if (i == CE_COUNT - 1) { +++ ar_pci->ce_diag = pipe->ce_hdl; +++ continue; +++ } +++ +++ pipe->buf_sz = (size_t)(host_ce_config_wlan[i].src_sz_max); ++ } ++ ++ return 0; ++ } ++ ++-static void ath10k_pci_free_ce(struct ath10k *ar) +++static void ath10k_pci_free_pipes(struct ath10k *ar) ++ { ++ int i; ++ ++@@ -1738,305 +1723,319 @@ static void ath10k_pci_free_ce(struct at ++ ath10k_ce_free_pipe(ar, i); ++ } ++ ++-static int ath10k_pci_ce_init(struct ath10k *ar) +++static int ath10k_pci_init_pipes(struct ath10k *ar) ++ { ++- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++- struct ath10k_pci_pipe *pipe_info; ++- const struct ce_attr *attr; ++- int pipe_num, ret; ++- ++- for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { ++- pipe_info = &ar_pci->pipe_info[pipe_num]; ++- pipe_info->ce_hdl = &ar_pci->ce_states[pipe_num]; ++- pipe_info->pipe_num = pipe_num; ++- pipe_info->hif_ce_state = ar; ++- attr = &host_ce_config_wlan[pipe_num]; +++ int i, ret; ++ ++- ret = ath10k_ce_init_pipe(ar, pipe_num, attr); +++ for (i = 0; i < CE_COUNT; i++) { +++ ret = ath10k_ce_init_pipe(ar, i, &host_ce_config_wlan[i]); ++ if (ret) { ++- ath10k_err("failed to initialize copy engine pipe %d: %d\n", ++- pipe_num, ret); +++ ath10k_err(ar, "failed to initialize copy engine pipe %d: %d\n", +++ i, ret); ++ return ret; ++ } ++- ++- if (pipe_num == CE_COUNT - 1) { ++- /* ++- * Reserve the ultimate CE for ++- * diagnostic Window support ++- */ ++- ar_pci->ce_diag = pipe_info->ce_hdl; ++- continue; ++- } ++- ++- pipe_info->buf_sz = (size_t) (attr->src_sz_max); ++ } ++ ++ return 0; ++ } ++ ++-static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar) +++static bool ath10k_pci_has_fw_crashed(struct ath10k *ar) ++ { ++- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++- u32 fw_indicator; ++- ++- ath10k_pci_wake(ar); ++- ++- fw_indicator = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); ++- ++- if (fw_indicator & FW_IND_EVENT_PENDING) { ++- /* ACK: clear Target-side pending event */ ++- ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, ++- fw_indicator & ~FW_IND_EVENT_PENDING); ++- ++- if (ar_pci->started) { ++- ath10k_pci_hif_dump_area(ar); ++- } else { ++- /* ++- * Probable Target failure before we're prepared ++- * to handle it. Generally unexpected. ++- */ ++- ath10k_warn("early firmware event indicated\n"); ++- } ++- } ++- ++- ath10k_pci_sleep(ar); +++ return ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS) & +++ FW_IND_EVENT_PENDING; ++ } ++ ++-static int ath10k_pci_warm_reset(struct ath10k *ar) +++static void ath10k_pci_fw_crashed_clear(struct ath10k *ar) ++ { ++- int ret = 0; ++ u32 val; ++ ++- ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset\n"); +++ val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); +++ val &= ~FW_IND_EVENT_PENDING; +++ ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, val); +++} ++ ++- ret = ath10k_do_pci_wake(ar); ++- if (ret) { ++- ath10k_err("failed to wake up target: %d\n", ret); ++- return ret; ++- } +++/* this function effectively clears target memory controller assert line */ +++static void ath10k_pci_warm_reset_si0(struct ath10k *ar) +++{ +++ u32 val; ++ ++- /* debug */ ++- val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + ++- PCIE_INTR_CAUSE_ADDRESS); ++- ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val); +++ val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS); +++ ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS, +++ val | SOC_RESET_CONTROL_SI0_RST_MASK); +++ val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS); ++ ++- val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + ++- CPU_INTR_ADDRESS); ++- ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n", ++- val); +++ msleep(10); ++ ++- /* disable pending irqs */ ++- ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + ++- PCIE_INTR_ENABLE_ADDRESS, 0); +++ val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS); +++ ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS, +++ val & ~SOC_RESET_CONTROL_SI0_RST_MASK); +++ val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS); ++ ++- ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + ++- PCIE_INTR_CLR_ADDRESS, ~0); +++ msleep(10); +++} ++ ++- msleep(100); +++static void ath10k_pci_warm_reset_cpu(struct ath10k *ar) +++{ +++ u32 val; ++ ++- /* clear fw indicator */ ++ ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, 0); ++ ++- /* clear target LF timer interrupts */ ++ val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + ++- SOC_LF_TIMER_CONTROL0_ADDRESS); ++- ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + ++- SOC_LF_TIMER_CONTROL0_ADDRESS, ++- val & ~SOC_LF_TIMER_CONTROL0_ENABLE_MASK); +++ SOC_RESET_CONTROL_ADDRESS); +++ ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, +++ val | SOC_RESET_CONTROL_CPU_WARM_RST_MASK); +++} +++ +++static void ath10k_pci_warm_reset_ce(struct ath10k *ar) +++{ +++ u32 val; ++ ++- /* reset CE */ ++ val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + ++ SOC_RESET_CONTROL_ADDRESS); +++ ++ ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, ++ val | SOC_RESET_CONTROL_CE_RST_MASK); ++- val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + ++- SOC_RESET_CONTROL_ADDRESS); ++ msleep(10); ++- ++- /* unreset CE */ ++ ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, ++ val & ~SOC_RESET_CONTROL_CE_RST_MASK); ++- val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + ++- SOC_RESET_CONTROL_ADDRESS); ++- msleep(10); +++} ++ ++- /* debug */ ++- val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + ++- PCIE_INTR_CAUSE_ADDRESS); ++- ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val); ++- ++- val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + ++- CPU_INTR_ADDRESS); ++- ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n", ++- val); +++static void ath10k_pci_warm_reset_clear_lf(struct ath10k *ar) +++{ +++ u32 val; ++ ++- /* CPU warm reset */ ++ val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + ++- SOC_RESET_CONTROL_ADDRESS); ++- ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, ++- val | SOC_RESET_CONTROL_CPU_WARM_RST_MASK); +++ SOC_LF_TIMER_CONTROL0_ADDRESS); +++ ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + +++ SOC_LF_TIMER_CONTROL0_ADDRESS, +++ val & ~SOC_LF_TIMER_CONTROL0_ENABLE_MASK); +++} ++ ++- val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + ++- SOC_RESET_CONTROL_ADDRESS); ++- ath10k_dbg(ATH10K_DBG_BOOT, "boot target reset state: 0x%08x\n", val); +++static int ath10k_pci_warm_reset(struct ath10k *ar) +++{ +++ int ret; ++ ++- msleep(100); +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset\n"); ++ ++- ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset complete\n"); +++ spin_lock_bh(&ar->data_lock); +++ ar->stats.fw_warm_reset_counter++; +++ spin_unlock_bh(&ar->data_lock); +++ +++ ath10k_pci_irq_disable(ar); +++ +++ /* Make sure the target CPU is not doing anything dangerous, e.g. if it +++ * were to access copy engine while host performs copy engine reset +++ * then it is possible for the device to confuse pci-e controller to +++ * the point of bringing host system to a complete stop (i.e. hang). +++ */ +++ ath10k_pci_warm_reset_si0(ar); +++ ath10k_pci_warm_reset_cpu(ar); +++ ath10k_pci_init_pipes(ar); +++ ath10k_pci_wait_for_target_init(ar); +++ +++ ath10k_pci_warm_reset_clear_lf(ar); +++ ath10k_pci_warm_reset_ce(ar); +++ ath10k_pci_warm_reset_cpu(ar); +++ ath10k_pci_init_pipes(ar); ++ ++- ath10k_do_pci_sleep(ar); ++- return ret; +++ ret = ath10k_pci_wait_for_target_init(ar); +++ if (ret) { +++ ath10k_warn(ar, "failed to wait for target init: %d\n", ret); +++ return ret; +++ } +++ +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset complete\n"); +++ +++ return 0; ++ } ++ ++-static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset) +++static int ath10k_pci_qca988x_chip_reset(struct ath10k *ar) ++ { ++- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++- const char *irq_mode; ++- int ret; +++ int i, ret; +++ u32 val; ++ ++- /* ++- * Bring the target up cleanly. +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot 988x chip reset\n"); +++ +++ /* Some hardware revisions (e.g. CUS223v2) has issues with cold reset. +++ * It is thus preferred to use warm reset which is safer but may not be +++ * able to recover the device from all possible fail scenarios. ++ * ++- * The target may be in an undefined state with an AUX-powered Target ++- * and a Host in WoW mode. If the Host crashes, loses power, or is ++- * restarted (without unloading the driver) then the Target is left ++- * (aux) powered and running. On a subsequent driver load, the Target ++- * is in an unexpected state. We try to catch that here in order to ++- * reset the Target and retry the probe. +++ * Warm reset doesn't always work on first try so attempt it a few +++ * times before giving up. ++ */ ++- if (cold_reset) ++- ret = ath10k_pci_cold_reset(ar); ++- else +++ for (i = 0; i < ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS; i++) { ++ ret = ath10k_pci_warm_reset(ar); +++ if (ret) { +++ ath10k_warn(ar, "failed to warm reset attempt %d of %d: %d\n", +++ i + 1, ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS, +++ ret); +++ continue; +++ } +++ +++ /* FIXME: Sometimes copy engine doesn't recover after warm +++ * reset. In most cases this needs cold reset. In some of these +++ * cases the device is in such a state that a cold reset may +++ * lock up the host. +++ * +++ * Reading any host interest register via copy engine is +++ * sufficient to verify if device is capable of booting +++ * firmware blob. +++ */ +++ ret = ath10k_pci_init_pipes(ar); +++ if (ret) { +++ ath10k_warn(ar, "failed to init copy engine: %d\n", +++ ret); +++ continue; +++ } +++ +++ ret = ath10k_pci_diag_read32(ar, QCA988X_HOST_INTEREST_ADDRESS, +++ &val); +++ if (ret) { +++ ath10k_warn(ar, "failed to poke copy engine: %d\n", +++ ret); +++ continue; +++ } +++ +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip reset complete (warm)\n"); +++ return 0; +++ } ++ +++ if (ath10k_pci_reset_mode == ATH10K_PCI_RESET_WARM_ONLY) { +++ ath10k_warn(ar, "refusing cold reset as requested\n"); +++ return -EPERM; +++ } +++ +++ ret = ath10k_pci_cold_reset(ar); ++ if (ret) { ++- ath10k_err("failed to reset target: %d\n", ret); ++- goto err; +++ ath10k_warn(ar, "failed to cold reset: %d\n", ret); +++ return ret; +++ } +++ +++ ret = ath10k_pci_wait_for_target_init(ar); +++ if (ret) { +++ ath10k_warn(ar, "failed to wait for target after cold reset: %d\n", +++ ret); +++ return ret; ++ } ++ ++- if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) ++- /* Force AWAKE forever */ ++- ath10k_do_pci_wake(ar); +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca988x chip reset complete (cold)\n"); ++ ++- ret = ath10k_pci_ce_init(ar); +++ return 0; +++} +++ +++static int ath10k_pci_qca6174_chip_reset(struct ath10k *ar) +++{ +++ int ret; +++ +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca6174 chip reset\n"); +++ +++ /* FIXME: QCA6174 requires cold + warm reset to work. */ +++ +++ ret = ath10k_pci_cold_reset(ar); ++ if (ret) { ++- ath10k_err("failed to initialize CE: %d\n", ret); ++- goto err_ps; +++ ath10k_warn(ar, "failed to cold reset: %d\n", ret); +++ return ret; ++ } ++ ++- ret = ath10k_ce_disable_interrupts(ar); +++ ret = ath10k_pci_wait_for_target_init(ar); ++ if (ret) { ++- ath10k_err("failed to disable CE interrupts: %d\n", ret); ++- goto err_ce; +++ ath10k_warn(ar, "failed to wait for target after cold reset: %d\n", +++ ret); +++ return ret; ++ } ++ ++- ret = ath10k_pci_init_irq(ar); +++ ret = ath10k_pci_warm_reset(ar); +++ if (ret) { +++ ath10k_warn(ar, "failed to warm reset: %d\n", ret); +++ return ret; +++ } +++ +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca6174 chip reset complete (cold)\n"); +++ +++ return 0; +++} +++ +++static int ath10k_pci_chip_reset(struct ath10k *ar) +++{ +++ if (QCA_REV_988X(ar)) +++ return ath10k_pci_qca988x_chip_reset(ar); +++ else if (QCA_REV_6174(ar)) +++ return ath10k_pci_qca6174_chip_reset(ar); +++ else +++ return -ENOTSUPP; +++} +++ +++static int ath10k_pci_hif_power_up(struct ath10k *ar) +++{ +++ int ret; +++ +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power up\n"); +++ +++ ret = ath10k_pci_wake(ar); +++ if (ret) { +++ ath10k_err(ar, "failed to wake up target: %d\n", ret); +++ return ret; +++ } +++ +++ /* +++ * Bring the target up cleanly. +++ * +++ * The target may be in an undefined state with an AUX-powered Target +++ * and a Host in WoW mode. If the Host crashes, loses power, or is +++ * restarted (without unloading the driver) then the Target is left +++ * (aux) powered and running. On a subsequent driver load, the Target +++ * is in an unexpected state. We try to catch that here in order to +++ * reset the Target and retry the probe. +++ */ +++ ret = ath10k_pci_chip_reset(ar); ++ if (ret) { ++- ath10k_err("failed to init irqs: %d\n", ret); ++- goto err_ce; ++- } +++ if (ath10k_pci_has_fw_crashed(ar)) { +++ ath10k_warn(ar, "firmware crashed during chip reset\n"); +++ ath10k_pci_fw_crashed_clear(ar); +++ ath10k_pci_fw_crashed_dump(ar); +++ } ++ ++- ret = ath10k_pci_request_early_irq(ar); ++- if (ret) { ++- ath10k_err("failed to request early irq: %d\n", ret); ++- goto err_deinit_irq; +++ ath10k_err(ar, "failed to reset chip: %d\n", ret); +++ goto err_sleep; ++ } ++ ++- ret = ath10k_pci_wait_for_target_init(ar); +++ ret = ath10k_pci_init_pipes(ar); ++ if (ret) { ++- ath10k_err("failed to wait for target to init: %d\n", ret); ++- goto err_free_early_irq; +++ ath10k_err(ar, "failed to initialize CE: %d\n", ret); +++ goto err_sleep; ++ } ++ ++ ret = ath10k_pci_init_config(ar); ++ if (ret) { ++- ath10k_err("failed to setup init config: %d\n", ret); ++- goto err_free_early_irq; +++ ath10k_err(ar, "failed to setup init config: %d\n", ret); +++ goto err_ce; ++ } ++ ++ ret = ath10k_pci_wake_target_cpu(ar); ++ if (ret) { ++- ath10k_err("could not wake up target CPU: %d\n", ret); ++- goto err_free_early_irq; +++ ath10k_err(ar, "could not wake up target CPU: %d\n", ret); +++ goto err_ce; ++ } ++ ++- if (ar_pci->num_msi_intrs > 1) ++- irq_mode = "MSI-X"; ++- else if (ar_pci->num_msi_intrs == 1) ++- irq_mode = "MSI"; ++- else ++- irq_mode = "legacy"; ++- ++- if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) ++- ath10k_info("pci irq %s irq_mode %d reset_mode %d\n", ++- irq_mode, ath10k_pci_irq_mode, ++- ath10k_pci_reset_mode); ++- ++ return 0; ++ ++-err_free_early_irq: ++- ath10k_pci_free_early_irq(ar); ++-err_deinit_irq: ++- ath10k_pci_deinit_irq(ar); ++ err_ce: ++ ath10k_pci_ce_deinit(ar); ++- ath10k_pci_warm_reset(ar); ++-err_ps: ++- if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) ++- ath10k_do_pci_sleep(ar); ++-err: ++- return ret; ++-} ++- ++-static int ath10k_pci_hif_power_up(struct ath10k *ar) ++-{ ++- int ret; ++- ++- ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power up\n"); ++- ++- /* ++- * Hardware CUS232 version 2 has some issues with cold reset and the ++- * preferred (and safer) way to perform a device reset is through a ++- * warm reset. ++- * ++- * Warm reset doesn't always work though (notably after a firmware ++- * crash) so fall back to cold reset if necessary. ++- */ ++- ret = __ath10k_pci_hif_power_up(ar, false); ++- if (ret) { ++- ath10k_warn("failed to power up target using warm reset: %d\n", ++- ret); ++- ++- if (ath10k_pci_reset_mode == ATH10K_PCI_RESET_WARM_ONLY) ++- return ret; ++ ++- ath10k_warn("trying cold reset\n"); ++- ++- ret = __ath10k_pci_hif_power_up(ar, true); ++- if (ret) { ++- ath10k_err("failed to power up target using cold reset too (%d)\n", ++- ret); ++- return ret; ++- } ++- } ++- ++- return 0; +++err_sleep: +++ ath10k_pci_sleep(ar); +++ return ret; ++ } ++ ++ static void ath10k_pci_hif_power_down(struct ath10k *ar) ++ { ++- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n"); ++ ++- ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power down\n"); ++- ++- ath10k_pci_free_early_irq(ar); ++- ath10k_pci_kill_tasklet(ar); ++- ath10k_pci_deinit_irq(ar); ++- ath10k_pci_ce_deinit(ar); ++- ath10k_pci_warm_reset(ar); +++ /* Currently hif_power_up performs effectively a reset and hif_stop +++ * resets the chip as well so there's no point in resetting here. +++ */ ++ ++- if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) ++- ath10k_do_pci_sleep(ar); +++ ath10k_pci_sleep(ar); ++ } ++ ++ #ifdef CONFIG_PM ++@@ -2090,6 +2089,8 @@ static int ath10k_pci_hif_resume(struct ++ ++ static const struct ath10k_hif_ops ath10k_pci_hif_ops = { ++ .tx_sg = ath10k_pci_hif_tx_sg, +++ .diag_read = ath10k_pci_hif_diag_read, +++ .diag_write = ath10k_pci_diag_write_mem, ++ .exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg, ++ .start = ath10k_pci_hif_start, ++ .stop = ath10k_pci_hif_stop, ++@@ -2100,6 +2101,8 @@ static const struct ath10k_hif_ops ath10 ++ .get_free_queue_number = ath10k_pci_hif_get_free_queue_number, ++ .power_up = ath10k_pci_hif_power_up, ++ .power_down = ath10k_pci_hif_power_down, +++ .read32 = ath10k_pci_read32, +++ .write32 = ath10k_pci_write32, ++ #ifdef CONFIG_PM ++ .suspend = ath10k_pci_hif_suspend, ++ .resume = ath10k_pci_hif_resume, ++@@ -2118,7 +2121,14 @@ static void ath10k_msi_err_tasklet(unsig ++ { ++ struct ath10k *ar = (struct ath10k *)data; ++ ++- ath10k_pci_fw_interrupt_handler(ar); +++ if (!ath10k_pci_has_fw_crashed(ar)) { +++ ath10k_warn(ar, "received unsolicited fw crash interrupt\n"); +++ return; +++ } +++ +++ ath10k_pci_irq_disable(ar); +++ ath10k_pci_fw_crashed_clear(ar); +++ ath10k_pci_fw_crashed_dump(ar); ++ } ++ ++ /* ++@@ -2132,7 +2142,8 @@ static irqreturn_t ath10k_pci_per_engine ++ int ce_id = irq - ar_pci->pdev->irq - MSI_ASSIGN_CE_INITIAL; ++ ++ if (ce_id < 0 || ce_id >= ARRAY_SIZE(ar_pci->pipe_info)) { ++- ath10k_warn("unexpected/invalid irq %d ce_id %d\n", irq, ce_id); +++ ath10k_warn(ar, "unexpected/invalid irq %d ce_id %d\n", irq, +++ ce_id); ++ return IRQ_HANDLED; ++ } ++ ++@@ -2179,39 +2190,18 @@ static irqreturn_t ath10k_pci_interrupt_ ++ return IRQ_HANDLED; ++ } ++ ++-static void ath10k_pci_early_irq_tasklet(unsigned long data) +++static void ath10k_pci_tasklet(unsigned long data) ++ { ++ struct ath10k *ar = (struct ath10k *)data; ++- u32 fw_ind; ++- int ret; +++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++ ++- ret = ath10k_pci_wake(ar); ++- if (ret) { ++- ath10k_warn("failed to wake target in early irq tasklet: %d\n", ++- ret); +++ if (ath10k_pci_has_fw_crashed(ar)) { +++ ath10k_pci_irq_disable(ar); +++ ath10k_pci_fw_crashed_clear(ar); +++ ath10k_pci_fw_crashed_dump(ar); ++ return; ++ } ++ ++- fw_ind = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); ++- if (fw_ind & FW_IND_EVENT_PENDING) { ++- ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, ++- fw_ind & ~FW_IND_EVENT_PENDING); ++- ++- /* Some structures are unavailable during early boot or at ++- * driver teardown so just print that the device has crashed. */ ++- ath10k_warn("device crashed - no diagnostics available\n"); ++- } ++- ++- ath10k_pci_sleep(ar); ++- ath10k_pci_enable_legacy_irq(ar); ++-} ++- ++-static void ath10k_pci_tasklet(unsigned long data) ++-{ ++- struct ath10k *ar = (struct ath10k *)data; ++- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++- ++- ath10k_pci_fw_interrupt_handler(ar); /* FIXME: Handle FW error */ ++ ath10k_ce_per_engine_service_any(ar); ++ ++ /* Re-enable legacy irq that was disabled in the irq handler */ ++@@ -2228,7 +2218,7 @@ static int ath10k_pci_request_irq_msix(s ++ ath10k_pci_msi_fw_handler, ++ IRQF_SHARED, "ath10k_pci", ar); ++ if (ret) { ++- ath10k_warn("failed to request MSI-X fw irq %d: %d\n", +++ ath10k_warn(ar, "failed to request MSI-X fw irq %d: %d\n", ++ ar_pci->pdev->irq + MSI_ASSIGN_FW, ret); ++ return ret; ++ } ++@@ -2238,7 +2228,7 @@ static int ath10k_pci_request_irq_msix(s ++ ath10k_pci_per_engine_handler, ++ IRQF_SHARED, "ath10k_pci", ar); ++ if (ret) { ++- ath10k_warn("failed to request MSI-X ce irq %d: %d\n", +++ ath10k_warn(ar, "failed to request MSI-X ce irq %d: %d\n", ++ ar_pci->pdev->irq + i, ret); ++ ++ for (i--; i >= MSI_ASSIGN_CE_INITIAL; i--) ++@@ -2261,7 +2251,7 @@ static int ath10k_pci_request_irq_msi(st ++ ath10k_pci_interrupt_handler, ++ IRQF_SHARED, "ath10k_pci", ar); ++ if (ret) { ++- ath10k_warn("failed to request MSI irq %d: %d\n", +++ ath10k_warn(ar, "failed to request MSI irq %d: %d\n", ++ ar_pci->pdev->irq, ret); ++ return ret; ++ } ++@@ -2278,7 +2268,7 @@ static int ath10k_pci_request_irq_legacy ++ ath10k_pci_interrupt_handler, ++ IRQF_SHARED, "ath10k_pci", ar); ++ if (ret) { ++- ath10k_warn("failed to request legacy irq %d: %d\n", +++ ath10k_warn(ar, "failed to request legacy irq %d: %d\n", ++ ar_pci->pdev->irq, ret); ++ return ret; ++ } ++@@ -2299,7 +2289,7 @@ static int ath10k_pci_request_irq(struct ++ return ath10k_pci_request_irq_msix(ar); ++ } ++ ++- ath10k_warn("unknown irq configuration upon request\n"); +++ ath10k_warn(ar, "unknown irq configuration upon request\n"); ++ return -EINVAL; ++ } ++ ++@@ -2322,8 +2312,6 @@ static void ath10k_pci_init_irq_tasklets ++ tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar); ++ tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet, ++ (unsigned long)ar); ++- tasklet_init(&ar_pci->early_irq_tasklet, ath10k_pci_early_irq_tasklet, ++- (unsigned long)ar); ++ ++ for (i = 0; i < CE_COUNT; i++) { ++ ar_pci->pipe_info[i].ar_pci = ar_pci; ++@@ -2335,21 +2323,19 @@ static void ath10k_pci_init_irq_tasklets ++ static int ath10k_pci_init_irq(struct ath10k *ar) ++ { ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++- bool msix_supported = test_bit(ATH10K_PCI_FEATURE_MSI_X, ++- ar_pci->features); ++ int ret; ++ ++ ath10k_pci_init_irq_tasklets(ar); ++ ++- if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_AUTO && ++- !test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) ++- ath10k_info("limiting irq mode to: %d\n", ath10k_pci_irq_mode); +++ if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_AUTO) +++ ath10k_info(ar, "limiting irq mode to: %d\n", +++ ath10k_pci_irq_mode); ++ ++ /* Try MSI-X */ ++- if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO && msix_supported) { +++ if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO) { ++ ar_pci->num_msi_intrs = MSI_NUM_REQUEST; ++ ret = pci_enable_msi_range(ar_pci->pdev, ar_pci->num_msi_intrs, ++- ar_pci->num_msi_intrs); +++ ar_pci->num_msi_intrs); ++ if (ret > 0) ++ return 0; ++ ++@@ -2376,34 +2362,16 @@ static int ath10k_pci_init_irq(struct at ++ * synchronization checking. */ ++ ar_pci->num_msi_intrs = 0; ++ ++- ret = ath10k_pci_wake(ar); ++- if (ret) { ++- ath10k_warn("failed to wake target: %d\n", ret); ++- return ret; ++- } ++- ++ ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, ++ PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL); ++- ath10k_pci_sleep(ar); ++ ++ return 0; ++ } ++ ++-static int ath10k_pci_deinit_irq_legacy(struct ath10k *ar) +++static void ath10k_pci_deinit_irq_legacy(struct ath10k *ar) ++ { ++- int ret; ++- ++- ret = ath10k_pci_wake(ar); ++- if (ret) { ++- ath10k_warn("failed to wake target: %d\n", ret); ++- return ret; ++- } ++- ++ ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, ++ 0); ++- ath10k_pci_sleep(ar); ++- ++- return 0; ++ } ++ ++ static int ath10k_pci_deinit_irq(struct ath10k *ar) ++@@ -2412,7 +2380,8 @@ static int ath10k_pci_deinit_irq(struct ++ ++ switch (ar_pci->num_msi_intrs) { ++ case 0: ++- return ath10k_pci_deinit_irq_legacy(ar); +++ ath10k_pci_deinit_irq_legacy(ar); +++ return 0; ++ case 1: ++ /* fall-through */ ++ case MSI_NUM_REQUEST: ++@@ -2422,7 +2391,7 @@ static int ath10k_pci_deinit_irq(struct ++ pci_disable_msi(ar_pci->pdev); ++ } ++ ++- ath10k_warn("unknown irq configuration upon deinit\n"); +++ ath10k_warn(ar, "unknown irq configuration upon deinit\n"); ++ return -EINVAL; ++ } ++ ++@@ -2430,23 +2399,17 @@ static int ath10k_pci_wait_for_target_in ++ { ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++ unsigned long timeout; ++- int ret; ++ u32 val; ++ ++- ath10k_dbg(ATH10K_DBG_BOOT, "boot waiting target to initialise\n"); ++- ++- ret = ath10k_pci_wake(ar); ++- if (ret) { ++- ath10k_err("failed to wake up target for init: %d\n", ret); ++- return ret; ++- } +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot waiting target to initialise\n"); ++ ++ timeout = jiffies + msecs_to_jiffies(ATH10K_PCI_TARGET_WAIT); ++ ++ do { ++ val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); ++ ++- ath10k_dbg(ATH10K_DBG_BOOT, "boot target indicator %x\n", val); +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target indicator %x\n", +++ val); ++ ++ /* target should never return this */ ++ if (val == 0xffffffff) ++@@ -2461,52 +2424,46 @@ static int ath10k_pci_wait_for_target_in ++ ++ if (ar_pci->num_msi_intrs == 0) ++ /* Fix potential race by repeating CORE_BASE writes */ ++- ath10k_pci_soc_write32(ar, PCIE_INTR_ENABLE_ADDRESS, ++- PCIE_INTR_FIRMWARE_MASK | ++- PCIE_INTR_CE_MASK_ALL); +++ ath10k_pci_enable_legacy_irq(ar); ++ ++ mdelay(10); ++ } while (time_before(jiffies, timeout)); ++ +++ ath10k_pci_disable_and_clear_legacy_irq(ar); +++ ath10k_pci_irq_msi_fw_mask(ar); +++ ++ if (val == 0xffffffff) { ++- ath10k_err("failed to read device register, device is gone\n"); ++- ret = -EIO; ++- goto out; +++ ath10k_err(ar, "failed to read device register, device is gone\n"); +++ return -EIO; ++ } ++ ++ if (val & FW_IND_EVENT_PENDING) { ++- ath10k_warn("device has crashed during init\n"); ++- ret = -ECOMM; ++- goto out; +++ ath10k_warn(ar, "device has crashed during init\n"); +++ return -ECOMM; ++ } ++ ++ if (!(val & FW_IND_INITIALIZED)) { ++- ath10k_err("failed to receive initialized event from target: %08x\n", +++ ath10k_err(ar, "failed to receive initialized event from target: %08x\n", ++ val); ++- ret = -ETIMEDOUT; ++- goto out; +++ return -ETIMEDOUT; ++ } ++ ++- ath10k_dbg(ATH10K_DBG_BOOT, "boot target initialised\n"); ++- ++-out: ++- ath10k_pci_sleep(ar); ++- return ret; +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target initialised\n"); +++ return 0; ++ } ++ ++ static int ath10k_pci_cold_reset(struct ath10k *ar) ++ { ++- int i, ret; +++ int i; ++ u32 val; ++ ++- ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset\n"); +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset\n"); ++ ++- ret = ath10k_do_pci_wake(ar); ++- if (ret) { ++- ath10k_err("failed to wake up target: %d\n", ++- ret); ++- return ret; ++- } +++ spin_lock_bh(&ar->data_lock); +++ +++ ar->stats.fw_cold_reset_counter++; +++ +++ spin_unlock_bh(&ar->data_lock); ++ ++ /* Put Target, including PCIe, into RESET. */ ++ val = ath10k_pci_reg_read32(ar, SOC_GLOBAL_RESET_ADDRESS); ++@@ -2531,181 +2488,227 @@ static int ath10k_pci_cold_reset(struct ++ msleep(1); ++ } ++ ++- ath10k_do_pci_sleep(ar); +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset complete\n"); +++ +++ return 0; +++} +++ +++static int ath10k_pci_claim(struct ath10k *ar) +++{ +++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); +++ struct pci_dev *pdev = ar_pci->pdev; +++ u32 lcr_val; +++ int ret; +++ +++ pci_set_drvdata(pdev, ar); +++ +++ ret = pci_enable_device(pdev); +++ if (ret) { +++ ath10k_err(ar, "failed to enable pci device: %d\n", ret); +++ return ret; +++ } +++ +++ ret = pci_request_region(pdev, BAR_NUM, "ath"); +++ if (ret) { +++ ath10k_err(ar, "failed to request region BAR%d: %d\n", BAR_NUM, +++ ret); +++ goto err_device; +++ } +++ +++ /* Target expects 32 bit DMA. Enforce it. */ +++ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); +++ if (ret) { +++ ath10k_err(ar, "failed to set dma mask to 32-bit: %d\n", ret); +++ goto err_region; +++ } +++ +++ ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); +++ if (ret) { +++ ath10k_err(ar, "failed to set consistent dma mask to 32-bit: %d\n", +++ ret); +++ goto err_region; +++ } +++ +++ pci_set_master(pdev); +++ +++ /* Workaround: Disable ASPM */ +++ pci_read_config_dword(pdev, 0x80, &lcr_val); +++ pci_write_config_dword(pdev, 0x80, (lcr_val & 0xffffff00)); ++ ++- ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset complete\n"); +++ /* Arrange for access to Target SoC registers. */ +++ ar_pci->mem = pci_iomap(pdev, BAR_NUM, 0); +++ if (!ar_pci->mem) { +++ ath10k_err(ar, "failed to iomap BAR%d\n", BAR_NUM); +++ ret = -EIO; +++ goto err_master; +++ } ++ +++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem); ++ return 0; +++ +++err_master: +++ pci_clear_master(pdev); +++ +++err_region: +++ pci_release_region(pdev, BAR_NUM); +++ +++err_device: +++ pci_disable_device(pdev); +++ +++ return ret; ++ } ++ ++-static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci) +++static void ath10k_pci_release(struct ath10k *ar) ++ { +++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); +++ struct pci_dev *pdev = ar_pci->pdev; +++ +++ pci_iounmap(pdev, ar_pci->mem); +++ pci_release_region(pdev, BAR_NUM); +++ pci_clear_master(pdev); +++ pci_disable_device(pdev); +++} +++ +++static bool ath10k_pci_chip_is_supported(u32 dev_id, u32 chip_id) +++{ +++ const struct ath10k_pci_supp_chip *supp_chip; ++ int i; +++ u32 rev_id = MS(chip_id, SOC_CHIP_ID_REV); ++ ++- for (i = 0; i < ATH10K_PCI_FEATURE_COUNT; i++) { ++- if (!test_bit(i, ar_pci->features)) ++- continue; +++ for (i = 0; i < ARRAY_SIZE(ath10k_pci_supp_chips); i++) { +++ supp_chip = &ath10k_pci_supp_chips[i]; ++ ++- switch (i) { ++- case ATH10K_PCI_FEATURE_MSI_X: ++- ath10k_dbg(ATH10K_DBG_BOOT, "device supports MSI-X\n"); ++- break; ++- case ATH10K_PCI_FEATURE_SOC_POWER_SAVE: ++- ath10k_dbg(ATH10K_DBG_BOOT, "QCA98XX SoC power save enabled\n"); ++- break; ++- } +++ if (supp_chip->dev_id == dev_id && +++ supp_chip->rev_id == rev_id) +++ return true; ++ } +++ +++ return false; ++ } ++ ++ static int ath10k_pci_probe(struct pci_dev *pdev, ++ const struct pci_device_id *pci_dev) ++ { ++- void __iomem *mem; ++ int ret = 0; ++ struct ath10k *ar; ++ struct ath10k_pci *ar_pci; ++- u32 lcr_val, chip_id; ++- ++- ath10k_dbg(ATH10K_DBG_PCI, "pci probe\n"); ++- ++- ar_pci = kzalloc(sizeof(*ar_pci), GFP_KERNEL); ++- if (ar_pci == NULL) ++- return -ENOMEM; ++- ++- ar_pci->pdev = pdev; ++- ar_pci->dev = &pdev->dev; +++ enum ath10k_hw_rev hw_rev; +++ u32 chip_id; ++ ++ switch (pci_dev->device) { ++ case QCA988X_2_0_DEVICE_ID: ++- set_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features); +++ hw_rev = ATH10K_HW_QCA988X; +++ break; +++ case QCA6174_2_1_DEVICE_ID: +++ hw_rev = ATH10K_HW_QCA6174; ++ break; ++ default: ++- ret = -ENODEV; ++- ath10k_err("Unknown device ID: %d\n", pci_dev->device); ++- goto err_ar_pci; +++ WARN_ON(1); +++ return -ENOTSUPP; ++ } ++ ++- if (ath10k_pci_target_ps) ++- set_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features); ++- ++- ath10k_pci_dump_features(ar_pci); ++- ++- ar = ath10k_core_create(ar_pci, ar_pci->dev, &ath10k_pci_hif_ops); +++ ar = ath10k_core_create(sizeof(*ar_pci), &pdev->dev, ATH10K_BUS_PCI, +++ hw_rev, &ath10k_pci_hif_ops); ++ if (!ar) { ++- ath10k_err("failed to create driver core\n"); ++- ret = -EINVAL; ++- goto err_ar_pci; +++ dev_err(&pdev->dev, "failed to allocate core\n"); +++ return -ENOMEM; ++ } ++ +++ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci probe\n"); +++ +++ ar_pci = ath10k_pci_priv(ar); +++ ar_pci->pdev = pdev; +++ ar_pci->dev = &pdev->dev; ++ ar_pci->ar = ar; ++- atomic_set(&ar_pci->keep_awake_count, 0); ++ ++- pci_set_drvdata(pdev, ar); +++ spin_lock_init(&ar_pci->ce_lock); +++ setup_timer(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry, +++ (unsigned long)ar); ++ ++- /* ++- * Without any knowledge of the Host, the Target may have been reset or ++- * power cycled and its Config Space may no longer reflect the PCI ++- * address space that was assigned earlier by the PCI infrastructure. ++- * Refresh it now. ++- */ ++- ret = pci_assign_resource(pdev, BAR_NUM); +++ ret = ath10k_pci_claim(ar); ++ if (ret) { ++- ath10k_err("failed to assign PCI space: %d\n", ret); ++- goto err_ar; +++ ath10k_err(ar, "failed to claim device: %d\n", ret); +++ goto err_core_destroy; ++ } ++ ++- ret = pci_enable_device(pdev); +++ ret = ath10k_pci_wake(ar); ++ if (ret) { ++- ath10k_err("failed to enable PCI device: %d\n", ret); ++- goto err_ar; +++ ath10k_err(ar, "failed to wake up: %d\n", ret); +++ goto err_release; ++ } ++ ++- /* Request MMIO resources */ ++- ret = pci_request_region(pdev, BAR_NUM, "ath"); +++ ret = ath10k_pci_alloc_pipes(ar); ++ if (ret) { ++- ath10k_err("failed to request MMIO region: %d\n", ret); ++- goto err_device; +++ ath10k_err(ar, "failed to allocate copy engine pipes: %d\n", +++ ret); +++ goto err_sleep; ++ } ++ ++- /* ++- * Target structures have a limit of 32 bit DMA pointers. ++- * DMA pointers can be wider than 32 bits by default on some systems. ++- */ ++- ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); ++- if (ret) { ++- ath10k_err("failed to set DMA mask to 32-bit: %d\n", ret); ++- goto err_region; ++- } +++ ath10k_pci_ce_deinit(ar); +++ ath10k_pci_irq_disable(ar); ++ ++- ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); +++ ret = ath10k_pci_init_irq(ar); ++ if (ret) { ++- ath10k_err("failed to set consistent DMA mask to 32-bit\n"); ++- goto err_region; +++ ath10k_err(ar, "failed to init irqs: %d\n", ret); +++ goto err_free_pipes; ++ } ++ ++- /* Set bus master bit in PCI_COMMAND to enable DMA */ ++- pci_set_master(pdev); ++- ++- /* ++- * Temporary FIX: disable ASPM ++- * Will be removed after the OTP is programmed ++- */ ++- pci_read_config_dword(pdev, 0x80, &lcr_val); ++- pci_write_config_dword(pdev, 0x80, (lcr_val & 0xffffff00)); +++ ath10k_info(ar, "pci irq %s interrupts %d irq_mode %d reset_mode %d\n", +++ ath10k_pci_get_irq_method(ar), ar_pci->num_msi_intrs, +++ ath10k_pci_irq_mode, ath10k_pci_reset_mode); ++ ++- /* Arrange for access to Target SoC registers. */ ++- mem = pci_iomap(pdev, BAR_NUM, 0); ++- if (!mem) { ++- ath10k_err("failed to perform IOMAP for BAR%d\n", BAR_NUM); ++- ret = -EIO; ++- goto err_master; +++ ret = ath10k_pci_request_irq(ar); +++ if (ret) { +++ ath10k_warn(ar, "failed to request irqs: %d\n", ret); +++ goto err_deinit_irq; ++ } ++ ++- ar_pci->mem = mem; ++- ++- spin_lock_init(&ar_pci->ce_lock); ++- ++- ret = ath10k_do_pci_wake(ar); +++ ret = ath10k_pci_chip_reset(ar); ++ if (ret) { ++- ath10k_err("Failed to get chip id: %d\n", ret); ++- goto err_iomap; +++ ath10k_err(ar, "failed to reset chip: %d\n", ret); +++ goto err_free_irq; ++ } ++ ++ chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); +++ if (chip_id == 0xffffffff) { +++ ath10k_err(ar, "failed to get chip id\n"); +++ goto err_free_irq; +++ } ++ ++- ath10k_do_pci_sleep(ar); ++- ++- ret = ath10k_pci_alloc_ce(ar); ++- if (ret) { ++- ath10k_err("failed to allocate copy engine pipes: %d\n", ret); ++- goto err_iomap; +++ if (!ath10k_pci_chip_is_supported(pdev->device, chip_id)) { +++ ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n", +++ pdev->device, chip_id); +++ goto err_sleep; ++ } ++ ++- ath10k_dbg(ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem); +++ ath10k_pci_sleep(ar); ++ ++ ret = ath10k_core_register(ar, chip_id); ++ if (ret) { ++- ath10k_err("failed to register driver core: %d\n", ret); ++- goto err_free_ce; +++ ath10k_err(ar, "failed to register driver core: %d\n", ret); +++ goto err_free_irq; ++ } ++ ++ return 0; ++ ++-err_free_ce: ++- ath10k_pci_free_ce(ar); ++-err_iomap: ++- pci_iounmap(pdev, mem); ++-err_master: ++- pci_clear_master(pdev); ++-err_region: ++- pci_release_region(pdev, BAR_NUM); ++-err_device: ++- pci_disable_device(pdev); ++-err_ar: +++err_free_irq: +++ ath10k_pci_free_irq(ar); +++ ath10k_pci_kill_tasklet(ar); +++ +++err_deinit_irq: +++ ath10k_pci_deinit_irq(ar); +++ +++err_free_pipes: +++ ath10k_pci_free_pipes(ar); +++ +++err_sleep: +++ ath10k_pci_sleep(ar); +++ +++err_release: +++ ath10k_pci_release(ar); +++ +++err_core_destroy: ++ ath10k_core_destroy(ar); ++-err_ar_pci: ++- /* call HIF PCI free here */ ++- kfree(ar_pci); ++ ++ return ret; ++ } ++@@ -2715,7 +2718,7 @@ static void ath10k_pci_remove(struct pci ++ struct ath10k *ar = pci_get_drvdata(pdev); ++ struct ath10k_pci *ar_pci; ++ ++- ath10k_dbg(ATH10K_DBG_PCI, "pci remove\n"); +++ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci remove\n"); ++ ++ if (!ar) ++ return; ++@@ -2725,18 +2728,14 @@ static void ath10k_pci_remove(struct pci ++ if (!ar_pci) ++ return; ++ ++- tasklet_kill(&ar_pci->msi_fw_err); ++- ++ ath10k_core_unregister(ar); ++- ath10k_pci_free_ce(ar); ++- ++- pci_iounmap(pdev, ar_pci->mem); ++- pci_release_region(pdev, BAR_NUM); ++- pci_clear_master(pdev); ++- pci_disable_device(pdev); ++- +++ ath10k_pci_free_irq(ar); +++ ath10k_pci_kill_tasklet(ar); +++ ath10k_pci_deinit_irq(ar); +++ ath10k_pci_ce_deinit(ar); +++ ath10k_pci_free_pipes(ar); +++ ath10k_pci_release(ar); ++ ath10k_core_destroy(ar); ++- kfree(ar_pci); ++ } ++ ++ MODULE_DEVICE_TABLE(pci, ath10k_pci_id_table); ++@@ -2754,7 +2753,8 @@ static int __init ath10k_pci_init(void) ++ ++ ret = pci_register_driver(&ath10k_pci_driver); ++ if (ret) ++- ath10k_err("failed to register PCI driver: %d\n", ret); +++ printk(KERN_ERR "failed to register ath10k pci driver: %d\n", +++ ret); ++ ++ return ret; ++ } ++@@ -2770,5 +2770,7 @@ module_exit(ath10k_pci_exit); ++ MODULE_AUTHOR("Qualcomm Atheros"); ++ MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices"); ++ MODULE_LICENSE("Dual BSD/GPL"); ++-MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_2_FILE); +++MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_FILE); +++MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API2_FILE); +++MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API3_FILE); ++ MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE); ++--- a/drivers/net/wireless/ath/ath10k/pci.h +++++ b/drivers/net/wireless/ath/ath10k/pci.h ++@@ -23,9 +23,6 @@ ++ #include "hw.h" ++ #include "ce.h" ++ ++-/* FW dump area */ ++-#define REG_DUMP_COUNT_QCA988X 60 ++- ++ /* ++ * maximum number of bytes that can be handled atomically by DiagRead/DiagWrite ++ */ ++@@ -38,7 +35,8 @@ ++ #define DIAG_TRANSFER_LIMIT 2048 ++ ++ struct bmi_xfer { ++- struct completion done; +++ bool tx_done; +++ bool rx_done; ++ bool wait_for_resp; ++ u32 resp_len; ++ }; ++@@ -102,12 +100,12 @@ struct pcie_state { ++ * NOTE: Structure is shared between Host software and Target firmware! ++ */ ++ struct ce_pipe_config { ++- u32 pipenum; ++- u32 pipedir; ++- u32 nentries; ++- u32 nbytes_max; ++- u32 flags; ++- u32 reserved; +++ __le32 pipenum; +++ __le32 pipedir; +++ __le32 nentries; +++ __le32 nbytes_max; +++ __le32 flags; +++ __le32 reserved; ++ }; ++ ++ /* ++@@ -129,17 +127,9 @@ struct ce_pipe_config { ++ ++ /* Establish a mapping between a service/direction and a pipe. */ ++ struct service_to_pipe { ++- u32 service_id; ++- u32 pipedir; ++- u32 pipenum; ++-}; ++- ++-enum ath10k_pci_features { ++- ATH10K_PCI_FEATURE_MSI_X = 0, ++- ATH10K_PCI_FEATURE_SOC_POWER_SAVE = 1, ++- ++- /* keep last */ ++- ATH10K_PCI_FEATURE_COUNT +++ __le32 service_id; +++ __le32 pipedir; +++ __le32 pipenum; ++ }; ++ ++ /* Per-pipe state. */ ++@@ -162,14 +152,17 @@ struct ath10k_pci_pipe { ++ struct tasklet_struct intr; ++ }; ++ +++struct ath10k_pci_supp_chip { +++ u32 dev_id; +++ u32 rev_id; +++}; +++ ++ struct ath10k_pci { ++ struct pci_dev *pdev; ++ struct device *dev; ++ struct ath10k *ar; ++ void __iomem *mem; ++ ++- DECLARE_BITMAP(features, ATH10K_PCI_FEATURE_COUNT); ++- ++ /* ++ * Number of MSI interrupts granted, 0 --> using legacy PCI line ++ * interrupts. ++@@ -178,12 +171,6 @@ struct ath10k_pci { ++ ++ struct tasklet_struct intr_tq; ++ struct tasklet_struct msi_fw_err; ++- struct tasklet_struct early_irq_tasklet; ++- ++- int started; ++- ++- atomic_t keep_awake_count; ++- bool verified_awake; ++ ++ struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX]; ++ ++@@ -197,29 +184,17 @@ struct ath10k_pci { ++ ++ /* Map CE id to ce_state */ ++ struct ath10k_ce_pipe ce_states[CE_COUNT_MAX]; +++ struct timer_list rx_post_retry; ++ }; ++ ++ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar) ++ { ++- return ar->hif.priv; ++-} ++- ++-static inline u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr) ++-{ ++- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++- ++- return ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr); ++-} ++- ++-static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val) ++-{ ++- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++- ++- iowrite32(val, ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr); +++ return (struct ath10k_pci *)ar->drv_priv; ++ } ++ +++#define ATH10K_PCI_RX_POST_RETRY_MS 50 ++ #define ATH_PCI_RESET_WAIT_MAX 10 /* ms */ ++-#define PCIE_WAKE_TIMEOUT 5000 /* 5ms */ +++#define PCIE_WAKE_TIMEOUT 10000 /* 10ms */ ++ ++ #define BAR_NUM 0 ++ ++@@ -241,35 +216,17 @@ static inline void ath10k_pci_reg_write3 ++ /* Wait up to this many Ms for a Diagnostic Access CE operation to complete */ ++ #define DIAG_ACCESS_CE_TIMEOUT_MS 10 ++ ++-/* ++- * This API allows the Host to access Target registers directly ++- * and relatively efficiently over PCIe. ++- * This allows the Host to avoid extra overhead associated with ++- * sending a message to firmware and waiting for a response message ++- * from firmware, as is done on other interconnects. ++- * ++- * Yet there is some complexity with direct accesses because the ++- * Target's power state is not known a priori. The Host must issue ++- * special PCIe reads/writes in order to explicitly wake the Target ++- * and to verify that it is awake and will remain awake. ++- * ++- * Usage: +++/* Target exposes its registers for direct access. However before host can +++ * access them it needs to make sure the target is awake (ath10k_pci_wake, +++ * ath10k_pci_wake_wait, ath10k_pci_is_awake). Once target is awake it won't go +++ * to sleep unless host tells it to (ath10k_pci_sleep). ++ * ++- * Use ath10k_pci_read32 and ath10k_pci_write32 to access Target space. ++- * These calls must be bracketed by ath10k_pci_wake and ++- * ath10k_pci_sleep. A single BEGIN/END pair is adequate for ++- * multiple READ/WRITE operations. +++ * If host tries to access target registers without waking it up it can +++ * scribble over host memory. ++ * ++- * Use ath10k_pci_wake to put the Target in a state in ++- * which it is legal for the Host to directly access it. This ++- * may involve waking the Target from a low power state, which ++- * may take up to 2Ms! ++- * ++- * Use ath10k_pci_sleep to tell the Target that as far as ++- * this code path is concerned, it no longer needs to remain ++- * directly accessible. BEGIN/END is under a reference counter; ++- * multiple code paths may issue BEGIN/END on a single targid. +++ * If target is asleep waking it up may take up to even 2ms. ++ */ +++ ++ static inline void ath10k_pci_write32(struct ath10k *ar, u32 offset, ++ u32 value) ++ { ++@@ -295,25 +252,18 @@ static inline void ath10k_pci_soc_write3 ++ ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + addr, val); ++ } ++ ++-int ath10k_do_pci_wake(struct ath10k *ar); ++-void ath10k_do_pci_sleep(struct ath10k *ar); ++- ++-static inline int ath10k_pci_wake(struct ath10k *ar) +++static inline u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr) ++ { ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++ ++- if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) ++- return ath10k_do_pci_wake(ar); ++- ++- return 0; +++ return ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr); ++ } ++ ++-static inline void ath10k_pci_sleep(struct ath10k *ar) +++static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val) ++ { ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ++ ++- if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) ++- ath10k_do_pci_sleep(ar); +++ iowrite32(val, ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr); ++ } ++ ++ #endif /* _PCI_H_ */ ++--- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++++ b/drivers/net/wireless/ath/ath10k/rx_desc.h ++@@ -839,7 +839,6 @@ struct rx_ppdu_start { ++ * Reserved: HW should fill with 0, FW should ignore. ++ */ ++ ++- ++ #define RX_PPDU_END_FLAGS_PHY_ERR (1 << 0) ++ #define RX_PPDU_END_FLAGS_RX_LOCATION (1 << 1) ++ #define RX_PPDU_END_FLAGS_TXBF_H_INFO (1 << 2) ++@@ -851,7 +850,7 @@ struct rx_ppdu_start { ++ ++ #define RX_PPDU_END_INFO1_PPDU_DONE (1 << 15) ++ ++-struct rx_ppdu_end { +++struct rx_ppdu_end_common { ++ __le32 evm_p0; ++ __le32 evm_p1; ++ __le32 evm_p2; ++@@ -874,10 +873,33 @@ struct rx_ppdu_end { ++ u8 phy_err_code; ++ __le16 flags; /* %RX_PPDU_END_FLAGS_ */ ++ __le32 info0; /* %RX_PPDU_END_INFO0_ */ +++} __packed; +++ +++struct rx_ppdu_end_qca988x { +++ __le16 bb_length; +++ __le16 info1; /* %RX_PPDU_END_INFO1_ */ +++} __packed; +++ +++#define RX_PPDU_END_RTT_CORRELATION_VALUE_MASK 0x00ffffff +++#define RX_PPDU_END_RTT_CORRELATION_VALUE_LSB 0 +++#define RX_PPDU_END_RTT_UNUSED_MASK 0x7f000000 +++#define RX_PPDU_END_RTT_UNUSED_LSB 24 +++#define RX_PPDU_END_RTT_NORMAL_MODE BIT(31) +++ +++struct rx_ppdu_end_qca6174 { +++ __le32 rtt; /* %RX_PPDU_END_RTT_ */ ++ __le16 bb_length; ++ __le16 info1; /* %RX_PPDU_END_INFO1_ */ ++ } __packed; ++ +++struct rx_ppdu_end { +++ struct rx_ppdu_end_common common; +++ union { +++ struct rx_ppdu_end_qca988x qca988x; +++ struct rx_ppdu_end_qca6174 qca6174; +++ } __packed; +++} __packed; +++ ++ /* ++ * evm_p0 ++ * EVM for pilot 0. Contain EVM for streams: 0, 1, 2 and 3. ++--- a/drivers/net/wireless/ath/ath10k/targaddrs.h +++++ b/drivers/net/wireless/ath/ath10k/targaddrs.h ++@@ -18,6 +18,8 @@ ++ #ifndef __TARGADDRS_H__ ++ #define __TARGADDRS_H__ ++ +++#include "hw.h" +++ ++ /* ++ * xxx_HOST_INTEREST_ADDRESS is the address in Target RAM of the ++ * host_interest structure. It must match the address of the _host_interest ++@@ -284,7 +286,6 @@ Fw Mode/SubMode Mask ++ #define HI_OPTION_ALL_FW_SUBMODE_MASK 0xFF00 ++ #define HI_OPTION_ALL_FW_SUBMODE_SHIFT 0x8 ++ ++- ++ /* hi_option_flag2 options */ ++ #define HI_OPTION_OFFLOAD_AMSDU 0x01 ++ #define HI_OPTION_DFS_SUPPORT 0x02 /* Enable DFS support */ ++@@ -446,4 +447,7 @@ Fw Mode/SubMode Mask ++ #define QCA988X_BOARD_DATA_SZ 7168 ++ #define QCA988X_BOARD_EXT_DATA_SZ 0 ++ +++#define QCA6174_BOARD_DATA_SZ 8192 +++#define QCA6174_BOARD_EXT_DATA_SZ 0 +++ ++ #endif /* __TARGADDRS_H__ */ ++--- a/drivers/net/wireless/ath/ath10k/trace.h +++++ b/drivers/net/wireless/ath/ath10k/trace.h ++@@ -18,6 +18,16 @@ ++ #if !defined(_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) ++ ++ #include +++#include "core.h" +++ +++#if !defined(_TRACE_H_) +++static inline u32 ath10k_frm_hdr_len(const void *buf) +++{ +++ const struct ieee80211_hdr *hdr = buf; +++ +++ return ieee80211_hdrlen(hdr->frame_control); +++} +++#endif ++ ++ #define _TRACE_H_ ++ ++@@ -39,59 +49,79 @@ static inline void trace_ ## name(proto) ++ #define ATH10K_MSG_MAX 200 ++ ++ DECLARE_EVENT_CLASS(ath10k_log_event, ++- TP_PROTO(struct va_format *vaf), ++- TP_ARGS(vaf), +++ TP_PROTO(struct ath10k *ar, struct va_format *vaf), +++ TP_ARGS(ar, vaf), ++ TP_STRUCT__entry( +++ __string(device, dev_name(ar->dev)) +++ __string(driver, dev_driver_string(ar->dev)) ++ __dynamic_array(char, msg, ATH10K_MSG_MAX) ++ ), ++ TP_fast_assign( +++ __assign_str(device, dev_name(ar->dev)); +++ __assign_str(driver, dev_driver_string(ar->dev)); ++ WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), ++ ATH10K_MSG_MAX, ++ vaf->fmt, ++ *vaf->va) >= ATH10K_MSG_MAX); ++ ), ++- TP_printk("%s", __get_str(msg)) +++ TP_printk( +++ "%s %s %s", +++ __get_str(driver), +++ __get_str(device), +++ __get_str(msg) +++ ) ++ ); ++ ++ DEFINE_EVENT(ath10k_log_event, ath10k_log_err, ++- TP_PROTO(struct va_format *vaf), ++- TP_ARGS(vaf) +++ TP_PROTO(struct ath10k *ar, struct va_format *vaf), +++ TP_ARGS(ar, vaf) ++ ); ++ ++ DEFINE_EVENT(ath10k_log_event, ath10k_log_warn, ++- TP_PROTO(struct va_format *vaf), ++- TP_ARGS(vaf) +++ TP_PROTO(struct ath10k *ar, struct va_format *vaf), +++ TP_ARGS(ar, vaf) ++ ); ++ ++ DEFINE_EVENT(ath10k_log_event, ath10k_log_info, ++- TP_PROTO(struct va_format *vaf), ++- TP_ARGS(vaf) +++ TP_PROTO(struct ath10k *ar, struct va_format *vaf), +++ TP_ARGS(ar, vaf) ++ ); ++ ++ TRACE_EVENT(ath10k_log_dbg, ++- TP_PROTO(unsigned int level, struct va_format *vaf), ++- TP_ARGS(level, vaf), +++ TP_PROTO(struct ath10k *ar, unsigned int level, struct va_format *vaf), +++ TP_ARGS(ar, level, vaf), ++ TP_STRUCT__entry( +++ __string(device, dev_name(ar->dev)) +++ __string(driver, dev_driver_string(ar->dev)) ++ __field(unsigned int, level) ++ __dynamic_array(char, msg, ATH10K_MSG_MAX) ++ ), ++ TP_fast_assign( +++ __assign_str(device, dev_name(ar->dev)); +++ __assign_str(driver, dev_driver_string(ar->dev)); ++ __entry->level = level; ++ WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), ++ ATH10K_MSG_MAX, ++ vaf->fmt, ++ *vaf->va) >= ATH10K_MSG_MAX); ++ ), ++- TP_printk("%s", __get_str(msg)) +++ TP_printk( +++ "%s %s %s", +++ __get_str(driver), +++ __get_str(device), +++ __get_str(msg) +++ ) ++ ); ++ ++ TRACE_EVENT(ath10k_log_dbg_dump, ++- TP_PROTO(const char *msg, const char *prefix, +++ TP_PROTO(struct ath10k *ar, const char *msg, const char *prefix, ++ const void *buf, size_t buf_len), ++ ++- TP_ARGS(msg, prefix, buf, buf_len), +++ TP_ARGS(ar, msg, prefix, buf, buf_len), ++ ++ TP_STRUCT__entry( +++ __string(device, dev_name(ar->dev)) +++ __string(driver, dev_driver_string(ar->dev)) ++ __string(msg, msg) ++ __string(prefix, prefix) ++ __field(size_t, buf_len) ++@@ -99,6 +129,8 @@ TRACE_EVENT(ath10k_log_dbg_dump, ++ ), ++ ++ TP_fast_assign( +++ __assign_str(device, dev_name(ar->dev)); +++ __assign_str(driver, dev_driver_string(ar->dev)); ++ __assign_str(msg, msg); ++ __assign_str(prefix, prefix); ++ __entry->buf_len = buf_len; ++@@ -106,16 +138,23 @@ TRACE_EVENT(ath10k_log_dbg_dump, ++ ), ++ ++ TP_printk( ++- "%s/%s\n", __get_str(prefix), __get_str(msg) +++ "%s %s %s/%s\n", +++ __get_str(driver), +++ __get_str(device), +++ __get_str(prefix), +++ __get_str(msg) ++ ) ++ ); ++ ++ TRACE_EVENT(ath10k_wmi_cmd, ++- TP_PROTO(int id, void *buf, size_t buf_len, int ret), +++ TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len, +++ int ret), ++ ++- TP_ARGS(id, buf, buf_len, ret), +++ TP_ARGS(ar, id, buf, buf_len, ret), ++ ++ TP_STRUCT__entry( +++ __string(device, dev_name(ar->dev)) +++ __string(driver, dev_driver_string(ar->dev)) ++ __field(unsigned int, id) ++ __field(size_t, buf_len) ++ __dynamic_array(u8, buf, buf_len) ++@@ -123,6 +162,8 @@ TRACE_EVENT(ath10k_wmi_cmd, ++ ), ++ ++ TP_fast_assign( +++ __assign_str(device, dev_name(ar->dev)); +++ __assign_str(driver, dev_driver_string(ar->dev)); ++ __entry->id = id; ++ __entry->buf_len = buf_len; ++ __entry->ret = ret; ++@@ -130,7 +171,9 @@ TRACE_EVENT(ath10k_wmi_cmd, ++ ), ++ ++ TP_printk( ++- "id %d len %zu ret %d", +++ "%s %s id %d len %zu ret %d", +++ __get_str(driver), +++ __get_str(device), ++ __entry->id, ++ __entry->buf_len, ++ __entry->ret ++@@ -138,71 +181,346 @@ TRACE_EVENT(ath10k_wmi_cmd, ++ ); ++ ++ TRACE_EVENT(ath10k_wmi_event, ++- TP_PROTO(int id, void *buf, size_t buf_len), +++ TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len), ++ ++- TP_ARGS(id, buf, buf_len), +++ TP_ARGS(ar, id, buf, buf_len), ++ ++ TP_STRUCT__entry( +++ __string(device, dev_name(ar->dev)) +++ __string(driver, dev_driver_string(ar->dev)) ++ __field(unsigned int, id) ++ __field(size_t, buf_len) ++ __dynamic_array(u8, buf, buf_len) ++ ), ++ ++ TP_fast_assign( +++ __assign_str(device, dev_name(ar->dev)); +++ __assign_str(driver, dev_driver_string(ar->dev)); ++ __entry->id = id; ++ __entry->buf_len = buf_len; ++ memcpy(__get_dynamic_array(buf), buf, buf_len); ++ ), ++ ++ TP_printk( ++- "id %d len %zu", +++ "%s %s id %d len %zu", +++ __get_str(driver), +++ __get_str(device), ++ __entry->id, ++ __entry->buf_len ++ ) ++ ); ++ ++ TRACE_EVENT(ath10k_htt_stats, ++- TP_PROTO(void *buf, size_t buf_len), +++ TP_PROTO(struct ath10k *ar, const void *buf, size_t buf_len), ++ ++- TP_ARGS(buf, buf_len), +++ TP_ARGS(ar, buf, buf_len), ++ ++ TP_STRUCT__entry( +++ __string(device, dev_name(ar->dev)) +++ __string(driver, dev_driver_string(ar->dev)) ++ __field(size_t, buf_len) ++ __dynamic_array(u8, buf, buf_len) ++ ), ++ ++ TP_fast_assign( +++ __assign_str(device, dev_name(ar->dev)); +++ __assign_str(driver, dev_driver_string(ar->dev)); ++ __entry->buf_len = buf_len; ++ memcpy(__get_dynamic_array(buf), buf, buf_len); ++ ), ++ ++ TP_printk( ++- "len %zu", +++ "%s %s len %zu", +++ __get_str(driver), +++ __get_str(device), ++ __entry->buf_len ++ ) ++ ); ++ ++ TRACE_EVENT(ath10k_wmi_dbglog, ++- TP_PROTO(void *buf, size_t buf_len), +++ TP_PROTO(struct ath10k *ar, const void *buf, size_t buf_len), ++ ++- TP_ARGS(buf, buf_len), +++ TP_ARGS(ar, buf, buf_len), ++ ++ TP_STRUCT__entry( +++ __string(device, dev_name(ar->dev)) +++ __string(driver, dev_driver_string(ar->dev)) ++ __field(size_t, buf_len) ++ __dynamic_array(u8, buf, buf_len) ++ ), ++ ++ TP_fast_assign( +++ __assign_str(device, dev_name(ar->dev)); +++ __assign_str(driver, dev_driver_string(ar->dev)); ++ __entry->buf_len = buf_len; ++ memcpy(__get_dynamic_array(buf), buf, buf_len); ++ ), ++ ++ TP_printk( ++- "len %zu", +++ "%s %s len %zu", +++ __get_str(driver), +++ __get_str(device), ++ __entry->buf_len ++ ) ++ ); ++ +++TRACE_EVENT(ath10k_htt_pktlog, +++ TP_PROTO(struct ath10k *ar, const void *buf, u16 buf_len), +++ +++ TP_ARGS(ar, buf, buf_len), +++ +++ TP_STRUCT__entry( +++ __string(device, dev_name(ar->dev)) +++ __string(driver, dev_driver_string(ar->dev)) +++ __field(u16, buf_len) +++ __dynamic_array(u8, pktlog, buf_len) +++ ), +++ +++ TP_fast_assign( +++ __assign_str(device, dev_name(ar->dev)); +++ __assign_str(driver, dev_driver_string(ar->dev)); +++ __entry->buf_len = buf_len; +++ memcpy(__get_dynamic_array(pktlog), buf, buf_len); +++ ), +++ +++ TP_printk( +++ "%s %s size %hu", +++ __get_str(driver), +++ __get_str(device), +++ __entry->buf_len +++ ) +++); +++ +++TRACE_EVENT(ath10k_htt_tx, +++ TP_PROTO(struct ath10k *ar, u16 msdu_id, u16 msdu_len, +++ u8 vdev_id, u8 tid), +++ +++ TP_ARGS(ar, msdu_id, msdu_len, vdev_id, tid), +++ +++ TP_STRUCT__entry( +++ __string(device, dev_name(ar->dev)) +++ __string(driver, dev_driver_string(ar->dev)) +++ __field(u16, msdu_id) +++ __field(u16, msdu_len) +++ __field(u8, vdev_id) +++ __field(u8, tid) +++ ), +++ +++ TP_fast_assign( +++ __assign_str(device, dev_name(ar->dev)); +++ __assign_str(driver, dev_driver_string(ar->dev)); +++ __entry->msdu_id = msdu_id; +++ __entry->msdu_len = msdu_len; +++ __entry->vdev_id = vdev_id; +++ __entry->tid = tid; +++ ), +++ +++ TP_printk( +++ "%s %s msdu_id %d msdu_len %d vdev_id %d tid %d", +++ __get_str(driver), +++ __get_str(device), +++ __entry->msdu_id, +++ __entry->msdu_len, +++ __entry->vdev_id, +++ __entry->tid +++ ) +++); +++ +++TRACE_EVENT(ath10k_txrx_tx_unref, +++ TP_PROTO(struct ath10k *ar, u16 msdu_id), +++ +++ TP_ARGS(ar, msdu_id), +++ +++ TP_STRUCT__entry( +++ __string(device, dev_name(ar->dev)) +++ __string(driver, dev_driver_string(ar->dev)) +++ __field(u16, msdu_id) +++ ), +++ +++ TP_fast_assign( +++ __assign_str(device, dev_name(ar->dev)); +++ __assign_str(driver, dev_driver_string(ar->dev)); +++ __entry->msdu_id = msdu_id; +++ ), +++ +++ TP_printk( +++ "%s %s msdu_id %d", +++ __get_str(driver), +++ __get_str(device), +++ __entry->msdu_id +++ ) +++); +++ +++DECLARE_EVENT_CLASS(ath10k_hdr_event, +++ TP_PROTO(struct ath10k *ar, const void *data, size_t len), +++ +++ TP_ARGS(ar, data, len), +++ +++ TP_STRUCT__entry( +++ __string(device, dev_name(ar->dev)) +++ __string(driver, dev_driver_string(ar->dev)) +++ __field(size_t, len) +++ __dynamic_array(u8, data, ath10k_frm_hdr_len(data)) +++ ), +++ +++ TP_fast_assign( +++ __assign_str(device, dev_name(ar->dev)); +++ __assign_str(driver, dev_driver_string(ar->dev)); +++ __entry->len = ath10k_frm_hdr_len(data); +++ memcpy(__get_dynamic_array(data), data, __entry->len); +++ ), +++ +++ TP_printk( +++ "%s %s len %zu\n", +++ __get_str(driver), +++ __get_str(device), +++ __entry->len +++ ) +++); +++ +++DECLARE_EVENT_CLASS(ath10k_payload_event, +++ TP_PROTO(struct ath10k *ar, const void *data, size_t len), +++ +++ TP_ARGS(ar, data, len), +++ +++ TP_STRUCT__entry( +++ __string(device, dev_name(ar->dev)) +++ __string(driver, dev_driver_string(ar->dev)) +++ __field(size_t, len) +++ __dynamic_array(u8, payload, (len - ath10k_frm_hdr_len(data))) +++ ), +++ +++ TP_fast_assign( +++ __assign_str(device, dev_name(ar->dev)); +++ __assign_str(driver, dev_driver_string(ar->dev)); +++ __entry->len = len - ath10k_frm_hdr_len(data); +++ memcpy(__get_dynamic_array(payload), +++ data + ath10k_frm_hdr_len(data), __entry->len); +++ ), +++ +++ TP_printk( +++ "%s %s len %zu\n", +++ __get_str(driver), +++ __get_str(device), +++ __entry->len +++ ) +++); +++ +++DEFINE_EVENT(ath10k_hdr_event, ath10k_tx_hdr, +++ TP_PROTO(struct ath10k *ar, const void *data, size_t len), +++ TP_ARGS(ar, data, len) +++); +++ +++DEFINE_EVENT(ath10k_payload_event, ath10k_tx_payload, +++ TP_PROTO(struct ath10k *ar, const void *data, size_t len), +++ TP_ARGS(ar, data, len) +++); +++ +++DEFINE_EVENT(ath10k_hdr_event, ath10k_rx_hdr, +++ TP_PROTO(struct ath10k *ar, const void *data, size_t len), +++ TP_ARGS(ar, data, len) +++); +++ +++DEFINE_EVENT(ath10k_payload_event, ath10k_rx_payload, +++ TP_PROTO(struct ath10k *ar, const void *data, size_t len), +++ TP_ARGS(ar, data, len) +++); +++ +++TRACE_EVENT(ath10k_htt_rx_desc, +++ TP_PROTO(struct ath10k *ar, const void *data, size_t len), +++ +++ TP_ARGS(ar, data, len), +++ +++ TP_STRUCT__entry( +++ __string(device, dev_name(ar->dev)) +++ __string(driver, dev_driver_string(ar->dev)) +++ __field(u16, len) +++ __dynamic_array(u8, rxdesc, len) +++ ), +++ +++ TP_fast_assign( +++ __assign_str(device, dev_name(ar->dev)); +++ __assign_str(driver, dev_driver_string(ar->dev)); +++ __entry->len = len; +++ memcpy(__get_dynamic_array(rxdesc), data, len); +++ ), +++ +++ TP_printk( +++ "%s %s rxdesc len %d", +++ __get_str(driver), +++ __get_str(device), +++ __entry->len +++ ) +++); +++ +++TRACE_EVENT(ath10k_wmi_diag_container, +++ TP_PROTO(struct ath10k *ar, +++ u8 type, +++ u32 timestamp, +++ u32 code, +++ u16 len, +++ const void *data), +++ +++ TP_ARGS(ar, type, timestamp, code, len, data), +++ +++ TP_STRUCT__entry( +++ __string(device, dev_name(ar->dev)) +++ __string(driver, dev_driver_string(ar->dev)) +++ __field(u8, type) +++ __field(u32, timestamp) +++ __field(u32, code) +++ __field(u16, len) +++ __dynamic_array(u8, data, len) +++ ), +++ +++ TP_fast_assign( +++ __assign_str(device, dev_name(ar->dev)); +++ __assign_str(driver, dev_driver_string(ar->dev)); +++ __entry->type = type; +++ __entry->timestamp = timestamp; +++ __entry->code = code; +++ __entry->len = len; +++ memcpy(__get_dynamic_array(data), data, len); +++ ), +++ +++ TP_printk( +++ "%s %s diag container type %hhu timestamp %u code %u len %d", +++ __get_str(driver), +++ __get_str(device), +++ __entry->type, +++ __entry->timestamp, +++ __entry->code, +++ __entry->len +++ ) +++); +++ +++TRACE_EVENT(ath10k_wmi_diag, +++ TP_PROTO(struct ath10k *ar, const void *data, size_t len), +++ +++ TP_ARGS(ar, data, len), +++ +++ TP_STRUCT__entry( +++ __string(device, dev_name(ar->dev)) +++ __string(driver, dev_driver_string(ar->dev)) +++ __field(u16, len) +++ __dynamic_array(u8, data, len) +++ ), +++ +++ TP_fast_assign( +++ __assign_str(device, dev_name(ar->dev)); +++ __assign_str(driver, dev_driver_string(ar->dev)); +++ __entry->len = len; +++ memcpy(__get_dynamic_array(data), data, len); +++ ), +++ +++ TP_printk( +++ "%s %s tlv diag len %d", +++ __get_str(driver), +++ __get_str(device), +++ __entry->len +++ ) +++); +++ ++ #endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/ ++ ++ /* we don't want to use include/trace/events */ ++--- a/drivers/net/wireless/ath/ath10k/txrx.c +++++ b/drivers/net/wireless/ath/ath10k/txrx.c ++@@ -32,14 +32,14 @@ static void ath10k_report_offchan_tx(str ++ * offchan_tx_skb. */ ++ spin_lock_bh(&ar->data_lock); ++ if (ar->offchan_tx_skb != skb) { ++- ath10k_warn("completed old offchannel frame\n"); +++ ath10k_warn(ar, "completed old offchannel frame\n"); ++ goto out; ++ } ++ ++ complete(&ar->offchan_tx_completed); ++ ar->offchan_tx_skb = NULL; /* just for sanity */ ++ ++- ath10k_dbg(ATH10K_DBG_HTT, "completed offchannel skb %p\n", skb); +++ ath10k_dbg(ar, ATH10K_DBG_HTT, "completed offchannel skb %p\n", skb); ++ out: ++ spin_unlock_bh(&ar->data_lock); ++ } ++@@ -47,23 +47,30 @@ out: ++ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, ++ const struct htt_tx_done *tx_done) ++ { ++- struct device *dev = htt->ar->dev; +++ struct ath10k *ar = htt->ar; +++ struct device *dev = ar->dev; ++ struct ieee80211_tx_info *info; ++ struct ath10k_skb_cb *skb_cb; ++ struct sk_buff *msdu; ++ ++ lockdep_assert_held(&htt->tx_lock); ++ ++- ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n", +++ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n", ++ tx_done->msdu_id, !!tx_done->discard, !!tx_done->no_ack); ++ ++ if (tx_done->msdu_id >= htt->max_num_pending_tx) { ++- ath10k_warn("warning: msdu_id %d too big, ignoring\n", +++ ath10k_warn(ar, "warning: msdu_id %d too big, ignoring\n", +++ tx_done->msdu_id); +++ return; +++ } +++ +++ msdu = idr_find(&htt->pending_tx, tx_done->msdu_id); +++ if (!msdu) { +++ ath10k_warn(ar, "received tx completion for invalid msdu_id: %d\n", ++ tx_done->msdu_id); ++ return; ++ } ++ ++- msdu = htt->pending_tx[tx_done->msdu_id]; ++ skb_cb = ATH10K_SKB_CB(msdu); ++ ++ dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); ++@@ -77,6 +84,7 @@ void ath10k_txrx_tx_unref(struct ath10k_ ++ ++ info = IEEE80211_SKB_CB(msdu); ++ memset(&info->status, 0, sizeof(info->status)); +++ trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id); ++ ++ if (tx_done->discard) { ++ ieee80211_free_txskb(htt->ar->hw, msdu); ++@@ -93,7 +101,6 @@ void ath10k_txrx_tx_unref(struct ath10k_ ++ /* we do not own the msdu anymore */ ++ ++ exit: ++- htt->pending_tx[tx_done->msdu_id] = NULL; ++ ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id); ++ __ath10k_htt_tx_dec_pending(htt); ++ if (htt->num_pending_tx == 0) ++@@ -119,8 +126,7 @@ struct ath10k_peer *ath10k_peer_find(str ++ return NULL; ++ } ++ ++-static struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, ++- int peer_id) +++struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, int peer_id) ++ { ++ struct ath10k_peer *peer; ++ ++@@ -145,7 +151,8 @@ static int ath10k_wait_for_peer_common(s ++ mapped = !!ath10k_peer_find(ar, vdev_id, addr); ++ spin_unlock_bh(&ar->data_lock); ++ ++- mapped == expect_mapped; +++ (mapped == expect_mapped || +++ test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)); ++ }), 3*HZ); ++ ++ if (ret <= 0) ++@@ -178,12 +185,12 @@ void ath10k_peer_map_event(struct ath10k ++ goto exit; ++ ++ peer->vdev_id = ev->vdev_id; ++- memcpy(peer->addr, ev->addr, ETH_ALEN); +++ ether_addr_copy(peer->addr, ev->addr); ++ list_add(&peer->list, &ar->peers); ++ wake_up(&ar->peer_mapping_wq); ++ } ++ ++- ath10k_dbg(ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n", +++ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n", ++ ev->vdev_id, ev->addr, ev->peer_id); ++ ++ set_bit(ev->peer_id, peer->peer_ids); ++@@ -200,12 +207,12 @@ void ath10k_peer_unmap_event(struct ath1 ++ spin_lock_bh(&ar->data_lock); ++ peer = ath10k_peer_find_by_id(ar, ev->peer_id); ++ if (!peer) { ++- ath10k_warn("peer-unmap-event: unknown peer id %d\n", +++ ath10k_warn(ar, "peer-unmap-event: unknown peer id %d\n", ++ ev->peer_id); ++ goto exit; ++ } ++ ++- ath10k_dbg(ATH10K_DBG_HTT, "htt peer unmap vdev %d peer %pM id %d\n", +++ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer unmap vdev %d peer %pM id %d\n", ++ peer->vdev_id, peer->addr, ev->peer_id); ++ ++ clear_bit(ev->peer_id, peer->peer_ids); ++--- a/drivers/net/wireless/ath/ath10k/txrx.h +++++ b/drivers/net/wireless/ath/ath10k/txrx.h ++@@ -24,6 +24,7 @@ void ath10k_txrx_tx_unref(struct ath10k_ ++ ++ struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id, ++ const u8 *addr); +++struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, int peer_id); ++ int ath10k_wait_for_peer_created(struct ath10k *ar, int vdev_id, ++ const u8 *addr); ++ int ath10k_wait_for_peer_deleted(struct ath10k *ar, int vdev_id, ++--- a/drivers/net/wireless/ath/ath10k/wmi.c +++++ b/drivers/net/wireless/ath/ath10k/wmi.c ++@@ -22,7 +22,10 @@ ++ #include "htc.h" ++ #include "debug.h" ++ #include "wmi.h" +++#include "wmi-tlv.h" ++ #include "mac.h" +++#include "testmode.h" +++#include "wmi-ops.h" ++ ++ /* MAIN WMI cmd track */ ++ static struct wmi_cmd_map wmi_cmd_map = { ++@@ -142,6 +145,7 @@ static struct wmi_cmd_map wmi_cmd_map = ++ .force_fw_hang_cmdid = WMI_FORCE_FW_HANG_CMDID, ++ .gpio_config_cmdid = WMI_GPIO_CONFIG_CMDID, ++ .gpio_output_cmdid = WMI_GPIO_OUTPUT_CMDID, +++ .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED, ++ }; ++ ++ /* 10.X WMI cmd track */ ++@@ -264,6 +268,129 @@ static struct wmi_cmd_map wmi_10x_cmd_ma ++ .force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED, ++ .gpio_config_cmdid = WMI_10X_GPIO_CONFIG_CMDID, ++ .gpio_output_cmdid = WMI_10X_GPIO_OUTPUT_CMDID, +++ .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED, +++}; +++ +++/* 10.2.4 WMI cmd track */ +++static struct wmi_cmd_map wmi_10_2_4_cmd_map = { +++ .init_cmdid = WMI_10_2_INIT_CMDID, +++ .start_scan_cmdid = WMI_10_2_START_SCAN_CMDID, +++ .stop_scan_cmdid = WMI_10_2_STOP_SCAN_CMDID, +++ .scan_chan_list_cmdid = WMI_10_2_SCAN_CHAN_LIST_CMDID, +++ .scan_sch_prio_tbl_cmdid = WMI_CMD_UNSUPPORTED, +++ .pdev_set_regdomain_cmdid = WMI_10_2_PDEV_SET_REGDOMAIN_CMDID, +++ .pdev_set_channel_cmdid = WMI_10_2_PDEV_SET_CHANNEL_CMDID, +++ .pdev_set_param_cmdid = WMI_10_2_PDEV_SET_PARAM_CMDID, +++ .pdev_pktlog_enable_cmdid = WMI_10_2_PDEV_PKTLOG_ENABLE_CMDID, +++ .pdev_pktlog_disable_cmdid = WMI_10_2_PDEV_PKTLOG_DISABLE_CMDID, +++ .pdev_set_wmm_params_cmdid = WMI_10_2_PDEV_SET_WMM_PARAMS_CMDID, +++ .pdev_set_ht_cap_ie_cmdid = WMI_10_2_PDEV_SET_HT_CAP_IE_CMDID, +++ .pdev_set_vht_cap_ie_cmdid = WMI_10_2_PDEV_SET_VHT_CAP_IE_CMDID, +++ .pdev_set_quiet_mode_cmdid = WMI_10_2_PDEV_SET_QUIET_MODE_CMDID, +++ .pdev_green_ap_ps_enable_cmdid = WMI_10_2_PDEV_GREEN_AP_PS_ENABLE_CMDID, +++ .pdev_get_tpc_config_cmdid = WMI_10_2_PDEV_GET_TPC_CONFIG_CMDID, +++ .pdev_set_base_macaddr_cmdid = WMI_10_2_PDEV_SET_BASE_MACADDR_CMDID, +++ .vdev_create_cmdid = WMI_10_2_VDEV_CREATE_CMDID, +++ .vdev_delete_cmdid = WMI_10_2_VDEV_DELETE_CMDID, +++ .vdev_start_request_cmdid = WMI_10_2_VDEV_START_REQUEST_CMDID, +++ .vdev_restart_request_cmdid = WMI_10_2_VDEV_RESTART_REQUEST_CMDID, +++ .vdev_up_cmdid = WMI_10_2_VDEV_UP_CMDID, +++ .vdev_stop_cmdid = WMI_10_2_VDEV_STOP_CMDID, +++ .vdev_down_cmdid = WMI_10_2_VDEV_DOWN_CMDID, +++ .vdev_set_param_cmdid = WMI_10_2_VDEV_SET_PARAM_CMDID, +++ .vdev_install_key_cmdid = WMI_10_2_VDEV_INSTALL_KEY_CMDID, +++ .peer_create_cmdid = WMI_10_2_PEER_CREATE_CMDID, +++ .peer_delete_cmdid = WMI_10_2_PEER_DELETE_CMDID, +++ .peer_flush_tids_cmdid = WMI_10_2_PEER_FLUSH_TIDS_CMDID, +++ .peer_set_param_cmdid = WMI_10_2_PEER_SET_PARAM_CMDID, +++ .peer_assoc_cmdid = WMI_10_2_PEER_ASSOC_CMDID, +++ .peer_add_wds_entry_cmdid = WMI_10_2_PEER_ADD_WDS_ENTRY_CMDID, +++ .peer_remove_wds_entry_cmdid = WMI_10_2_PEER_REMOVE_WDS_ENTRY_CMDID, +++ .peer_mcast_group_cmdid = WMI_10_2_PEER_MCAST_GROUP_CMDID, +++ .bcn_tx_cmdid = WMI_10_2_BCN_TX_CMDID, +++ .pdev_send_bcn_cmdid = WMI_10_2_PDEV_SEND_BCN_CMDID, +++ .bcn_tmpl_cmdid = WMI_CMD_UNSUPPORTED, +++ .bcn_filter_rx_cmdid = WMI_10_2_BCN_FILTER_RX_CMDID, +++ .prb_req_filter_rx_cmdid = WMI_10_2_PRB_REQ_FILTER_RX_CMDID, +++ .mgmt_tx_cmdid = WMI_10_2_MGMT_TX_CMDID, +++ .prb_tmpl_cmdid = WMI_CMD_UNSUPPORTED, +++ .addba_clear_resp_cmdid = WMI_10_2_ADDBA_CLEAR_RESP_CMDID, +++ .addba_send_cmdid = WMI_10_2_ADDBA_SEND_CMDID, +++ .addba_status_cmdid = WMI_10_2_ADDBA_STATUS_CMDID, +++ .delba_send_cmdid = WMI_10_2_DELBA_SEND_CMDID, +++ .addba_set_resp_cmdid = WMI_10_2_ADDBA_SET_RESP_CMDID, +++ .send_singleamsdu_cmdid = WMI_10_2_SEND_SINGLEAMSDU_CMDID, +++ .sta_powersave_mode_cmdid = WMI_10_2_STA_POWERSAVE_MODE_CMDID, +++ .sta_powersave_param_cmdid = WMI_10_2_STA_POWERSAVE_PARAM_CMDID, +++ .sta_mimo_ps_mode_cmdid = WMI_10_2_STA_MIMO_PS_MODE_CMDID, +++ .pdev_dfs_enable_cmdid = WMI_10_2_PDEV_DFS_ENABLE_CMDID, +++ .pdev_dfs_disable_cmdid = WMI_10_2_PDEV_DFS_DISABLE_CMDID, +++ .roam_scan_mode = WMI_10_2_ROAM_SCAN_MODE, +++ .roam_scan_rssi_threshold = WMI_10_2_ROAM_SCAN_RSSI_THRESHOLD, +++ .roam_scan_period = WMI_10_2_ROAM_SCAN_PERIOD, +++ .roam_scan_rssi_change_threshold = +++ WMI_10_2_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, +++ .roam_ap_profile = WMI_10_2_ROAM_AP_PROFILE, +++ .ofl_scan_add_ap_profile = WMI_10_2_OFL_SCAN_ADD_AP_PROFILE, +++ .ofl_scan_remove_ap_profile = WMI_10_2_OFL_SCAN_REMOVE_AP_PROFILE, +++ .ofl_scan_period = WMI_10_2_OFL_SCAN_PERIOD, +++ .p2p_dev_set_device_info = WMI_10_2_P2P_DEV_SET_DEVICE_INFO, +++ .p2p_dev_set_discoverability = WMI_10_2_P2P_DEV_SET_DISCOVERABILITY, +++ .p2p_go_set_beacon_ie = WMI_10_2_P2P_GO_SET_BEACON_IE, +++ .p2p_go_set_probe_resp_ie = WMI_10_2_P2P_GO_SET_PROBE_RESP_IE, +++ .p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED, +++ .ap_ps_peer_param_cmdid = WMI_10_2_AP_PS_PEER_PARAM_CMDID, +++ .ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED, +++ .peer_rate_retry_sched_cmdid = WMI_10_2_PEER_RATE_RETRY_SCHED_CMDID, +++ .wlan_profile_trigger_cmdid = WMI_10_2_WLAN_PROFILE_TRIGGER_CMDID, +++ .wlan_profile_set_hist_intvl_cmdid = +++ WMI_10_2_WLAN_PROFILE_SET_HIST_INTVL_CMDID, +++ .wlan_profile_get_profile_data_cmdid = +++ WMI_10_2_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, +++ .wlan_profile_enable_profile_id_cmdid = +++ WMI_10_2_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, +++ .wlan_profile_list_profile_id_cmdid = +++ WMI_10_2_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, +++ .pdev_suspend_cmdid = WMI_10_2_PDEV_SUSPEND_CMDID, +++ .pdev_resume_cmdid = WMI_10_2_PDEV_RESUME_CMDID, +++ .add_bcn_filter_cmdid = WMI_10_2_ADD_BCN_FILTER_CMDID, +++ .rmv_bcn_filter_cmdid = WMI_10_2_RMV_BCN_FILTER_CMDID, +++ .wow_add_wake_pattern_cmdid = WMI_10_2_WOW_ADD_WAKE_PATTERN_CMDID, +++ .wow_del_wake_pattern_cmdid = WMI_10_2_WOW_DEL_WAKE_PATTERN_CMDID, +++ .wow_enable_disable_wake_event_cmdid = +++ WMI_10_2_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, +++ .wow_enable_cmdid = WMI_10_2_WOW_ENABLE_CMDID, +++ .wow_hostwakeup_from_sleep_cmdid = +++ WMI_10_2_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, +++ .rtt_measreq_cmdid = WMI_10_2_RTT_MEASREQ_CMDID, +++ .rtt_tsf_cmdid = WMI_10_2_RTT_TSF_CMDID, +++ .vdev_spectral_scan_configure_cmdid = +++ WMI_10_2_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID, +++ .vdev_spectral_scan_enable_cmdid = +++ WMI_10_2_VDEV_SPECTRAL_SCAN_ENABLE_CMDID, +++ .request_stats_cmdid = WMI_10_2_REQUEST_STATS_CMDID, +++ .set_arp_ns_offload_cmdid = WMI_CMD_UNSUPPORTED, +++ .network_list_offload_config_cmdid = WMI_CMD_UNSUPPORTED, +++ .gtk_offload_cmdid = WMI_CMD_UNSUPPORTED, +++ .csa_offload_enable_cmdid = WMI_CMD_UNSUPPORTED, +++ .csa_offload_chanswitch_cmdid = WMI_CMD_UNSUPPORTED, +++ .chatter_set_mode_cmdid = WMI_CMD_UNSUPPORTED, +++ .peer_tid_addba_cmdid = WMI_CMD_UNSUPPORTED, +++ .peer_tid_delba_cmdid = WMI_CMD_UNSUPPORTED, +++ .sta_dtim_ps_method_cmdid = WMI_CMD_UNSUPPORTED, +++ .sta_uapsd_auto_trig_cmdid = WMI_CMD_UNSUPPORTED, +++ .sta_keepalive_cmd = WMI_CMD_UNSUPPORTED, +++ .echo_cmdid = WMI_10_2_ECHO_CMDID, +++ .pdev_utf_cmdid = WMI_10_2_PDEV_UTF_CMDID, +++ .dbglog_cfg_cmdid = WMI_10_2_DBGLOG_CFG_CMDID, +++ .pdev_qvit_cmdid = WMI_10_2_PDEV_QVIT_CMDID, +++ .pdev_ftm_intg_cmdid = WMI_CMD_UNSUPPORTED, +++ .vdev_set_keepalive_cmdid = WMI_CMD_UNSUPPORTED, +++ .vdev_get_keepalive_cmdid = WMI_CMD_UNSUPPORTED, +++ .force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED, +++ .gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID, +++ .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID, +++ .pdev_get_temperature_cmdid = WMI_10_2_PDEV_GET_TEMPERATURE_CMDID, ++ }; ++ ++ /* MAIN WMI VDEV param map */ ++@@ -384,6 +511,64 @@ static struct wmi_vdev_param_map wmi_10x ++ WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, ++ }; ++ +++static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = { +++ .rts_threshold = WMI_10X_VDEV_PARAM_RTS_THRESHOLD, +++ .fragmentation_threshold = WMI_10X_VDEV_PARAM_FRAGMENTATION_THRESHOLD, +++ .beacon_interval = WMI_10X_VDEV_PARAM_BEACON_INTERVAL, +++ .listen_interval = WMI_10X_VDEV_PARAM_LISTEN_INTERVAL, +++ .multicast_rate = WMI_10X_VDEV_PARAM_MULTICAST_RATE, +++ .mgmt_tx_rate = WMI_10X_VDEV_PARAM_MGMT_TX_RATE, +++ .slot_time = WMI_10X_VDEV_PARAM_SLOT_TIME, +++ .preamble = WMI_10X_VDEV_PARAM_PREAMBLE, +++ .swba_time = WMI_10X_VDEV_PARAM_SWBA_TIME, +++ .wmi_vdev_stats_update_period = WMI_10X_VDEV_STATS_UPDATE_PERIOD, +++ .wmi_vdev_pwrsave_ageout_time = WMI_10X_VDEV_PWRSAVE_AGEOUT_TIME, +++ .wmi_vdev_host_swba_interval = WMI_10X_VDEV_HOST_SWBA_INTERVAL, +++ .dtim_period = WMI_10X_VDEV_PARAM_DTIM_PERIOD, +++ .wmi_vdev_oc_scheduler_air_time_limit = +++ WMI_10X_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT, +++ .wds = WMI_10X_VDEV_PARAM_WDS, +++ .atim_window = WMI_10X_VDEV_PARAM_ATIM_WINDOW, +++ .bmiss_count_max = WMI_10X_VDEV_PARAM_BMISS_COUNT_MAX, +++ .bmiss_first_bcnt = WMI_VDEV_PARAM_UNSUPPORTED, +++ .bmiss_final_bcnt = WMI_VDEV_PARAM_UNSUPPORTED, +++ .feature_wmm = WMI_10X_VDEV_PARAM_FEATURE_WMM, +++ .chwidth = WMI_10X_VDEV_PARAM_CHWIDTH, +++ .chextoffset = WMI_10X_VDEV_PARAM_CHEXTOFFSET, +++ .disable_htprotection = WMI_10X_VDEV_PARAM_DISABLE_HTPROTECTION, +++ .sta_quickkickout = WMI_10X_VDEV_PARAM_STA_QUICKKICKOUT, +++ .mgmt_rate = WMI_10X_VDEV_PARAM_MGMT_RATE, +++ .protection_mode = WMI_10X_VDEV_PARAM_PROTECTION_MODE, +++ .fixed_rate = WMI_10X_VDEV_PARAM_FIXED_RATE, +++ .sgi = WMI_10X_VDEV_PARAM_SGI, +++ .ldpc = WMI_10X_VDEV_PARAM_LDPC, +++ .tx_stbc = WMI_10X_VDEV_PARAM_TX_STBC, +++ .rx_stbc = WMI_10X_VDEV_PARAM_RX_STBC, +++ .intra_bss_fwd = WMI_10X_VDEV_PARAM_INTRA_BSS_FWD, +++ .def_keyid = WMI_10X_VDEV_PARAM_DEF_KEYID, +++ .nss = WMI_10X_VDEV_PARAM_NSS, +++ .bcast_data_rate = WMI_10X_VDEV_PARAM_BCAST_DATA_RATE, +++ .mcast_data_rate = WMI_10X_VDEV_PARAM_MCAST_DATA_RATE, +++ .mcast_indicate = WMI_10X_VDEV_PARAM_MCAST_INDICATE, +++ .dhcp_indicate = WMI_10X_VDEV_PARAM_DHCP_INDICATE, +++ .unknown_dest_indicate = WMI_10X_VDEV_PARAM_UNKNOWN_DEST_INDICATE, +++ .ap_keepalive_min_idle_inactive_time_secs = +++ WMI_10X_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, +++ .ap_keepalive_max_idle_inactive_time_secs = +++ WMI_10X_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, +++ .ap_keepalive_max_unresponsive_time_secs = +++ WMI_10X_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, +++ .ap_enable_nawds = WMI_10X_VDEV_PARAM_AP_ENABLE_NAWDS, +++ .mcast2ucast_set = WMI_10X_VDEV_PARAM_MCAST2UCAST_SET, +++ .enable_rtscts = WMI_10X_VDEV_PARAM_ENABLE_RTSCTS, +++ .txbf = WMI_VDEV_PARAM_UNSUPPORTED, +++ .packet_powersave = WMI_VDEV_PARAM_UNSUPPORTED, +++ .drop_unencry = WMI_VDEV_PARAM_UNSUPPORTED, +++ .tx_encap_type = WMI_VDEV_PARAM_UNSUPPORTED, +++ .ap_detect_out_of_sync_sleeping_sta_time_secs = +++ WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, +++}; +++ ++ static struct wmi_pdev_param_map wmi_pdev_param_map = { ++ .tx_chain_mask = WMI_PDEV_PARAM_TX_CHAIN_MASK, ++ .rx_chain_mask = WMI_PDEV_PARAM_RX_CHAIN_MASK, ++@@ -433,6 +618,7 @@ static struct wmi_pdev_param_map wmi_pde ++ .fast_channel_reset = WMI_PDEV_PARAM_UNSUPPORTED, ++ .burst_dur = WMI_PDEV_PARAM_UNSUPPORTED, ++ .burst_enable = WMI_PDEV_PARAM_UNSUPPORTED, +++ .cal_period = WMI_PDEV_PARAM_UNSUPPORTED, ++ }; ++ ++ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { ++@@ -485,11 +671,221 @@ static struct wmi_pdev_param_map wmi_10x ++ .fast_channel_reset = WMI_10X_PDEV_PARAM_FAST_CHANNEL_RESET, ++ .burst_dur = WMI_10X_PDEV_PARAM_BURST_DUR, ++ .burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE, +++ .cal_period = WMI_10X_PDEV_PARAM_CAL_PERIOD, +++}; +++ +++static struct wmi_pdev_param_map wmi_10_2_4_pdev_param_map = { +++ .tx_chain_mask = WMI_10X_PDEV_PARAM_TX_CHAIN_MASK, +++ .rx_chain_mask = WMI_10X_PDEV_PARAM_RX_CHAIN_MASK, +++ .txpower_limit2g = WMI_10X_PDEV_PARAM_TXPOWER_LIMIT2G, +++ .txpower_limit5g = WMI_10X_PDEV_PARAM_TXPOWER_LIMIT5G, +++ .txpower_scale = WMI_10X_PDEV_PARAM_TXPOWER_SCALE, +++ .beacon_gen_mode = WMI_10X_PDEV_PARAM_BEACON_GEN_MODE, +++ .beacon_tx_mode = WMI_10X_PDEV_PARAM_BEACON_TX_MODE, +++ .resmgr_offchan_mode = WMI_10X_PDEV_PARAM_RESMGR_OFFCHAN_MODE, +++ .protection_mode = WMI_10X_PDEV_PARAM_PROTECTION_MODE, +++ .dynamic_bw = WMI_10X_PDEV_PARAM_DYNAMIC_BW, +++ .non_agg_sw_retry_th = WMI_10X_PDEV_PARAM_NON_AGG_SW_RETRY_TH, +++ .agg_sw_retry_th = WMI_10X_PDEV_PARAM_AGG_SW_RETRY_TH, +++ .sta_kickout_th = WMI_10X_PDEV_PARAM_STA_KICKOUT_TH, +++ .ac_aggrsize_scaling = WMI_10X_PDEV_PARAM_AC_AGGRSIZE_SCALING, +++ .ltr_enable = WMI_10X_PDEV_PARAM_LTR_ENABLE, +++ .ltr_ac_latency_be = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_BE, +++ .ltr_ac_latency_bk = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_BK, +++ .ltr_ac_latency_vi = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_VI, +++ .ltr_ac_latency_vo = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_VO, +++ .ltr_ac_latency_timeout = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT, +++ .ltr_sleep_override = WMI_10X_PDEV_PARAM_LTR_SLEEP_OVERRIDE, +++ .ltr_rx_override = WMI_10X_PDEV_PARAM_LTR_RX_OVERRIDE, +++ .ltr_tx_activity_timeout = WMI_10X_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT, +++ .l1ss_enable = WMI_10X_PDEV_PARAM_L1SS_ENABLE, +++ .dsleep_enable = WMI_10X_PDEV_PARAM_DSLEEP_ENABLE, +++ .pcielp_txbuf_flush = WMI_PDEV_PARAM_UNSUPPORTED, +++ .pcielp_txbuf_watermark = WMI_PDEV_PARAM_UNSUPPORTED, +++ .pcielp_txbuf_tmo_en = WMI_PDEV_PARAM_UNSUPPORTED, +++ .pcielp_txbuf_tmo_value = WMI_PDEV_PARAM_UNSUPPORTED, +++ .pdev_stats_update_period = WMI_10X_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD, +++ .vdev_stats_update_period = WMI_10X_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD, +++ .peer_stats_update_period = WMI_10X_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD, +++ .bcnflt_stats_update_period = +++ WMI_10X_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, +++ .pmf_qos = WMI_10X_PDEV_PARAM_PMF_QOS, +++ .arp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE, +++ .dcs = WMI_10X_PDEV_PARAM_DCS, +++ .ani_enable = WMI_10X_PDEV_PARAM_ANI_ENABLE, +++ .ani_poll_period = WMI_10X_PDEV_PARAM_ANI_POLL_PERIOD, +++ .ani_listen_period = WMI_10X_PDEV_PARAM_ANI_LISTEN_PERIOD, +++ .ani_ofdm_level = WMI_10X_PDEV_PARAM_ANI_OFDM_LEVEL, +++ .ani_cck_level = WMI_10X_PDEV_PARAM_ANI_CCK_LEVEL, +++ .dyntxchain = WMI_10X_PDEV_PARAM_DYNTXCHAIN, +++ .proxy_sta = WMI_PDEV_PARAM_UNSUPPORTED, +++ .idle_ps_config = WMI_PDEV_PARAM_UNSUPPORTED, +++ .power_gating_sleep = WMI_PDEV_PARAM_UNSUPPORTED, +++ .fast_channel_reset = WMI_10X_PDEV_PARAM_FAST_CHANNEL_RESET, +++ .burst_dur = WMI_10X_PDEV_PARAM_BURST_DUR, +++ .burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE, +++ .cal_period = WMI_10X_PDEV_PARAM_CAL_PERIOD, +++}; +++ +++/* firmware 10.2 specific mappings */ +++static struct wmi_cmd_map wmi_10_2_cmd_map = { +++ .init_cmdid = WMI_10_2_INIT_CMDID, +++ .start_scan_cmdid = WMI_10_2_START_SCAN_CMDID, +++ .stop_scan_cmdid = WMI_10_2_STOP_SCAN_CMDID, +++ .scan_chan_list_cmdid = WMI_10_2_SCAN_CHAN_LIST_CMDID, +++ .scan_sch_prio_tbl_cmdid = WMI_CMD_UNSUPPORTED, +++ .pdev_set_regdomain_cmdid = WMI_10_2_PDEV_SET_REGDOMAIN_CMDID, +++ .pdev_set_channel_cmdid = WMI_10_2_PDEV_SET_CHANNEL_CMDID, +++ .pdev_set_param_cmdid = WMI_10_2_PDEV_SET_PARAM_CMDID, +++ .pdev_pktlog_enable_cmdid = WMI_10_2_PDEV_PKTLOG_ENABLE_CMDID, +++ .pdev_pktlog_disable_cmdid = WMI_10_2_PDEV_PKTLOG_DISABLE_CMDID, +++ .pdev_set_wmm_params_cmdid = WMI_10_2_PDEV_SET_WMM_PARAMS_CMDID, +++ .pdev_set_ht_cap_ie_cmdid = WMI_10_2_PDEV_SET_HT_CAP_IE_CMDID, +++ .pdev_set_vht_cap_ie_cmdid = WMI_10_2_PDEV_SET_VHT_CAP_IE_CMDID, +++ .pdev_set_quiet_mode_cmdid = WMI_10_2_PDEV_SET_QUIET_MODE_CMDID, +++ .pdev_green_ap_ps_enable_cmdid = WMI_10_2_PDEV_GREEN_AP_PS_ENABLE_CMDID, +++ .pdev_get_tpc_config_cmdid = WMI_10_2_PDEV_GET_TPC_CONFIG_CMDID, +++ .pdev_set_base_macaddr_cmdid = WMI_10_2_PDEV_SET_BASE_MACADDR_CMDID, +++ .vdev_create_cmdid = WMI_10_2_VDEV_CREATE_CMDID, +++ .vdev_delete_cmdid = WMI_10_2_VDEV_DELETE_CMDID, +++ .vdev_start_request_cmdid = WMI_10_2_VDEV_START_REQUEST_CMDID, +++ .vdev_restart_request_cmdid = WMI_10_2_VDEV_RESTART_REQUEST_CMDID, +++ .vdev_up_cmdid = WMI_10_2_VDEV_UP_CMDID, +++ .vdev_stop_cmdid = WMI_10_2_VDEV_STOP_CMDID, +++ .vdev_down_cmdid = WMI_10_2_VDEV_DOWN_CMDID, +++ .vdev_set_param_cmdid = WMI_10_2_VDEV_SET_PARAM_CMDID, +++ .vdev_install_key_cmdid = WMI_10_2_VDEV_INSTALL_KEY_CMDID, +++ .peer_create_cmdid = WMI_10_2_PEER_CREATE_CMDID, +++ .peer_delete_cmdid = WMI_10_2_PEER_DELETE_CMDID, +++ .peer_flush_tids_cmdid = WMI_10_2_PEER_FLUSH_TIDS_CMDID, +++ .peer_set_param_cmdid = WMI_10_2_PEER_SET_PARAM_CMDID, +++ .peer_assoc_cmdid = WMI_10_2_PEER_ASSOC_CMDID, +++ .peer_add_wds_entry_cmdid = WMI_10_2_PEER_ADD_WDS_ENTRY_CMDID, +++ .peer_remove_wds_entry_cmdid = WMI_10_2_PEER_REMOVE_WDS_ENTRY_CMDID, +++ .peer_mcast_group_cmdid = WMI_10_2_PEER_MCAST_GROUP_CMDID, +++ .bcn_tx_cmdid = WMI_10_2_BCN_TX_CMDID, +++ .pdev_send_bcn_cmdid = WMI_10_2_PDEV_SEND_BCN_CMDID, +++ .bcn_tmpl_cmdid = WMI_CMD_UNSUPPORTED, +++ .bcn_filter_rx_cmdid = WMI_10_2_BCN_FILTER_RX_CMDID, +++ .prb_req_filter_rx_cmdid = WMI_10_2_PRB_REQ_FILTER_RX_CMDID, +++ .mgmt_tx_cmdid = WMI_10_2_MGMT_TX_CMDID, +++ .prb_tmpl_cmdid = WMI_CMD_UNSUPPORTED, +++ .addba_clear_resp_cmdid = WMI_10_2_ADDBA_CLEAR_RESP_CMDID, +++ .addba_send_cmdid = WMI_10_2_ADDBA_SEND_CMDID, +++ .addba_status_cmdid = WMI_10_2_ADDBA_STATUS_CMDID, +++ .delba_send_cmdid = WMI_10_2_DELBA_SEND_CMDID, +++ .addba_set_resp_cmdid = WMI_10_2_ADDBA_SET_RESP_CMDID, +++ .send_singleamsdu_cmdid = WMI_10_2_SEND_SINGLEAMSDU_CMDID, +++ .sta_powersave_mode_cmdid = WMI_10_2_STA_POWERSAVE_MODE_CMDID, +++ .sta_powersave_param_cmdid = WMI_10_2_STA_POWERSAVE_PARAM_CMDID, +++ .sta_mimo_ps_mode_cmdid = WMI_10_2_STA_MIMO_PS_MODE_CMDID, +++ .pdev_dfs_enable_cmdid = WMI_10_2_PDEV_DFS_ENABLE_CMDID, +++ .pdev_dfs_disable_cmdid = WMI_10_2_PDEV_DFS_DISABLE_CMDID, +++ .roam_scan_mode = WMI_10_2_ROAM_SCAN_MODE, +++ .roam_scan_rssi_threshold = WMI_10_2_ROAM_SCAN_RSSI_THRESHOLD, +++ .roam_scan_period = WMI_10_2_ROAM_SCAN_PERIOD, +++ .roam_scan_rssi_change_threshold = +++ WMI_10_2_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, +++ .roam_ap_profile = WMI_10_2_ROAM_AP_PROFILE, +++ .ofl_scan_add_ap_profile = WMI_10_2_OFL_SCAN_ADD_AP_PROFILE, +++ .ofl_scan_remove_ap_profile = WMI_10_2_OFL_SCAN_REMOVE_AP_PROFILE, +++ .ofl_scan_period = WMI_10_2_OFL_SCAN_PERIOD, +++ .p2p_dev_set_device_info = WMI_10_2_P2P_DEV_SET_DEVICE_INFO, +++ .p2p_dev_set_discoverability = WMI_10_2_P2P_DEV_SET_DISCOVERABILITY, +++ .p2p_go_set_beacon_ie = WMI_10_2_P2P_GO_SET_BEACON_IE, +++ .p2p_go_set_probe_resp_ie = WMI_10_2_P2P_GO_SET_PROBE_RESP_IE, +++ .p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED, +++ .ap_ps_peer_param_cmdid = WMI_10_2_AP_PS_PEER_PARAM_CMDID, +++ .ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED, +++ .peer_rate_retry_sched_cmdid = WMI_10_2_PEER_RATE_RETRY_SCHED_CMDID, +++ .wlan_profile_trigger_cmdid = WMI_10_2_WLAN_PROFILE_TRIGGER_CMDID, +++ .wlan_profile_set_hist_intvl_cmdid = +++ WMI_10_2_WLAN_PROFILE_SET_HIST_INTVL_CMDID, +++ .wlan_profile_get_profile_data_cmdid = +++ WMI_10_2_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, +++ .wlan_profile_enable_profile_id_cmdid = +++ WMI_10_2_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, +++ .wlan_profile_list_profile_id_cmdid = +++ WMI_10_2_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, +++ .pdev_suspend_cmdid = WMI_10_2_PDEV_SUSPEND_CMDID, +++ .pdev_resume_cmdid = WMI_10_2_PDEV_RESUME_CMDID, +++ .add_bcn_filter_cmdid = WMI_10_2_ADD_BCN_FILTER_CMDID, +++ .rmv_bcn_filter_cmdid = WMI_10_2_RMV_BCN_FILTER_CMDID, +++ .wow_add_wake_pattern_cmdid = WMI_10_2_WOW_ADD_WAKE_PATTERN_CMDID, +++ .wow_del_wake_pattern_cmdid = WMI_10_2_WOW_DEL_WAKE_PATTERN_CMDID, +++ .wow_enable_disable_wake_event_cmdid = +++ WMI_10_2_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, +++ .wow_enable_cmdid = WMI_10_2_WOW_ENABLE_CMDID, +++ .wow_hostwakeup_from_sleep_cmdid = +++ WMI_10_2_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, +++ .rtt_measreq_cmdid = WMI_10_2_RTT_MEASREQ_CMDID, +++ .rtt_tsf_cmdid = WMI_10_2_RTT_TSF_CMDID, +++ .vdev_spectral_scan_configure_cmdid = +++ WMI_10_2_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID, +++ .vdev_spectral_scan_enable_cmdid = +++ WMI_10_2_VDEV_SPECTRAL_SCAN_ENABLE_CMDID, +++ .request_stats_cmdid = WMI_10_2_REQUEST_STATS_CMDID, +++ .set_arp_ns_offload_cmdid = WMI_CMD_UNSUPPORTED, +++ .network_list_offload_config_cmdid = WMI_CMD_UNSUPPORTED, +++ .gtk_offload_cmdid = WMI_CMD_UNSUPPORTED, +++ .csa_offload_enable_cmdid = WMI_CMD_UNSUPPORTED, +++ .csa_offload_chanswitch_cmdid = WMI_CMD_UNSUPPORTED, +++ .chatter_set_mode_cmdid = WMI_CMD_UNSUPPORTED, +++ .peer_tid_addba_cmdid = WMI_CMD_UNSUPPORTED, +++ .peer_tid_delba_cmdid = WMI_CMD_UNSUPPORTED, +++ .sta_dtim_ps_method_cmdid = WMI_CMD_UNSUPPORTED, +++ .sta_uapsd_auto_trig_cmdid = WMI_CMD_UNSUPPORTED, +++ .sta_keepalive_cmd = WMI_CMD_UNSUPPORTED, +++ .echo_cmdid = WMI_10_2_ECHO_CMDID, +++ .pdev_utf_cmdid = WMI_10_2_PDEV_UTF_CMDID, +++ .dbglog_cfg_cmdid = WMI_10_2_DBGLOG_CFG_CMDID, +++ .pdev_qvit_cmdid = WMI_10_2_PDEV_QVIT_CMDID, +++ .pdev_ftm_intg_cmdid = WMI_CMD_UNSUPPORTED, +++ .vdev_set_keepalive_cmdid = WMI_CMD_UNSUPPORTED, +++ .vdev_get_keepalive_cmdid = WMI_CMD_UNSUPPORTED, +++ .force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED, +++ .gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID, +++ .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID, +++ .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED, ++ }; ++ +++void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, +++ const struct wmi_channel_arg *arg) +++{ +++ u32 flags = 0; +++ +++ memset(ch, 0, sizeof(*ch)); +++ +++ if (arg->passive) +++ flags |= WMI_CHAN_FLAG_PASSIVE; +++ if (arg->allow_ibss) +++ flags |= WMI_CHAN_FLAG_ADHOC_ALLOWED; +++ if (arg->allow_ht) +++ flags |= WMI_CHAN_FLAG_ALLOW_HT; +++ if (arg->allow_vht) +++ flags |= WMI_CHAN_FLAG_ALLOW_VHT; +++ if (arg->ht40plus) +++ flags |= WMI_CHAN_FLAG_HT40_PLUS; +++ if (arg->chan_radar) +++ flags |= WMI_CHAN_FLAG_DFS; +++ +++ ch->mhz = __cpu_to_le32(arg->freq); +++ ch->band_center_freq1 = __cpu_to_le32(arg->band_center_freq1); +++ ch->band_center_freq2 = 0; +++ ch->min_power = arg->min_power; +++ ch->max_power = arg->max_power; +++ ch->reg_power = arg->max_reg_power; +++ ch->antenna_max = arg->max_antenna_gain; +++ +++ /* mode & flags share storage */ +++ ch->mode = arg->mode; +++ ch->flags |= __cpu_to_le32(flags); +++} +++ ++ int ath10k_wmi_wait_for_service_ready(struct ath10k *ar) ++ { ++ int ret; +++ ++ ret = wait_for_completion_timeout(&ar->wmi.service_ready, ++ WMI_SERVICE_READY_TIMEOUT_HZ); ++ return ret; ++@@ -498,23 +894,24 @@ int ath10k_wmi_wait_for_service_ready(st ++ int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar) ++ { ++ int ret; +++ ++ ret = wait_for_completion_timeout(&ar->wmi.unified_ready, ++ WMI_UNIFIED_READY_TIMEOUT_HZ); ++ return ret; ++ } ++ ++-static struct sk_buff *ath10k_wmi_alloc_skb(u32 len) +++struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len) ++ { ++ struct sk_buff *skb; ++ u32 round_len = roundup(len, 4); ++ ++- skb = ath10k_htc_alloc_skb(WMI_SKB_HEADROOM + round_len); +++ skb = ath10k_htc_alloc_skb(ar, WMI_SKB_HEADROOM + round_len); ++ if (!skb) ++ return NULL; ++ ++ skb_reserve(skb, WMI_SKB_HEADROOM); ++ if (!IS_ALIGNED((unsigned long)skb->data, 4)) ++- ath10k_warn("Unaligned WMI skb\n"); +++ ath10k_warn(ar, "Unaligned WMI skb\n"); ++ ++ skb_put(skb, round_len); ++ memset(skb->data, 0, round_len); ++@@ -527,8 +924,8 @@ static void ath10k_wmi_htc_tx_complete(s ++ dev_kfree_skb(skb); ++ } ++ ++-static int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb, ++- u32 cmd_id) +++int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb, +++ u32 cmd_id) ++ { ++ struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb); ++ struct wmi_cmd_hdr *cmd_hdr; ++@@ -545,7 +942,7 @@ static int ath10k_wmi_cmd_send_nowait(st ++ ++ memset(skb_cb, 0, sizeof(*skb_cb)); ++ ret = ath10k_htc_send(&ar->htc, ar->wmi.eid, skb); ++- trace_ath10k_wmi_cmd(cmd_id, skb->data, skb->len, ret); +++ trace_ath10k_wmi_cmd(ar, cmd_id, skb->data, skb->len, ret); ++ ++ if (ret) ++ goto err_pull; ++@@ -559,23 +956,45 @@ err_pull: ++ ++ static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) ++ { +++ struct ath10k *ar = arvif->ar; +++ struct ath10k_skb_cb *cb; +++ struct sk_buff *bcn; ++ int ret; ++ ++- lockdep_assert_held(&arvif->ar->data_lock); +++ spin_lock_bh(&ar->data_lock); ++ ++- if (arvif->beacon == NULL) ++- return; +++ bcn = arvif->beacon; ++ ++- if (arvif->beacon_sent) ++- return; +++ if (!bcn) +++ goto unlock; ++ ++- ret = ath10k_wmi_beacon_send_ref_nowait(arvif); ++- if (ret) ++- return; +++ cb = ATH10K_SKB_CB(bcn); +++ +++ switch (arvif->beacon_state) { +++ case ATH10K_BEACON_SENDING: +++ case ATH10K_BEACON_SENT: +++ break; +++ case ATH10K_BEACON_SCHEDULED: +++ arvif->beacon_state = ATH10K_BEACON_SENDING; +++ spin_unlock_bh(&ar->data_lock); +++ +++ ret = ath10k_wmi_beacon_send_ref_nowait(arvif->ar, +++ arvif->vdev_id, +++ bcn->data, bcn->len, +++ cb->paddr, +++ cb->bcn.dtim_zero, +++ cb->bcn.deliver_cab); +++ +++ spin_lock_bh(&ar->data_lock); ++ ++- /* We need to retain the arvif->beacon reference for DMA unmapping and ++- * freeing the skbuff later. */ ++- arvif->beacon_sent = true; +++ if (ret == 0) +++ arvif->beacon_state = ATH10K_BEACON_SENT; +++ else +++ arvif->beacon_state = ATH10K_BEACON_SCHEDULED; +++ } +++ +++unlock: +++ spin_unlock_bh(&ar->data_lock); ++ } ++ ++ static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac, ++@@ -588,12 +1007,10 @@ static void ath10k_wmi_tx_beacons_iter(v ++ ++ static void ath10k_wmi_tx_beacons_nowait(struct ath10k *ar) ++ { ++- spin_lock_bh(&ar->data_lock); ++ ieee80211_iterate_active_interfaces_atomic(ar->hw, ++ IEEE80211_IFACE_ITER_NORMAL, ++ ath10k_wmi_tx_beacons_iter, ++ NULL); ++- spin_unlock_bh(&ar->data_lock); ++ } ++ ++ static void ath10k_wmi_op_ep_tx_credits(struct ath10k *ar) ++@@ -604,15 +1021,14 @@ static void ath10k_wmi_op_ep_tx_credits( ++ wake_up(&ar->wmi.tx_credits_wq); ++ } ++ ++-static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, ++- u32 cmd_id) +++int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id) ++ { ++ int ret = -EOPNOTSUPP; ++ ++ might_sleep(); ++ ++ if (cmd_id == WMI_CMD_UNSUPPORTED) { ++- ath10k_warn("wmi command %d is not supported by firmware\n", +++ ath10k_warn(ar, "wmi command %d is not supported by firmware\n", ++ cmd_id); ++ return ret; ++ } ++@@ -622,6 +1038,10 @@ static int ath10k_wmi_cmd_send(struct at ++ ath10k_wmi_tx_beacons_nowait(ar); ++ ++ ret = ath10k_wmi_cmd_send_nowait(ar, skb, cmd_id); +++ +++ if (ret && test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) +++ ret = -ESHUTDOWN; +++ ++ (ret != -EAGAIN); ++ }), 3*HZ); ++ ++@@ -631,147 +1051,270 @@ static int ath10k_wmi_cmd_send(struct at ++ return ret; ++ } ++ ++-int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb) +++static struct sk_buff * +++ath10k_wmi_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) ++ { ++- int ret = 0; ++ struct wmi_mgmt_tx_cmd *cmd; ++ struct ieee80211_hdr *hdr; ++- struct sk_buff *wmi_skb; ++- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); +++ struct sk_buff *skb; ++ int len; +++ u32 buf_len = msdu->len; ++ u16 fc; ++ ++- hdr = (struct ieee80211_hdr *)skb->data; +++ hdr = (struct ieee80211_hdr *)msdu->data; ++ fc = le16_to_cpu(hdr->frame_control); ++ ++ if (WARN_ON_ONCE(!ieee80211_is_mgmt(hdr->frame_control))) ++- return -EINVAL; +++ return ERR_PTR(-EINVAL); +++ +++ len = sizeof(cmd->hdr) + msdu->len; +++ +++ if ((ieee80211_is_action(hdr->frame_control) || +++ ieee80211_is_deauth(hdr->frame_control) || +++ ieee80211_is_disassoc(hdr->frame_control)) && +++ ieee80211_has_protected(hdr->frame_control)) { +++ len += IEEE80211_CCMP_MIC_LEN; +++ buf_len += IEEE80211_CCMP_MIC_LEN; +++ } ++ ++- len = sizeof(cmd->hdr) + skb->len; ++ len = round_up(len, 4); ++ ++- wmi_skb = ath10k_wmi_alloc_skb(len); ++- if (!wmi_skb) ++- return -ENOMEM; +++ skb = ath10k_wmi_alloc_skb(ar, len); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); ++ ++- cmd = (struct wmi_mgmt_tx_cmd *)wmi_skb->data; +++ cmd = (struct wmi_mgmt_tx_cmd *)skb->data; ++ ++- cmd->hdr.vdev_id = __cpu_to_le32(ATH10K_SKB_CB(skb)->vdev_id); +++ cmd->hdr.vdev_id = __cpu_to_le32(ATH10K_SKB_CB(msdu)->vdev_id); ++ cmd->hdr.tx_rate = 0; ++ cmd->hdr.tx_power = 0; ++- cmd->hdr.buf_len = __cpu_to_le32((u32)(skb->len)); +++ cmd->hdr.buf_len = __cpu_to_le32(buf_len); ++ ++- memcpy(cmd->hdr.peer_macaddr.addr, ieee80211_get_DA(hdr), ETH_ALEN); ++- memcpy(cmd->buf, skb->data, skb->len); +++ ether_addr_copy(cmd->hdr.peer_macaddr.addr, ieee80211_get_DA(hdr)); +++ memcpy(cmd->buf, msdu->data, msdu->len); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n", ++- wmi_skb, wmi_skb->len, fc & IEEE80211_FCTL_FTYPE, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n", +++ msdu, skb->len, fc & IEEE80211_FCTL_FTYPE, ++ fc & IEEE80211_FCTL_STYPE); +++ trace_ath10k_tx_hdr(ar, skb->data, skb->len); +++ trace_ath10k_tx_payload(ar, skb->data, skb->len); ++ ++- /* Send the management frame buffer to the target */ ++- ret = ath10k_wmi_cmd_send(ar, wmi_skb, ar->wmi.cmd->mgmt_tx_cmdid); ++- if (ret) ++- return ret; ++- ++- /* TODO: report tx status to mac80211 - temporary just ACK */ ++- info->flags |= IEEE80211_TX_STAT_ACK; ++- ieee80211_tx_status_irqsafe(ar->hw, skb); ++- ++- return ret; +++ return skb; ++ } ++ ++-static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) +++static void ath10k_wmi_event_scan_started(struct ath10k *ar) ++ { ++- struct wmi_scan_event *event = (struct wmi_scan_event *)skb->data; ++- enum wmi_scan_event_type event_type; ++- enum wmi_scan_completion_reason reason; ++- u32 freq; ++- u32 req_id; ++- u32 scan_id; ++- u32 vdev_id; ++- ++- event_type = __le32_to_cpu(event->event_type); ++- reason = __le32_to_cpu(event->reason); ++- freq = __le32_to_cpu(event->channel_freq); ++- req_id = __le32_to_cpu(event->scan_req_id); ++- scan_id = __le32_to_cpu(event->scan_id); ++- vdev_id = __le32_to_cpu(event->vdev_id); ++- ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENTID\n"); ++- ath10k_dbg(ATH10K_DBG_WMI, ++- "scan event type %d reason %d freq %d req_id %d " ++- "scan_id %d vdev_id %d\n", ++- event_type, reason, freq, req_id, scan_id, vdev_id); +++ lockdep_assert_held(&ar->data_lock); ++ ++- spin_lock_bh(&ar->data_lock); +++ switch (ar->scan.state) { +++ case ATH10K_SCAN_IDLE: +++ case ATH10K_SCAN_RUNNING: +++ case ATH10K_SCAN_ABORTING: +++ ath10k_warn(ar, "received scan started event in an invalid scan state: %s (%d)\n", +++ ath10k_scan_state_str(ar->scan.state), +++ ar->scan.state); +++ break; +++ case ATH10K_SCAN_STARTING: +++ ar->scan.state = ATH10K_SCAN_RUNNING; ++ ++- switch (event_type) { ++- case WMI_SCAN_EVENT_STARTED: ++- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_STARTED\n"); ++- if (ar->scan.in_progress && ar->scan.is_roc) +++ if (ar->scan.is_roc) ++ ieee80211_ready_on_channel(ar->hw); ++ ++ complete(&ar->scan.started); ++ break; ++- case WMI_SCAN_EVENT_COMPLETED: ++- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_COMPLETED\n"); ++- switch (reason) { ++- case WMI_SCAN_REASON_COMPLETED: ++- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_COMPLETED\n"); ++- break; ++- case WMI_SCAN_REASON_CANCELLED: ++- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_CANCELED\n"); ++- break; ++- case WMI_SCAN_REASON_PREEMPTED: ++- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_PREEMPTED\n"); ++- break; ++- case WMI_SCAN_REASON_TIMEDOUT: ++- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_TIMEDOUT\n"); ++- break; ++- default: ++- break; ++- } ++- ++- ar->scan_channel = NULL; ++- if (!ar->scan.in_progress) { ++- ath10k_warn("no scan requested, ignoring\n"); ++- break; ++- } ++- ++- if (ar->scan.is_roc) { ++- ath10k_offchan_tx_purge(ar); +++ } +++} ++ ++- if (!ar->scan.aborting) ++- ieee80211_remain_on_channel_expired(ar->hw); ++- } else { ++- ieee80211_scan_completed(ar->hw, ar->scan.aborting); ++- } +++static void ath10k_wmi_event_scan_start_failed(struct ath10k *ar) +++{ +++ lockdep_assert_held(&ar->data_lock); ++ ++- del_timer(&ar->scan.timeout); ++- complete_all(&ar->scan.completed); ++- ar->scan.in_progress = false; +++ switch (ar->scan.state) { +++ case ATH10K_SCAN_IDLE: +++ case ATH10K_SCAN_RUNNING: +++ case ATH10K_SCAN_ABORTING: +++ ath10k_warn(ar, "received scan start failed event in an invalid scan state: %s (%d)\n", +++ ath10k_scan_state_str(ar->scan.state), +++ ar->scan.state); ++ break; ++- case WMI_SCAN_EVENT_BSS_CHANNEL: ++- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_BSS_CHANNEL\n"); ++- ar->scan_channel = NULL; +++ case ATH10K_SCAN_STARTING: +++ complete(&ar->scan.started); +++ __ath10k_scan_finish(ar); ++ break; ++- case WMI_SCAN_EVENT_FOREIGN_CHANNEL: ++- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_FOREIGN_CHANNEL\n"); +++ } +++} +++ +++static void ath10k_wmi_event_scan_completed(struct ath10k *ar) +++{ +++ lockdep_assert_held(&ar->data_lock); +++ +++ switch (ar->scan.state) { +++ case ATH10K_SCAN_IDLE: +++ case ATH10K_SCAN_STARTING: +++ /* One suspected reason scan can be completed while starting is +++ * if firmware fails to deliver all scan events to the host, +++ * e.g. when transport pipe is full. This has been observed +++ * with spectral scan phyerr events starving wmi transport +++ * pipe. In such case the "scan completed" event should be (and +++ * is) ignored by the host as it may be just firmware's scan +++ * state machine recovering. +++ */ +++ ath10k_warn(ar, "received scan completed event in an invalid scan state: %s (%d)\n", +++ ath10k_scan_state_str(ar->scan.state), +++ ar->scan.state); +++ break; +++ case ATH10K_SCAN_RUNNING: +++ case ATH10K_SCAN_ABORTING: +++ __ath10k_scan_finish(ar); +++ break; +++ } +++} +++ +++static void ath10k_wmi_event_scan_bss_chan(struct ath10k *ar) +++{ +++ lockdep_assert_held(&ar->data_lock); +++ +++ switch (ar->scan.state) { +++ case ATH10K_SCAN_IDLE: +++ case ATH10K_SCAN_STARTING: +++ ath10k_warn(ar, "received scan bss chan event in an invalid scan state: %s (%d)\n", +++ ath10k_scan_state_str(ar->scan.state), +++ ar->scan.state); +++ break; +++ case ATH10K_SCAN_RUNNING: +++ case ATH10K_SCAN_ABORTING: +++ ar->scan_channel = NULL; +++ break; +++ } +++} +++ +++static void ath10k_wmi_event_scan_foreign_chan(struct ath10k *ar, u32 freq) +++{ +++ lockdep_assert_held(&ar->data_lock); +++ +++ switch (ar->scan.state) { +++ case ATH10K_SCAN_IDLE: +++ case ATH10K_SCAN_STARTING: +++ ath10k_warn(ar, "received scan foreign chan event in an invalid scan state: %s (%d)\n", +++ ath10k_scan_state_str(ar->scan.state), +++ ar->scan.state); +++ break; +++ case ATH10K_SCAN_RUNNING: +++ case ATH10K_SCAN_ABORTING: ++ ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq); ++- if (ar->scan.in_progress && ar->scan.is_roc && ++- ar->scan.roc_freq == freq) { +++ +++ if (ar->scan.is_roc && ar->scan.roc_freq == freq) ++ complete(&ar->scan.on_channel); ++- } ++ break; +++ } +++} +++ +++static const char * +++ath10k_wmi_event_scan_type_str(enum wmi_scan_event_type type, +++ enum wmi_scan_completion_reason reason) +++{ +++ switch (type) { +++ case WMI_SCAN_EVENT_STARTED: +++ return "started"; +++ case WMI_SCAN_EVENT_COMPLETED: +++ switch (reason) { +++ case WMI_SCAN_REASON_COMPLETED: +++ return "completed"; +++ case WMI_SCAN_REASON_CANCELLED: +++ return "completed [cancelled]"; +++ case WMI_SCAN_REASON_PREEMPTED: +++ return "completed [preempted]"; +++ case WMI_SCAN_REASON_TIMEDOUT: +++ return "completed [timedout]"; +++ case WMI_SCAN_REASON_MAX: +++ break; +++ } +++ return "completed [unknown]"; +++ case WMI_SCAN_EVENT_BSS_CHANNEL: +++ return "bss channel"; +++ case WMI_SCAN_EVENT_FOREIGN_CHANNEL: +++ return "foreign channel"; ++ case WMI_SCAN_EVENT_DEQUEUED: ++- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_DEQUEUED\n"); ++- break; +++ return "dequeued"; ++ case WMI_SCAN_EVENT_PREEMPTED: ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENT_PREEMPTED\n"); +++ return "preempted"; +++ case WMI_SCAN_EVENT_START_FAILED: +++ return "start failed"; +++ default: +++ return "unknown"; +++ } +++} +++ +++static int ath10k_wmi_op_pull_scan_ev(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_scan_ev_arg *arg) +++{ +++ struct wmi_scan_event *ev = (void *)skb->data; +++ +++ if (skb->len < sizeof(*ev)) +++ return -EPROTO; +++ +++ skb_pull(skb, sizeof(*ev)); +++ arg->event_type = ev->event_type; +++ arg->reason = ev->reason; +++ arg->channel_freq = ev->channel_freq; +++ arg->scan_req_id = ev->scan_req_id; +++ arg->scan_id = ev->scan_id; +++ arg->vdev_id = ev->vdev_id; +++ +++ return 0; +++} +++ +++int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) +++{ +++ struct wmi_scan_ev_arg arg = {}; +++ enum wmi_scan_event_type event_type; +++ enum wmi_scan_completion_reason reason; +++ u32 freq; +++ u32 req_id; +++ u32 scan_id; +++ u32 vdev_id; +++ int ret; +++ +++ ret = ath10k_wmi_pull_scan(ar, skb, &arg); +++ if (ret) { +++ ath10k_warn(ar, "failed to parse scan event: %d\n", ret); +++ return ret; +++ } +++ +++ event_type = __le32_to_cpu(arg.event_type); +++ reason = __le32_to_cpu(arg.reason); +++ freq = __le32_to_cpu(arg.channel_freq); +++ req_id = __le32_to_cpu(arg.scan_req_id); +++ scan_id = __le32_to_cpu(arg.scan_id); +++ vdev_id = __le32_to_cpu(arg.vdev_id); +++ +++ spin_lock_bh(&ar->data_lock); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, +++ "scan event %s type %d reason %d freq %d req_id %d scan_id %d vdev_id %d state %s (%d)\n", +++ ath10k_wmi_event_scan_type_str(event_type, reason), +++ event_type, reason, freq, req_id, scan_id, vdev_id, +++ ath10k_scan_state_str(ar->scan.state), ar->scan.state); +++ +++ switch (event_type) { +++ case WMI_SCAN_EVENT_STARTED: +++ ath10k_wmi_event_scan_started(ar); +++ break; +++ case WMI_SCAN_EVENT_COMPLETED: +++ ath10k_wmi_event_scan_completed(ar); +++ break; +++ case WMI_SCAN_EVENT_BSS_CHANNEL: +++ ath10k_wmi_event_scan_bss_chan(ar); +++ break; +++ case WMI_SCAN_EVENT_FOREIGN_CHANNEL: +++ ath10k_wmi_event_scan_foreign_chan(ar, freq); ++ break; ++ case WMI_SCAN_EVENT_START_FAILED: ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENT_START_FAILED\n"); +++ ath10k_warn(ar, "received scan start failure event\n"); +++ ath10k_wmi_event_scan_start_failed(ar); ++ break; +++ case WMI_SCAN_EVENT_DEQUEUED: +++ case WMI_SCAN_EVENT_PREEMPTED: ++ default: ++ break; ++ } ++@@ -865,13 +1408,86 @@ static inline u8 get_rate_idx(u32 rate, ++ return rate_idx; ++ } ++ ++-static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) +++/* If keys are configured, HW decrypts all frames +++ * with protected bit set. Mark such frames as decrypted. +++ */ +++static void ath10k_wmi_handle_wep_reauth(struct ath10k *ar, +++ struct sk_buff *skb, +++ struct ieee80211_rx_status *status) +++{ +++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; +++ unsigned int hdrlen; +++ bool peer_key; +++ u8 *addr, keyidx; +++ +++ if (!ieee80211_is_auth(hdr->frame_control) || +++ !ieee80211_has_protected(hdr->frame_control)) +++ return; +++ +++ hdrlen = ieee80211_hdrlen(hdr->frame_control); +++ if (skb->len < (hdrlen + IEEE80211_WEP_IV_LEN)) +++ return; +++ +++ keyidx = skb->data[hdrlen + (IEEE80211_WEP_IV_LEN - 1)] >> WEP_KEYID_SHIFT; +++ addr = ieee80211_get_SA(hdr); +++ +++ spin_lock_bh(&ar->data_lock); +++ peer_key = ath10k_mac_is_peer_wep_key_set(ar, addr, keyidx); +++ spin_unlock_bh(&ar->data_lock); +++ +++ if (peer_key) { +++ ath10k_dbg(ar, ATH10K_DBG_MAC, +++ "mac wep key present for peer %pM\n", addr); +++ status->flag |= RX_FLAG_DECRYPTED; +++ } +++} +++ +++static int ath10k_wmi_op_pull_mgmt_rx_ev(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_mgmt_rx_ev_arg *arg) ++ { ++ struct wmi_mgmt_rx_event_v1 *ev_v1; ++ struct wmi_mgmt_rx_event_v2 *ev_v2; ++ struct wmi_mgmt_rx_hdr_v1 *ev_hdr; +++ size_t pull_len; +++ u32 msdu_len; +++ +++ if (test_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features)) { +++ ev_v2 = (struct wmi_mgmt_rx_event_v2 *)skb->data; +++ ev_hdr = &ev_v2->hdr.v1; +++ pull_len = sizeof(*ev_v2); +++ } else { +++ ev_v1 = (struct wmi_mgmt_rx_event_v1 *)skb->data; +++ ev_hdr = &ev_v1->hdr; +++ pull_len = sizeof(*ev_v1); +++ } +++ +++ if (skb->len < pull_len) +++ return -EPROTO; +++ +++ skb_pull(skb, pull_len); +++ arg->channel = ev_hdr->channel; +++ arg->buf_len = ev_hdr->buf_len; +++ arg->status = ev_hdr->status; +++ arg->snr = ev_hdr->snr; +++ arg->phy_mode = ev_hdr->phy_mode; +++ arg->rate = ev_hdr->rate; +++ +++ msdu_len = __le32_to_cpu(arg->buf_len); +++ if (skb->len < msdu_len) +++ return -EPROTO; +++ +++ /* the WMI buffer might've ended up being padded to 4 bytes due to HTC +++ * trailer with credit update. Trim the excess garbage. +++ */ +++ skb_trim(skb, msdu_len); +++ +++ return 0; +++} +++ +++int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) +++{ +++ struct wmi_mgmt_rx_ev_arg arg = {}; ++ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); ++- struct ieee80211_channel *ch; ++ struct ieee80211_hdr *hdr; ++ u32 rx_status; ++ u32 channel; ++@@ -880,28 +1496,24 @@ static int ath10k_wmi_event_mgmt_rx(stru ++ u32 rate; ++ u32 buf_len; ++ u16 fc; ++- int pull_len; +++ int ret; ++ ++- if (test_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features)) { ++- ev_v2 = (struct wmi_mgmt_rx_event_v2 *)skb->data; ++- ev_hdr = &ev_v2->hdr.v1; ++- pull_len = sizeof(*ev_v2); ++- } else { ++- ev_v1 = (struct wmi_mgmt_rx_event_v1 *)skb->data; ++- ev_hdr = &ev_v1->hdr; ++- pull_len = sizeof(*ev_v1); +++ ret = ath10k_wmi_pull_mgmt_rx(ar, skb, &arg); +++ if (ret) { +++ ath10k_warn(ar, "failed to parse mgmt rx event: %d\n", ret); +++ return ret; ++ } ++ ++- channel = __le32_to_cpu(ev_hdr->channel); ++- buf_len = __le32_to_cpu(ev_hdr->buf_len); ++- rx_status = __le32_to_cpu(ev_hdr->status); ++- snr = __le32_to_cpu(ev_hdr->snr); ++- phy_mode = __le32_to_cpu(ev_hdr->phy_mode); ++- rate = __le32_to_cpu(ev_hdr->rate); +++ channel = __le32_to_cpu(arg.channel); +++ buf_len = __le32_to_cpu(arg.buf_len); +++ rx_status = __le32_to_cpu(arg.status); +++ snr = __le32_to_cpu(arg.snr); +++ phy_mode = __le32_to_cpu(arg.phy_mode); +++ rate = __le32_to_cpu(arg.rate); ++ ++ memset(status, 0, sizeof(*status)); ++ ++- ath10k_dbg(ATH10K_DBG_MGMT, +++ ath10k_dbg(ar, ATH10K_DBG_MGMT, ++ "event mgmt rx status %08x\n", rx_status); ++ ++ if (test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) { ++@@ -919,66 +1531,70 @@ static int ath10k_wmi_event_mgmt_rx(stru ++ return 0; ++ } ++ ++- if (rx_status & WMI_RX_STATUS_ERR_CRC) ++- status->flag |= RX_FLAG_FAILED_FCS_CRC; +++ if (rx_status & WMI_RX_STATUS_ERR_CRC) { +++ dev_kfree_skb(skb); +++ return 0; +++ } +++ ++ if (rx_status & WMI_RX_STATUS_ERR_MIC) ++ status->flag |= RX_FLAG_MMIC_ERROR; ++ ++- /* HW can Rx CCK rates on 5GHz. In that case phy_mode is set to +++ /* Hardware can Rx CCK rates on 5GHz. In that case phy_mode is set to ++ * MODE_11B. This means phy_mode is not a reliable source for the band ++- * of mgmt rx. */ ++- ++- ch = ar->scan_channel; ++- if (!ch) ++- ch = ar->rx_channel; ++- ++- if (ch) { ++- status->band = ch->band; ++- ++- if (phy_mode == MODE_11B && ++- status->band == IEEE80211_BAND_5GHZ) ++- ath10k_dbg(ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n"); +++ * of mgmt rx. +++ */ +++ if (channel >= 1 && channel <= 14) { +++ status->band = IEEE80211_BAND_2GHZ; +++ } else if (channel >= 36 && channel <= 165) { +++ status->band = IEEE80211_BAND_5GHZ; ++ } else { ++- ath10k_warn("using (unreliable) phy_mode to extract band for mgmt rx\n"); ++- status->band = phy_mode_to_band(phy_mode); +++ /* Shouldn't happen unless list of advertised channels to +++ * mac80211 has been changed. +++ */ +++ WARN_ON_ONCE(1); +++ dev_kfree_skb(skb); +++ return 0; ++ } ++ +++ if (phy_mode == MODE_11B && status->band == IEEE80211_BAND_5GHZ) +++ ath10k_dbg(ar, ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n"); +++ ++ status->freq = ieee80211_channel_to_frequency(channel, status->band); ++ status->signal = snr + ATH10K_DEFAULT_NOISE_FLOOR; ++ status->rate_idx = get_rate_idx(rate, status->band); ++ ++- skb_pull(skb, pull_len); ++- ++ hdr = (struct ieee80211_hdr *)skb->data; ++ fc = le16_to_cpu(hdr->frame_control); ++ +++ ath10k_wmi_handle_wep_reauth(ar, skb, status); +++ ++ /* FW delivers WEP Shared Auth frame with Protected Bit set and ++ * encrypted payload. However in case of PMF it delivers decrypted ++ * frames with Protected Bit set. */ ++ if (ieee80211_has_protected(hdr->frame_control) && ++ !ieee80211_is_auth(hdr->frame_control)) { ++- status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED | ++- RX_FLAG_MMIC_STRIPPED; ++- hdr->frame_control = __cpu_to_le16(fc & +++ status->flag |= RX_FLAG_DECRYPTED; +++ +++ if (!ieee80211_is_action(hdr->frame_control) && +++ !ieee80211_is_deauth(hdr->frame_control) && +++ !ieee80211_is_disassoc(hdr->frame_control)) { +++ status->flag |= RX_FLAG_IV_STRIPPED | +++ RX_FLAG_MMIC_STRIPPED; +++ hdr->frame_control = __cpu_to_le16(fc & ++ ~IEEE80211_FCTL_PROTECTED); +++ } ++ } ++ ++- ath10k_dbg(ATH10K_DBG_MGMT, +++ ath10k_dbg(ar, ATH10K_DBG_MGMT, ++ "event mgmt rx skb %p len %d ftype %02x stype %02x\n", ++ skb, skb->len, ++ fc & IEEE80211_FCTL_FTYPE, fc & IEEE80211_FCTL_STYPE); ++ ++- ath10k_dbg(ATH10K_DBG_MGMT, +++ ath10k_dbg(ar, ATH10K_DBG_MGMT, ++ "event mgmt rx freq %d band %d snr %d, rate_idx %d\n", ++ status->freq, status->band, status->signal, ++ status->rate_idx); ++ ++- /* ++- * packets from HTC come aligned to 4byte boundaries ++- * because they can originally come in along with a trailer ++- */ ++- skb_trim(skb, buf_len); ++- ++ ieee80211_rx(ar->hw, skb); ++ return 0; ++ } ++@@ -1002,37 +1618,65 @@ exit: ++ return idx; ++ } ++ ++-static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) +++static int ath10k_wmi_op_pull_ch_info_ev(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_ch_info_ev_arg *arg) +++{ +++ struct wmi_chan_info_event *ev = (void *)skb->data; +++ +++ if (skb->len < sizeof(*ev)) +++ return -EPROTO; +++ +++ skb_pull(skb, sizeof(*ev)); +++ arg->err_code = ev->err_code; +++ arg->freq = ev->freq; +++ arg->cmd_flags = ev->cmd_flags; +++ arg->noise_floor = ev->noise_floor; +++ arg->rx_clear_count = ev->rx_clear_count; +++ arg->cycle_count = ev->cycle_count; +++ +++ return 0; +++} +++ +++void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) ++ { ++- struct wmi_chan_info_event *ev; +++ struct wmi_ch_info_ev_arg arg = {}; ++ struct survey_info *survey; ++ u32 err_code, freq, cmd_flags, noise_floor, rx_clear_count, cycle_count; ++- int idx; +++ int idx, ret; ++ ++- ev = (struct wmi_chan_info_event *)skb->data; +++ ret = ath10k_wmi_pull_ch_info(ar, skb, &arg); +++ if (ret) { +++ ath10k_warn(ar, "failed to parse chan info event: %d\n", ret); +++ return; +++ } ++ ++- err_code = __le32_to_cpu(ev->err_code); ++- freq = __le32_to_cpu(ev->freq); ++- cmd_flags = __le32_to_cpu(ev->cmd_flags); ++- noise_floor = __le32_to_cpu(ev->noise_floor); ++- rx_clear_count = __le32_to_cpu(ev->rx_clear_count); ++- cycle_count = __le32_to_cpu(ev->cycle_count); +++ err_code = __le32_to_cpu(arg.err_code); +++ freq = __le32_to_cpu(arg.freq); +++ cmd_flags = __le32_to_cpu(arg.cmd_flags); +++ noise_floor = __le32_to_cpu(arg.noise_floor); +++ rx_clear_count = __le32_to_cpu(arg.rx_clear_count); +++ cycle_count = __le32_to_cpu(arg.cycle_count); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "chan info err_code %d freq %d cmd_flags %d noise_floor %d rx_clear_count %d cycle_count %d\n", ++ err_code, freq, cmd_flags, noise_floor, rx_clear_count, ++ cycle_count); ++ ++ spin_lock_bh(&ar->data_lock); ++ ++- if (!ar->scan.in_progress) { ++- ath10k_warn("chan info event without a scan request?\n"); +++ switch (ar->scan.state) { +++ case ATH10K_SCAN_IDLE: +++ case ATH10K_SCAN_STARTING: +++ ath10k_warn(ar, "received chan info event without a scan request, ignoring\n"); ++ goto exit; +++ case ATH10K_SCAN_RUNNING: +++ case ATH10K_SCAN_ABORTING: +++ break; ++ } ++ ++ idx = freq_to_idx(ar, freq); ++ if (idx >= ARRAY_SIZE(ar->survey)) { ++- ath10k_warn("chan info: invalid frequency %d (idx %d out of bounds)\n", +++ ath10k_warn(ar, "chan info: invalid frequency %d (idx %d out of bounds)\n", ++ freq, idx); ++ goto exit; ++ } ++@@ -1061,191 +1705,579 @@ exit: ++ spin_unlock_bh(&ar->data_lock); ++ } ++ ++-static void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb) +++void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n"); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n"); ++ } ++ ++-static int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb) +++int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_WMI, "wmi event debug mesg len %d\n", +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event debug mesg len %d\n", ++ skb->len); ++ ++- trace_ath10k_wmi_dbglog(skb->data, skb->len); +++ trace_ath10k_wmi_dbglog(ar, skb->data, skb->len); ++ ++ return 0; ++ } ++ ++-static void ath10k_wmi_event_update_stats(struct ath10k *ar, ++- struct sk_buff *skb) +++void ath10k_wmi_pull_pdev_stats_base(const struct wmi_pdev_stats_base *src, +++ struct ath10k_fw_stats_pdev *dst) ++ { ++- struct wmi_stats_event *ev = (struct wmi_stats_event *)skb->data; ++- ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n"); ++- ++- ath10k_debug_read_target_stats(ar, ev); ++-} ++- ++-static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, ++- struct sk_buff *skb) +++ dst->ch_noise_floor = __le32_to_cpu(src->chan_nf); +++ dst->tx_frame_count = __le32_to_cpu(src->tx_frame_count); +++ dst->rx_frame_count = __le32_to_cpu(src->rx_frame_count); +++ dst->rx_clear_count = __le32_to_cpu(src->rx_clear_count); +++ dst->cycle_count = __le32_to_cpu(src->cycle_count); +++ dst->phy_err_count = __le32_to_cpu(src->phy_err_count); +++ dst->chan_tx_power = __le32_to_cpu(src->chan_tx_pwr); +++} +++ +++void ath10k_wmi_pull_pdev_stats_tx(const struct wmi_pdev_stats_tx *src, +++ struct ath10k_fw_stats_pdev *dst) +++{ +++ dst->comp_queued = __le32_to_cpu(src->comp_queued); +++ dst->comp_delivered = __le32_to_cpu(src->comp_delivered); +++ dst->msdu_enqued = __le32_to_cpu(src->msdu_enqued); +++ dst->mpdu_enqued = __le32_to_cpu(src->mpdu_enqued); +++ dst->wmm_drop = __le32_to_cpu(src->wmm_drop); +++ dst->local_enqued = __le32_to_cpu(src->local_enqued); +++ dst->local_freed = __le32_to_cpu(src->local_freed); +++ dst->hw_queued = __le32_to_cpu(src->hw_queued); +++ dst->hw_reaped = __le32_to_cpu(src->hw_reaped); +++ dst->underrun = __le32_to_cpu(src->underrun); +++ dst->tx_abort = __le32_to_cpu(src->tx_abort); +++ dst->mpdus_requed = __le32_to_cpu(src->mpdus_requed); +++ dst->tx_ko = __le32_to_cpu(src->tx_ko); +++ dst->data_rc = __le32_to_cpu(src->data_rc); +++ dst->self_triggers = __le32_to_cpu(src->self_triggers); +++ dst->sw_retry_failure = __le32_to_cpu(src->sw_retry_failure); +++ dst->illgl_rate_phy_err = __le32_to_cpu(src->illgl_rate_phy_err); +++ dst->pdev_cont_xretry = __le32_to_cpu(src->pdev_cont_xretry); +++ dst->pdev_tx_timeout = __le32_to_cpu(src->pdev_tx_timeout); +++ dst->pdev_resets = __le32_to_cpu(src->pdev_resets); +++ dst->phy_underrun = __le32_to_cpu(src->phy_underrun); +++ dst->txop_ovf = __le32_to_cpu(src->txop_ovf); +++} +++ +++void ath10k_wmi_pull_pdev_stats_rx(const struct wmi_pdev_stats_rx *src, +++ struct ath10k_fw_stats_pdev *dst) +++{ +++ dst->mid_ppdu_route_change = __le32_to_cpu(src->mid_ppdu_route_change); +++ dst->status_rcvd = __le32_to_cpu(src->status_rcvd); +++ dst->r0_frags = __le32_to_cpu(src->r0_frags); +++ dst->r1_frags = __le32_to_cpu(src->r1_frags); +++ dst->r2_frags = __le32_to_cpu(src->r2_frags); +++ dst->r3_frags = __le32_to_cpu(src->r3_frags); +++ dst->htt_msdus = __le32_to_cpu(src->htt_msdus); +++ dst->htt_mpdus = __le32_to_cpu(src->htt_mpdus); +++ dst->loc_msdus = __le32_to_cpu(src->loc_msdus); +++ dst->loc_mpdus = __le32_to_cpu(src->loc_mpdus); +++ dst->oversize_amsdu = __le32_to_cpu(src->oversize_amsdu); +++ dst->phy_errs = __le32_to_cpu(src->phy_errs); +++ dst->phy_err_drop = __le32_to_cpu(src->phy_err_drop); +++ dst->mpdu_errs = __le32_to_cpu(src->mpdu_errs); +++} +++ +++void ath10k_wmi_pull_pdev_stats_extra(const struct wmi_pdev_stats_extra *src, +++ struct ath10k_fw_stats_pdev *dst) +++{ +++ dst->ack_rx_bad = __le32_to_cpu(src->ack_rx_bad); +++ dst->rts_bad = __le32_to_cpu(src->rts_bad); +++ dst->rts_good = __le32_to_cpu(src->rts_good); +++ dst->fcs_bad = __le32_to_cpu(src->fcs_bad); +++ dst->no_beacons = __le32_to_cpu(src->no_beacons); +++ dst->mib_int_count = __le32_to_cpu(src->mib_int_count); +++} +++ +++void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src, +++ struct ath10k_fw_stats_peer *dst) +++{ +++ ether_addr_copy(dst->peer_macaddr, src->peer_macaddr.addr); +++ dst->peer_rssi = __le32_to_cpu(src->peer_rssi); +++ dst->peer_tx_rate = __le32_to_cpu(src->peer_tx_rate); +++} +++ +++static int ath10k_wmi_main_op_pull_fw_stats(struct ath10k *ar, +++ struct sk_buff *skb, +++ struct ath10k_fw_stats *stats) ++ { ++- struct wmi_vdev_start_response_event *ev; +++ const struct wmi_stats_event *ev = (void *)skb->data; +++ u32 num_pdev_stats, num_vdev_stats, num_peer_stats; +++ int i; ++ ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n"); +++ if (!skb_pull(skb, sizeof(*ev))) +++ return -EPROTO; ++ ++- ev = (struct wmi_vdev_start_response_event *)skb->data; +++ num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); +++ num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); +++ num_peer_stats = __le32_to_cpu(ev->num_peer_stats); +++ +++ for (i = 0; i < num_pdev_stats; i++) { +++ const struct wmi_pdev_stats *src; +++ struct ath10k_fw_stats_pdev *dst; +++ +++ src = (void *)skb->data; +++ if (!skb_pull(skb, sizeof(*src))) +++ return -EPROTO; ++ ++- if (WARN_ON(__le32_to_cpu(ev->status))) ++- return; +++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC); +++ if (!dst) +++ continue; ++ ++- complete(&ar->vdev_setup_done); ++-} +++ ath10k_wmi_pull_pdev_stats_base(&src->base, dst); +++ ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst); +++ ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst); ++ ++-static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, ++- struct sk_buff *skb) ++-{ ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_STOPPED_EVENTID\n"); ++- complete(&ar->vdev_setup_done); ++-} +++ list_add_tail(&dst->list, &stats->pdevs); +++ } ++ ++-static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, ++- struct sk_buff *skb) ++-{ ++- struct wmi_peer_sta_kickout_event *ev; ++- struct ieee80211_sta *sta; +++ /* fw doesn't implement vdev stats */ ++ ++- ev = (struct wmi_peer_sta_kickout_event *)skb->data; +++ for (i = 0; i < num_peer_stats; i++) { +++ const struct wmi_peer_stats *src; +++ struct ath10k_fw_stats_peer *dst; ++ ++- ath10k_dbg(ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n", ++- ev->peer_macaddr.addr); +++ src = (void *)skb->data; +++ if (!skb_pull(skb, sizeof(*src))) +++ return -EPROTO; ++ ++- rcu_read_lock(); +++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC); +++ if (!dst) +++ continue; ++ ++- sta = ieee80211_find_sta_by_ifaddr(ar->hw, ev->peer_macaddr.addr, NULL); ++- if (!sta) { ++- ath10k_warn("Spurious quick kickout for STA %pM\n", ++- ev->peer_macaddr.addr); ++- goto exit; +++ ath10k_wmi_pull_peer_stats(src, dst); +++ list_add_tail(&dst->list, &stats->peers); ++ } ++ ++- ieee80211_report_low_ack(sta, 10); ++- ++-exit: ++- rcu_read_unlock(); +++ return 0; ++ } ++ ++-/* ++- * FIXME ++- * ++- * We don't report to mac80211 sleep state of connected ++- * stations. Due to this mac80211 can't fill in TIM IE ++- * correctly. ++- * ++- * I know of no way of getting nullfunc frames that contain ++- * sleep transition from connected stations - these do not ++- * seem to be sent from the target to the host. There also ++- * doesn't seem to be a dedicated event for that. So the ++- * only way left to do this would be to read tim_bitmap ++- * during SWBA. ++- * ++- * We could probably try using tim_bitmap from SWBA to tell ++- * mac80211 which stations are asleep and which are not. The ++- * problem here is calling mac80211 functions so many times ++- * could take too long and make us miss the time to submit ++- * the beacon to the target. ++- * ++- * So as a workaround we try to extend the TIM IE if there ++- * is unicast buffered for stations with aid > 7 and fill it ++- * in ourselves. ++- */ ++-static void ath10k_wmi_update_tim(struct ath10k *ar, ++- struct ath10k_vif *arvif, ++- struct sk_buff *bcn, ++- struct wmi_bcn_info *bcn_info) +++static int ath10k_wmi_10x_op_pull_fw_stats(struct ath10k *ar, +++ struct sk_buff *skb, +++ struct ath10k_fw_stats *stats) ++ { ++- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)bcn->data; ++- struct ieee80211_tim_ie *tim; ++- u8 *ies, *ie; ++- u8 ie_len, pvm_len; +++ const struct wmi_stats_event *ev = (void *)skb->data; +++ u32 num_pdev_stats, num_vdev_stats, num_peer_stats; +++ int i; ++ ++- /* if next SWBA has no tim_changed the tim_bitmap is garbage. ++- * we must copy the bitmap upon change and reuse it later */ ++- if (__le32_to_cpu(bcn_info->tim_info.tim_changed)) { ++- int i; +++ if (!skb_pull(skb, sizeof(*ev))) +++ return -EPROTO; ++ ++- BUILD_BUG_ON(sizeof(arvif->u.ap.tim_bitmap) != ++- sizeof(bcn_info->tim_info.tim_bitmap)); +++ num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); +++ num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); +++ num_peer_stats = __le32_to_cpu(ev->num_peer_stats); +++ +++ for (i = 0; i < num_pdev_stats; i++) { +++ const struct wmi_10x_pdev_stats *src; +++ struct ath10k_fw_stats_pdev *dst; +++ +++ src = (void *)skb->data; +++ if (!skb_pull(skb, sizeof(*src))) +++ return -EPROTO; ++ ++- for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++) { ++- __le32 t = bcn_info->tim_info.tim_bitmap[i / 4]; ++- u32 v = __le32_to_cpu(t); ++- arvif->u.ap.tim_bitmap[i] = (v >> ((i % 4) * 8)) & 0xFF; ++- } +++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC); +++ if (!dst) +++ continue; ++ ++- /* FW reports either length 0 or 16 ++- * so we calculate this on our own */ ++- arvif->u.ap.tim_len = 0; ++- for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++) ++- if (arvif->u.ap.tim_bitmap[i]) ++- arvif->u.ap.tim_len = i; +++ ath10k_wmi_pull_pdev_stats_base(&src->base, dst); +++ ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst); +++ ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst); +++ ath10k_wmi_pull_pdev_stats_extra(&src->extra, dst); ++ ++- arvif->u.ap.tim_len++; +++ list_add_tail(&dst->list, &stats->pdevs); ++ } ++ ++- ies = bcn->data; ++- ies += ieee80211_hdrlen(hdr->frame_control); ++- ies += 12; /* fixed parameters */ +++ /* fw doesn't implement vdev stats */ ++ ++- ie = (u8 *)cfg80211_find_ie(WLAN_EID_TIM, ies, ++- (u8 *)skb_tail_pointer(bcn) - ies); ++- if (!ie) { ++- if (arvif->vdev_type != WMI_VDEV_TYPE_IBSS) ++- ath10k_warn("no tim ie found;\n"); ++- return; ++- } +++ for (i = 0; i < num_peer_stats; i++) { +++ const struct wmi_10x_peer_stats *src; +++ struct ath10k_fw_stats_peer *dst; ++ ++- tim = (void *)ie + 2; ++- ie_len = ie[1]; ++- pvm_len = ie_len - 3; /* exclude dtim count, dtim period, bmap ctl */ +++ src = (void *)skb->data; +++ if (!skb_pull(skb, sizeof(*src))) +++ return -EPROTO; ++ ++- if (pvm_len < arvif->u.ap.tim_len) { ++- int expand_size = sizeof(arvif->u.ap.tim_bitmap) - pvm_len; ++- int move_size = skb_tail_pointer(bcn) - (ie + 2 + ie_len); ++- void *next_ie = ie + 2 + ie_len; +++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC); +++ if (!dst) +++ continue; ++ ++- if (skb_put(bcn, expand_size)) { ++- memmove(next_ie + expand_size, next_ie, move_size); +++ ath10k_wmi_pull_peer_stats(&src->old, dst); ++ ++- ie[1] += expand_size; ++- ie_len += expand_size; ++- pvm_len += expand_size; ++- } else { ++- ath10k_warn("tim expansion failed\n"); ++- } ++- } +++ dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate); ++ ++- if (pvm_len > sizeof(arvif->u.ap.tim_bitmap)) { ++- ath10k_warn("tim pvm length is too great (%d)\n", pvm_len); ++- return; +++ list_add_tail(&dst->list, &stats->peers); ++ } ++ ++- tim->bitmap_ctrl = !!__le32_to_cpu(bcn_info->tim_info.tim_mcast); ++- memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len); +++ return 0; +++} ++ ++- if (tim->dtim_count == 0) { ++- ATH10K_SKB_CB(bcn)->bcn.dtim_zero = true; +++static int ath10k_wmi_10_2_op_pull_fw_stats(struct ath10k *ar, +++ struct sk_buff *skb, +++ struct ath10k_fw_stats *stats) +++{ +++ const struct wmi_10_2_stats_event *ev = (void *)skb->data; +++ u32 num_pdev_stats; +++ u32 num_pdev_ext_stats; +++ u32 num_vdev_stats; +++ u32 num_peer_stats; +++ int i; ++ ++- if (__le32_to_cpu(bcn_info->tim_info.tim_mcast) == 1) ++- ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true; ++- } +++ if (!skb_pull(skb, sizeof(*ev))) +++ return -EPROTO; ++ ++- ath10k_dbg(ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n", ++- tim->dtim_count, tim->dtim_period, ++- tim->bitmap_ctrl, pvm_len); +++ num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); +++ num_pdev_ext_stats = __le32_to_cpu(ev->num_pdev_ext_stats); +++ num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); +++ num_peer_stats = __le32_to_cpu(ev->num_peer_stats); +++ +++ for (i = 0; i < num_pdev_stats; i++) { +++ const struct wmi_10_2_pdev_stats *src; +++ struct ath10k_fw_stats_pdev *dst; +++ +++ src = (void *)skb->data; +++ if (!skb_pull(skb, sizeof(*src))) +++ return -EPROTO; +++ +++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC); +++ if (!dst) +++ continue; +++ +++ ath10k_wmi_pull_pdev_stats_base(&src->base, dst); +++ ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst); +++ ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst); +++ ath10k_wmi_pull_pdev_stats_extra(&src->extra, dst); +++ /* FIXME: expose 10.2 specific values */ +++ +++ list_add_tail(&dst->list, &stats->pdevs); +++ } +++ +++ for (i = 0; i < num_pdev_ext_stats; i++) { +++ const struct wmi_10_2_pdev_ext_stats *src; +++ +++ src = (void *)skb->data; +++ if (!skb_pull(skb, sizeof(*src))) +++ return -EPROTO; +++ +++ /* FIXME: expose values to userspace +++ * +++ * Note: Even though this loop seems to do nothing it is +++ * required to parse following sub-structures properly. +++ */ +++ } +++ +++ /* fw doesn't implement vdev stats */ +++ +++ for (i = 0; i < num_peer_stats; i++) { +++ const struct wmi_10_2_peer_stats *src; +++ struct ath10k_fw_stats_peer *dst; +++ +++ src = (void *)skb->data; +++ if (!skb_pull(skb, sizeof(*src))) +++ return -EPROTO; +++ +++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC); +++ if (!dst) +++ continue; +++ +++ ath10k_wmi_pull_peer_stats(&src->old, dst); +++ +++ dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate); +++ /* FIXME: expose 10.2 specific values */ +++ +++ list_add_tail(&dst->list, &stats->peers); +++ } +++ +++ return 0; +++} +++ +++static int ath10k_wmi_10_2_4_op_pull_fw_stats(struct ath10k *ar, +++ struct sk_buff *skb, +++ struct ath10k_fw_stats *stats) +++{ +++ const struct wmi_10_2_stats_event *ev = (void *)skb->data; +++ u32 num_pdev_stats; +++ u32 num_pdev_ext_stats; +++ u32 num_vdev_stats; +++ u32 num_peer_stats; +++ int i; +++ +++ if (!skb_pull(skb, sizeof(*ev))) +++ return -EPROTO; +++ +++ num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); +++ num_pdev_ext_stats = __le32_to_cpu(ev->num_pdev_ext_stats); +++ num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); +++ num_peer_stats = __le32_to_cpu(ev->num_peer_stats); +++ +++ for (i = 0; i < num_pdev_stats; i++) { +++ const struct wmi_10_2_pdev_stats *src; +++ struct ath10k_fw_stats_pdev *dst; +++ +++ src = (void *)skb->data; +++ if (!skb_pull(skb, sizeof(*src))) +++ return -EPROTO; +++ +++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC); +++ if (!dst) +++ continue; +++ +++ ath10k_wmi_pull_pdev_stats_base(&src->base, dst); +++ ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst); +++ ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst); +++ ath10k_wmi_pull_pdev_stats_extra(&src->extra, dst); +++ /* FIXME: expose 10.2 specific values */ +++ +++ list_add_tail(&dst->list, &stats->pdevs); +++ } +++ +++ for (i = 0; i < num_pdev_ext_stats; i++) { +++ const struct wmi_10_2_pdev_ext_stats *src; +++ +++ src = (void *)skb->data; +++ if (!skb_pull(skb, sizeof(*src))) +++ return -EPROTO; +++ +++ /* FIXME: expose values to userspace +++ * +++ * Note: Even though this loop seems to do nothing it is +++ * required to parse following sub-structures properly. +++ */ +++ } +++ +++ /* fw doesn't implement vdev stats */ +++ +++ for (i = 0; i < num_peer_stats; i++) { +++ const struct wmi_10_2_4_peer_stats *src; +++ struct ath10k_fw_stats_peer *dst; +++ +++ src = (void *)skb->data; +++ if (!skb_pull(skb, sizeof(*src))) +++ return -EPROTO; +++ +++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC); +++ if (!dst) +++ continue; +++ +++ ath10k_wmi_pull_peer_stats(&src->common.old, dst); +++ +++ dst->peer_rx_rate = __le32_to_cpu(src->common.peer_rx_rate); +++ /* FIXME: expose 10.2 specific values */ +++ +++ list_add_tail(&dst->list, &stats->peers); +++ } +++ +++ return 0; +++} +++ +++void ath10k_wmi_event_update_stats(struct ath10k *ar, struct sk_buff *skb) +++{ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n"); +++ ath10k_debug_fw_stats_process(ar, skb); +++} +++ +++static int +++ath10k_wmi_op_pull_vdev_start_ev(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_vdev_start_ev_arg *arg) +++{ +++ struct wmi_vdev_start_response_event *ev = (void *)skb->data; +++ +++ if (skb->len < sizeof(*ev)) +++ return -EPROTO; +++ +++ skb_pull(skb, sizeof(*ev)); +++ arg->vdev_id = ev->vdev_id; +++ arg->req_id = ev->req_id; +++ arg->resp_type = ev->resp_type; +++ arg->status = ev->status; +++ +++ return 0; +++} +++ +++void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, struct sk_buff *skb) +++{ +++ struct wmi_vdev_start_ev_arg arg = {}; +++ int ret; +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n"); +++ +++ ret = ath10k_wmi_pull_vdev_start(ar, skb, &arg); +++ if (ret) { +++ ath10k_warn(ar, "failed to parse vdev start event: %d\n", ret); +++ return; +++ } +++ +++ if (WARN_ON(__le32_to_cpu(arg.status))) +++ return; +++ +++ complete(&ar->vdev_setup_done); +++} +++ +++void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, struct sk_buff *skb) +++{ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_STOPPED_EVENTID\n"); +++ complete(&ar->vdev_setup_done); +++} +++ +++static int +++ath10k_wmi_op_pull_peer_kick_ev(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_peer_kick_ev_arg *arg) +++{ +++ struct wmi_peer_sta_kickout_event *ev = (void *)skb->data; +++ +++ if (skb->len < sizeof(*ev)) +++ return -EPROTO; +++ +++ skb_pull(skb, sizeof(*ev)); +++ arg->mac_addr = ev->peer_macaddr.addr; +++ +++ return 0; +++} +++ +++void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, struct sk_buff *skb) +++{ +++ struct wmi_peer_kick_ev_arg arg = {}; +++ struct ieee80211_sta *sta; +++ int ret; +++ +++ ret = ath10k_wmi_pull_peer_kick(ar, skb, &arg); +++ if (ret) { +++ ath10k_warn(ar, "failed to parse peer kickout event: %d\n", +++ ret); +++ return; +++ } +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n", +++ arg.mac_addr); +++ +++ rcu_read_lock(); +++ +++ sta = ieee80211_find_sta_by_ifaddr(ar->hw, arg.mac_addr, NULL); +++ if (!sta) { +++ ath10k_warn(ar, "Spurious quick kickout for STA %pM\n", +++ arg.mac_addr); +++ goto exit; +++ } +++ +++ ieee80211_report_low_ack(sta, 10); +++ +++exit: +++ rcu_read_unlock(); +++} +++ +++/* +++ * FIXME +++ * +++ * We don't report to mac80211 sleep state of connected +++ * stations. Due to this mac80211 can't fill in TIM IE +++ * correctly. +++ * +++ * I know of no way of getting nullfunc frames that contain +++ * sleep transition from connected stations - these do not +++ * seem to be sent from the target to the host. There also +++ * doesn't seem to be a dedicated event for that. So the +++ * only way left to do this would be to read tim_bitmap +++ * during SWBA. +++ * +++ * We could probably try using tim_bitmap from SWBA to tell +++ * mac80211 which stations are asleep and which are not. The +++ * problem here is calling mac80211 functions so many times +++ * could take too long and make us miss the time to submit +++ * the beacon to the target. +++ * +++ * So as a workaround we try to extend the TIM IE if there +++ * is unicast buffered for stations with aid > 7 and fill it +++ * in ourselves. +++ */ +++static void ath10k_wmi_update_tim(struct ath10k *ar, +++ struct ath10k_vif *arvif, +++ struct sk_buff *bcn, +++ const struct wmi_tim_info *tim_info) +++{ +++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)bcn->data; +++ struct ieee80211_tim_ie *tim; +++ u8 *ies, *ie; +++ u8 ie_len, pvm_len; +++ __le32 t; +++ u32 v; +++ +++ /* if next SWBA has no tim_changed the tim_bitmap is garbage. +++ * we must copy the bitmap upon change and reuse it later */ +++ if (__le32_to_cpu(tim_info->tim_changed)) { +++ int i; +++ +++ BUILD_BUG_ON(sizeof(arvif->u.ap.tim_bitmap) != +++ sizeof(tim_info->tim_bitmap)); +++ +++ for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++) { +++ t = tim_info->tim_bitmap[i / 4]; +++ v = __le32_to_cpu(t); +++ arvif->u.ap.tim_bitmap[i] = (v >> ((i % 4) * 8)) & 0xFF; +++ } +++ +++ /* FW reports either length 0 or 16 +++ * so we calculate this on our own */ +++ arvif->u.ap.tim_len = 0; +++ for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++) +++ if (arvif->u.ap.tim_bitmap[i]) +++ arvif->u.ap.tim_len = i; +++ +++ arvif->u.ap.tim_len++; +++ } +++ +++ ies = bcn->data; +++ ies += ieee80211_hdrlen(hdr->frame_control); +++ ies += 12; /* fixed parameters */ +++ +++ ie = (u8 *)cfg80211_find_ie(WLAN_EID_TIM, ies, +++ (u8 *)skb_tail_pointer(bcn) - ies); +++ if (!ie) { +++ if (arvif->vdev_type != WMI_VDEV_TYPE_IBSS) +++ ath10k_warn(ar, "no tim ie found;\n"); +++ return; +++ } +++ +++ tim = (void *)ie + 2; +++ ie_len = ie[1]; +++ pvm_len = ie_len - 3; /* exclude dtim count, dtim period, bmap ctl */ +++ +++ if (pvm_len < arvif->u.ap.tim_len) { +++ int expand_size = sizeof(arvif->u.ap.tim_bitmap) - pvm_len; +++ int move_size = skb_tail_pointer(bcn) - (ie + 2 + ie_len); +++ void *next_ie = ie + 2 + ie_len; +++ +++ if (skb_put(bcn, expand_size)) { +++ memmove(next_ie + expand_size, next_ie, move_size); +++ +++ ie[1] += expand_size; +++ ie_len += expand_size; +++ pvm_len += expand_size; +++ } else { +++ ath10k_warn(ar, "tim expansion failed\n"); +++ } +++ } +++ +++ if (pvm_len > sizeof(arvif->u.ap.tim_bitmap)) { +++ ath10k_warn(ar, "tim pvm length is too great (%d)\n", pvm_len); +++ return; +++ } +++ +++ tim->bitmap_ctrl = !!__le32_to_cpu(tim_info->tim_mcast); +++ memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len); +++ +++ if (tim->dtim_count == 0) { +++ ATH10K_SKB_CB(bcn)->bcn.dtim_zero = true; +++ +++ if (__le32_to_cpu(tim_info->tim_mcast) == 1) +++ ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true; +++ } +++ +++ ath10k_dbg(ar, ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n", +++ tim->dtim_count, tim->dtim_period, +++ tim->bitmap_ctrl, pvm_len); ++ } ++ ++ static void ath10k_p2p_fill_noa_ie(u8 *data, u32 len, ++- struct wmi_p2p_noa_info *noa) +++ const struct wmi_p2p_noa_info *noa) ++ { ++ struct ieee80211_p2p_noa_attr *noa_attr; ++ u8 ctwindow_oppps = noa->ctwindow_oppps; ++@@ -1287,14 +2319,13 @@ static void ath10k_p2p_fill_noa_ie(u8 *d ++ *noa_attr_len = __cpu_to_le16(attr_len); ++ } ++ ++-static u32 ath10k_p2p_calc_noa_ie_len(struct wmi_p2p_noa_info *noa) +++static u32 ath10k_p2p_calc_noa_ie_len(const struct wmi_p2p_noa_info *noa) ++ { ++ u32 len = 0; ++ u8 noa_descriptors = noa->num_descriptors; ++ u8 opp_ps_info = noa->ctwindow_oppps; ++ bool opps_enabled = !!(opp_ps_info & WMI_P2P_OPPPS_ENABLE_BIT); ++ ++- ++ if (!noa_descriptors && !opps_enabled) ++ return len; ++ ++@@ -1308,16 +2339,15 @@ static u32 ath10k_p2p_calc_noa_ie_len(st ++ ++ static void ath10k_wmi_update_noa(struct ath10k *ar, struct ath10k_vif *arvif, ++ struct sk_buff *bcn, ++- struct wmi_bcn_info *bcn_info) +++ const struct wmi_p2p_noa_info *noa) ++ { ++- struct wmi_p2p_noa_info *noa = &bcn_info->p2p_noa_info; ++ u8 *new_data, *old_data = arvif->u.ap.noa_data; ++ u32 new_len; ++ ++ if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO) ++ return; ++ ++- ath10k_dbg(ATH10K_DBG_MGMT, "noa changed: %d\n", noa->changed); +++ ath10k_dbg(ar, ATH10K_DBG_MGMT, "noa changed: %d\n", noa->changed); ++ if (noa->changed & WMI_P2P_NOA_CHANGED_BIT) { ++ new_len = ath10k_p2p_calc_noa_ie_len(noa); ++ if (!new_len) ++@@ -1351,22 +2381,59 @@ cleanup: ++ kfree(old_data); ++ } ++ +++static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_swba_ev_arg *arg) +++{ +++ struct wmi_host_swba_event *ev = (void *)skb->data; +++ u32 map; +++ size_t i; +++ +++ if (skb->len < sizeof(*ev)) +++ return -EPROTO; +++ +++ skb_pull(skb, sizeof(*ev)); +++ arg->vdev_map = ev->vdev_map; +++ +++ for (i = 0, map = __le32_to_cpu(ev->vdev_map); map; map >>= 1) { +++ if (!(map & BIT(0))) +++ continue; +++ +++ /* If this happens there were some changes in firmware and +++ * ath10k should update the max size of tim_info array. +++ */ +++ if (WARN_ON_ONCE(i == ARRAY_SIZE(arg->tim_info))) +++ break; +++ +++ arg->tim_info[i] = &ev->bcn_info[i].tim_info; +++ arg->noa_info[i] = &ev->bcn_info[i].p2p_noa_info; +++ i++; +++ } +++ +++ return 0; +++} ++ ++-static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) +++void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) ++ { ++- struct wmi_host_swba_event *ev; +++ struct wmi_swba_ev_arg arg = {}; ++ u32 map; ++ int i = -1; ++- struct wmi_bcn_info *bcn_info; +++ const struct wmi_tim_info *tim_info; +++ const struct wmi_p2p_noa_info *noa_info; ++ struct ath10k_vif *arvif; ++ struct sk_buff *bcn; +++ dma_addr_t paddr; ++ int ret, vdev_id = 0; ++ ++- ev = (struct wmi_host_swba_event *)skb->data; ++- map = __le32_to_cpu(ev->vdev_map); +++ ret = ath10k_wmi_pull_swba(ar, skb, &arg); +++ if (ret) { +++ ath10k_warn(ar, "failed to parse swba event: %d\n", ret); +++ return; +++ } +++ +++ map = __le32_to_cpu(arg.vdev_map); ++ ++- ath10k_dbg(ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n", ++- ev->vdev_map); +++ ath10k_dbg(ar, ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n", +++ map); ++ ++ for (; map; map >>= 1, vdev_id++) { ++ if (!(map & 0x1)) ++@@ -1375,27 +2442,29 @@ static void ath10k_wmi_event_host_swba(s ++ i++; ++ ++ if (i >= WMI_MAX_AP_VDEV) { ++- ath10k_warn("swba has corrupted vdev map\n"); +++ ath10k_warn(ar, "swba has corrupted vdev map\n"); ++ break; ++ } ++ ++- bcn_info = &ev->bcn_info[i]; +++ tim_info = arg.tim_info[i]; +++ noa_info = arg.noa_info[i]; ++ ++- ath10k_dbg(ATH10K_DBG_MGMT, +++ ath10k_dbg(ar, ATH10K_DBG_MGMT, ++ "mgmt event bcn_info %d tim_len %d mcast %d changed %d num_ps_pending %d bitmap 0x%08x%08x%08x%08x\n", ++ i, ++- __le32_to_cpu(bcn_info->tim_info.tim_len), ++- __le32_to_cpu(bcn_info->tim_info.tim_mcast), ++- __le32_to_cpu(bcn_info->tim_info.tim_changed), ++- __le32_to_cpu(bcn_info->tim_info.tim_num_ps_pending), ++- __le32_to_cpu(bcn_info->tim_info.tim_bitmap[3]), ++- __le32_to_cpu(bcn_info->tim_info.tim_bitmap[2]), ++- __le32_to_cpu(bcn_info->tim_info.tim_bitmap[1]), ++- __le32_to_cpu(bcn_info->tim_info.tim_bitmap[0])); +++ __le32_to_cpu(tim_info->tim_len), +++ __le32_to_cpu(tim_info->tim_mcast), +++ __le32_to_cpu(tim_info->tim_changed), +++ __le32_to_cpu(tim_info->tim_num_ps_pending), +++ __le32_to_cpu(tim_info->tim_bitmap[3]), +++ __le32_to_cpu(tim_info->tim_bitmap[2]), +++ __le32_to_cpu(tim_info->tim_bitmap[1]), +++ __le32_to_cpu(tim_info->tim_bitmap[0])); ++ ++ arvif = ath10k_get_arvif(ar, vdev_id); ++ if (arvif == NULL) { ++- ath10k_warn("no vif for vdev_id %d found\n", vdev_id); +++ ath10k_warn(ar, "no vif for vdev_id %d found\n", +++ vdev_id); ++ continue; ++ } ++ ++@@ -1412,57 +2481,77 @@ static void ath10k_wmi_event_host_swba(s ++ ++ bcn = ieee80211_beacon_get(ar->hw, arvif->vif); ++ if (!bcn) { ++- ath10k_warn("could not get mac80211 beacon\n"); +++ ath10k_warn(ar, "could not get mac80211 beacon\n"); ++ continue; ++ } ++ ++- ath10k_tx_h_seq_no(bcn); ++- ath10k_wmi_update_tim(ar, arvif, bcn, bcn_info); ++- ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info); +++ ath10k_tx_h_seq_no(arvif->vif, bcn); +++ ath10k_wmi_update_tim(ar, arvif, bcn, tim_info); +++ ath10k_wmi_update_noa(ar, arvif, bcn, noa_info); ++ ++ spin_lock_bh(&ar->data_lock); ++ ++ if (arvif->beacon) { ++- if (!arvif->beacon_sent) ++- ath10k_warn("SWBA overrun on vdev %d\n", +++ switch (arvif->beacon_state) { +++ case ATH10K_BEACON_SENT: +++ break; +++ case ATH10K_BEACON_SCHEDULED: +++ ath10k_warn(ar, "SWBA overrun on vdev %d, skipped old beacon\n", ++ arvif->vdev_id); +++ break; +++ case ATH10K_BEACON_SENDING: +++ ath10k_warn(ar, "SWBA overrun on vdev %d, skipped new beacon\n", +++ arvif->vdev_id); +++ dev_kfree_skb(bcn); +++ goto skip; +++ } ++ ++- dma_unmap_single(arvif->ar->dev, ++- ATH10K_SKB_CB(arvif->beacon)->paddr, ++- arvif->beacon->len, DMA_TO_DEVICE); ++- dev_kfree_skb_any(arvif->beacon); ++- arvif->beacon = NULL; +++ ath10k_mac_vif_beacon_free(arvif); ++ } ++ ++- ATH10K_SKB_CB(bcn)->paddr = dma_map_single(arvif->ar->dev, ++- bcn->data, bcn->len, ++- DMA_TO_DEVICE); ++- ret = dma_mapping_error(arvif->ar->dev, ++- ATH10K_SKB_CB(bcn)->paddr); ++- if (ret) { ++- ath10k_warn("failed to map beacon: %d\n", ret); ++- dev_kfree_skb_any(bcn); ++- goto skip; +++ if (!arvif->beacon_buf) { +++ paddr = dma_map_single(arvif->ar->dev, bcn->data, +++ bcn->len, DMA_TO_DEVICE); +++ ret = dma_mapping_error(arvif->ar->dev, paddr); +++ if (ret) { +++ ath10k_warn(ar, "failed to map beacon: %d\n", +++ ret); +++ dev_kfree_skb_any(bcn); +++ goto skip; +++ } +++ +++ ATH10K_SKB_CB(bcn)->paddr = paddr; +++ } else { +++ if (bcn->len > IEEE80211_MAX_FRAME_LEN) { +++ ath10k_warn(ar, "trimming beacon %d -> %d bytes!\n", +++ bcn->len, IEEE80211_MAX_FRAME_LEN); +++ skb_trim(bcn, IEEE80211_MAX_FRAME_LEN); +++ } +++ memcpy(arvif->beacon_buf, bcn->data, bcn->len); +++ ATH10K_SKB_CB(bcn)->paddr = arvif->beacon_paddr; ++ } ++ ++ arvif->beacon = bcn; ++- arvif->beacon_sent = false; +++ arvif->beacon_state = ATH10K_BEACON_SCHEDULED; +++ +++ trace_ath10k_tx_hdr(ar, bcn->data, bcn->len); +++ trace_ath10k_tx_payload(ar, bcn->data, bcn->len); ++ ++- ath10k_wmi_tx_beacon_nowait(arvif); ++ skip: ++ spin_unlock_bh(&ar->data_lock); ++ } +++ +++ ath10k_wmi_tx_beacons_nowait(ar); ++ } ++ ++-static void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, ++- struct sk_buff *skb) +++void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n"); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n"); ++ } ++ ++ static void ath10k_dfs_radar_report(struct ath10k *ar, ++- struct wmi_single_phyerr_rx_event *event, ++- struct phyerr_radar_report *rr, +++ const struct wmi_phyerr *phyerr, +++ const struct phyerr_radar_report *rr, ++ u64 tsf) ++ { ++ u32 reg0, reg1, tsf32l; ++@@ -1473,20 +2562,20 @@ static void ath10k_dfs_radar_report(stru ++ reg0 = __le32_to_cpu(rr->reg0); ++ reg1 = __le32_to_cpu(rr->reg1); ++ ++- ath10k_dbg(ATH10K_DBG_REGULATORY, +++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY, ++ "wmi phyerr radar report chirp %d max_width %d agc_total_gain %d pulse_delta_diff %d\n", ++ MS(reg0, RADAR_REPORT_REG0_PULSE_IS_CHIRP), ++ MS(reg0, RADAR_REPORT_REG0_PULSE_IS_MAX_WIDTH), ++ MS(reg0, RADAR_REPORT_REG0_AGC_TOTAL_GAIN), ++ MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_DIFF)); ++- ath10k_dbg(ATH10K_DBG_REGULATORY, +++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY, ++ "wmi phyerr radar report pulse_delta_pean %d pulse_sidx %d fft_valid %d agc_mb_gain %d subchan_mask %d\n", ++ MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_PEAK), ++ MS(reg0, RADAR_REPORT_REG0_PULSE_SIDX), ++ MS(reg1, RADAR_REPORT_REG1_PULSE_SRCH_FFT_VALID), ++ MS(reg1, RADAR_REPORT_REG1_PULSE_AGC_MB_GAIN), ++ MS(reg1, RADAR_REPORT_REG1_PULSE_SUBCHAN_MASK)); ++- ath10k_dbg(ATH10K_DBG_REGULATORY, +++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY, ++ "wmi phyerr radar report pulse_tsf_offset 0x%X pulse_dur: %d\n", ++ MS(reg1, RADAR_REPORT_REG1_PULSE_TSF_OFFSET), ++ MS(reg1, RADAR_REPORT_REG1_PULSE_DUR)); ++@@ -1495,12 +2584,12 @@ static void ath10k_dfs_radar_report(stru ++ return; ++ ++ /* report event to DFS pattern detector */ ++- tsf32l = __le32_to_cpu(event->hdr.tsf_timestamp); +++ tsf32l = __le32_to_cpu(phyerr->tsf_timestamp); ++ tsf64 = tsf & (~0xFFFFFFFFULL); ++ tsf64 |= tsf32l; ++ ++ width = MS(reg1, RADAR_REPORT_REG1_PULSE_DUR); ++- rssi = event->hdr.rssi_combined; +++ rssi = phyerr->rssi_combined; ++ ++ /* hardware store this as 8 bit signed value, ++ * set to zero if negative number ++@@ -1513,25 +2602,25 @@ static void ath10k_dfs_radar_report(stru ++ pe.width = width; ++ pe.rssi = rssi; ++ ++- ath10k_dbg(ATH10K_DBG_REGULATORY, +++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY, ++ "dfs add pulse freq: %d, width: %d, rssi %d, tsf: %llX\n", ++ pe.freq, pe.width, pe.rssi, pe.ts); ++ ++ ATH10K_DFS_STAT_INC(ar, pulses_detected); ++ ++ if (!ar->dfs_detector->add_pulse(ar->dfs_detector, &pe)) { ++- ath10k_dbg(ATH10K_DBG_REGULATORY, +++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY, ++ "dfs no pulse pattern detected, yet\n"); ++ return; ++ } ++ ++- ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs radar detected\n"); +++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs radar detected\n"); ++ ATH10K_DFS_STAT_INC(ar, radar_detected); ++ ++ /* Control radar events reporting in debugfs file ++ dfs_block_radar_events */ ++ if (ar->dfs_block_radar_events) { ++- ath10k_info("DFS Radar detected, but ignored as requested\n"); +++ ath10k_info(ar, "DFS Radar detected, but ignored as requested\n"); ++ return; ++ } ++ ++@@ -1539,8 +2628,8 @@ static void ath10k_dfs_radar_report(stru ++ } ++ ++ static int ath10k_dfs_fft_report(struct ath10k *ar, ++- struct wmi_single_phyerr_rx_event *event, ++- struct phyerr_fft_report *fftr, +++ const struct wmi_phyerr *phyerr, +++ const struct phyerr_fft_report *fftr, ++ u64 tsf) ++ { ++ u32 reg0, reg1; ++@@ -1548,15 +2637,15 @@ static int ath10k_dfs_fft_report(struct ++ ++ reg0 = __le32_to_cpu(fftr->reg0); ++ reg1 = __le32_to_cpu(fftr->reg1); ++- rssi = event->hdr.rssi_combined; +++ rssi = phyerr->rssi_combined; ++ ++- ath10k_dbg(ATH10K_DBG_REGULATORY, +++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY, ++ "wmi phyerr fft report total_gain_db %d base_pwr_db %d fft_chn_idx %d peak_sidx %d\n", ++ MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB), ++ MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB), ++ MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX), ++ MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX)); ++- ath10k_dbg(ATH10K_DBG_REGULATORY, +++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY, ++ "wmi phyerr fft report rel_pwr_db %d avgpwr_db %d peak_mag %d num_store_bin %d\n", ++ MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB), ++ MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB), ++@@ -1568,7 +2657,7 @@ static int ath10k_dfs_fft_report(struct ++ /* false event detection */ ++ if (rssi == DFS_RSSI_POSSIBLY_FALSE && ++ peak_mag < 2 * DFS_PEAK_MAG_THOLD_POSSIBLY_FALSE) { ++- ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs false pulse detected\n"); +++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs false pulse detected\n"); ++ ATH10K_DFS_STAT_INC(ar, pulses_discarded); ++ return -EINVAL; ++ } ++@@ -1576,21 +2665,21 @@ static int ath10k_dfs_fft_report(struct ++ return 0; ++ } ++ ++-static void ath10k_wmi_event_dfs(struct ath10k *ar, ++- struct wmi_single_phyerr_rx_event *event, ++- u64 tsf) +++void ath10k_wmi_event_dfs(struct ath10k *ar, +++ const struct wmi_phyerr *phyerr, +++ u64 tsf) ++ { ++ int buf_len, tlv_len, res, i = 0; ++- struct phyerr_tlv *tlv; ++- struct phyerr_radar_report *rr; ++- struct phyerr_fft_report *fftr; ++- u8 *tlv_buf; +++ const struct phyerr_tlv *tlv; +++ const struct phyerr_radar_report *rr; +++ const struct phyerr_fft_report *fftr; +++ const u8 *tlv_buf; ++ ++- buf_len = __le32_to_cpu(event->hdr.buf_len); ++- ath10k_dbg(ATH10K_DBG_REGULATORY, +++ buf_len = __le32_to_cpu(phyerr->buf_len); +++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY, ++ "wmi event dfs err_code %d rssi %d tsfl 0x%X tsf64 0x%llX len %d\n", ++- event->hdr.phy_err_code, event->hdr.rssi_combined, ++- __le32_to_cpu(event->hdr.tsf_timestamp), tsf, buf_len); +++ phyerr->phy_err_code, phyerr->rssi_combined, +++ __le32_to_cpu(phyerr->tsf_timestamp), tsf, buf_len); ++ ++ /* Skip event if DFS disabled */ ++ if (!config_enabled(CPTCFG_ATH10K_DFS_CERTIFIED)) ++@@ -1600,36 +2689,38 @@ static void ath10k_wmi_event_dfs(struct ++ ++ while (i < buf_len) { ++ if (i + sizeof(*tlv) > buf_len) { ++- ath10k_warn("too short buf for tlv header (%d)\n", i); +++ ath10k_warn(ar, "too short buf for tlv header (%d)\n", +++ i); ++ return; ++ } ++ ++- tlv = (struct phyerr_tlv *)&event->bufp[i]; +++ tlv = (struct phyerr_tlv *)&phyerr->buf[i]; ++ tlv_len = __le16_to_cpu(tlv->len); ++- tlv_buf = &event->bufp[i + sizeof(*tlv)]; ++- ath10k_dbg(ATH10K_DBG_REGULATORY, +++ tlv_buf = &phyerr->buf[i + sizeof(*tlv)]; +++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY, ++ "wmi event dfs tlv_len %d tlv_tag 0x%02X tlv_sig 0x%02X\n", ++ tlv_len, tlv->tag, tlv->sig); ++ ++ switch (tlv->tag) { ++ case PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY: ++ if (i + sizeof(*tlv) + sizeof(*rr) > buf_len) { ++- ath10k_warn("too short radar pulse summary (%d)\n", +++ ath10k_warn(ar, "too short radar pulse summary (%d)\n", ++ i); ++ return; ++ } ++ ++ rr = (struct phyerr_radar_report *)tlv_buf; ++- ath10k_dfs_radar_report(ar, event, rr, tsf); +++ ath10k_dfs_radar_report(ar, phyerr, rr, tsf); ++ break; ++ case PHYERR_TLV_TAG_SEARCH_FFT_REPORT: ++ if (i + sizeof(*tlv) + sizeof(*fftr) > buf_len) { ++- ath10k_warn("too short fft report (%d)\n", i); +++ ath10k_warn(ar, "too short fft report (%d)\n", +++ i); ++ return; ++ } ++ ++ fftr = (struct phyerr_fft_report *)tlv_buf; ++- res = ath10k_dfs_fft_report(ar, event, fftr, tsf); +++ res = ath10k_dfs_fft_report(ar, phyerr, fftr, tsf); ++ if (res) ++ return; ++ break; ++@@ -1639,58 +2730,122 @@ static void ath10k_wmi_event_dfs(struct ++ } ++ } ++ ++-static void ath10k_wmi_event_spectral_scan(struct ath10k *ar, ++- struct wmi_single_phyerr_rx_event *event, ++- u64 tsf) ++-{ ++- ath10k_dbg(ATH10K_DBG_WMI, "wmi event spectral scan\n"); ++-} ++- ++-static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) +++void ath10k_wmi_event_spectral_scan(struct ath10k *ar, +++ const struct wmi_phyerr *phyerr, +++ u64 tsf) ++ { ++- struct wmi_comb_phyerr_rx_event *comb_event; ++- struct wmi_single_phyerr_rx_event *event; ++- u32 count, i, buf_len, phy_err_code; ++- u64 tsf; ++- int left_len = skb->len; ++- ++- ATH10K_DFS_STAT_INC(ar, phy_errors); ++- ++- /* Check if combined event available */ ++- if (left_len < sizeof(*comb_event)) { ++- ath10k_warn("wmi phyerr combined event wrong len\n"); ++- return; ++- } ++- ++- left_len -= sizeof(*comb_event); +++ int buf_len, tlv_len, res, i = 0; +++ struct phyerr_tlv *tlv; +++ const void *tlv_buf; +++ const struct phyerr_fft_report *fftr; +++ size_t fftr_len; ++ ++- /* Check number of included events */ ++- comb_event = (struct wmi_comb_phyerr_rx_event *)skb->data; ++- count = __le32_to_cpu(comb_event->hdr.num_phyerr_events); +++ buf_len = __le32_to_cpu(phyerr->buf_len); ++ ++- tsf = __le32_to_cpu(comb_event->hdr.tsf_u32); ++- tsf <<= 32; ++- tsf |= __le32_to_cpu(comb_event->hdr.tsf_l32); +++ while (i < buf_len) { +++ if (i + sizeof(*tlv) > buf_len) { +++ ath10k_warn(ar, "failed to parse phyerr tlv header at byte %d\n", +++ i); +++ return; +++ } ++ ++- ath10k_dbg(ATH10K_DBG_WMI, ++- "wmi event phyerr count %d tsf64 0x%llX\n", ++- count, tsf); +++ tlv = (struct phyerr_tlv *)&phyerr->buf[i]; +++ tlv_len = __le16_to_cpu(tlv->len); +++ tlv_buf = &phyerr->buf[i + sizeof(*tlv)]; ++ ++- event = (struct wmi_single_phyerr_rx_event *)comb_event->bufp; ++- for (i = 0; i < count; i++) { ++- /* Check if we can read event header */ ++- if (left_len < sizeof(*event)) { ++- ath10k_warn("single event (%d) wrong head len\n", i); +++ if (i + sizeof(*tlv) + tlv_len > buf_len) { +++ ath10k_warn(ar, "failed to parse phyerr tlv payload at byte %d\n", +++ i); ++ return; ++ } ++ ++- left_len -= sizeof(*event); ++- ++- buf_len = __le32_to_cpu(event->hdr.buf_len); ++- phy_err_code = event->hdr.phy_err_code; +++ switch (tlv->tag) { +++ case PHYERR_TLV_TAG_SEARCH_FFT_REPORT: +++ if (sizeof(*fftr) > tlv_len) { +++ ath10k_warn(ar, "failed to parse fft report at byte %d\n", +++ i); +++ return; +++ } +++ +++ fftr_len = tlv_len - sizeof(*fftr); +++ fftr = tlv_buf; +++ res = ath10k_spectral_process_fft(ar, phyerr, +++ fftr, fftr_len, +++ tsf); +++ if (res < 0) { +++ ath10k_warn(ar, "failed to process fft report: %d\n", +++ res); +++ return; +++ } +++ break; +++ } +++ +++ i += sizeof(*tlv) + tlv_len; +++ } +++} +++ +++static int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_phyerr_ev_arg *arg) +++{ +++ struct wmi_phyerr_event *ev = (void *)skb->data; +++ +++ if (skb->len < sizeof(*ev)) +++ return -EPROTO; +++ +++ arg->num_phyerrs = ev->num_phyerrs; +++ arg->tsf_l32 = ev->tsf_l32; +++ arg->tsf_u32 = ev->tsf_u32; +++ arg->buf_len = __cpu_to_le32(skb->len - sizeof(*ev)); +++ arg->phyerrs = ev->phyerrs; +++ +++ return 0; +++} +++ +++void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) +++{ +++ struct wmi_phyerr_ev_arg arg = {}; +++ const struct wmi_phyerr *phyerr; +++ u32 count, i, buf_len, phy_err_code; +++ u64 tsf; +++ int left_len, ret; +++ +++ ATH10K_DFS_STAT_INC(ar, phy_errors); +++ +++ ret = ath10k_wmi_pull_phyerr(ar, skb, &arg); +++ if (ret) { +++ ath10k_warn(ar, "failed to parse phyerr event: %d\n", ret); +++ return; +++ } +++ +++ left_len = __le32_to_cpu(arg.buf_len); +++ +++ /* Check number of included events */ +++ count = __le32_to_cpu(arg.num_phyerrs); +++ +++ tsf = __le32_to_cpu(arg.tsf_u32); +++ tsf <<= 32; +++ tsf |= __le32_to_cpu(arg.tsf_l32); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, +++ "wmi event phyerr count %d tsf64 0x%llX\n", +++ count, tsf); +++ +++ phyerr = arg.phyerrs; +++ for (i = 0; i < count; i++) { +++ /* Check if we can read event header */ +++ if (left_len < sizeof(*phyerr)) { +++ ath10k_warn(ar, "single event (%d) wrong head len\n", +++ i); +++ return; +++ } +++ +++ left_len -= sizeof(*phyerr); +++ +++ buf_len = __le32_to_cpu(phyerr->buf_len); +++ phy_err_code = phyerr->phy_err_code; ++ ++ if (left_len < buf_len) { ++- ath10k_warn("single event (%d) wrong buf len\n", i); +++ ath10k_warn(ar, "single event (%d) wrong buf len\n", i); ++ return; ++ } ++ ++@@ -1698,36 +2853,34 @@ static void ath10k_wmi_event_phyerr(stru ++ ++ switch (phy_err_code) { ++ case PHY_ERROR_RADAR: ++- ath10k_wmi_event_dfs(ar, event, tsf); +++ ath10k_wmi_event_dfs(ar, phyerr, tsf); ++ break; ++ case PHY_ERROR_SPECTRAL_SCAN: ++- ath10k_wmi_event_spectral_scan(ar, event, tsf); +++ ath10k_wmi_event_spectral_scan(ar, phyerr, tsf); ++ break; ++ case PHY_ERROR_FALSE_RADAR_EXT: ++- ath10k_wmi_event_dfs(ar, event, tsf); ++- ath10k_wmi_event_spectral_scan(ar, event, tsf); +++ ath10k_wmi_event_dfs(ar, phyerr, tsf); +++ ath10k_wmi_event_spectral_scan(ar, phyerr, tsf); ++ break; ++ default: ++ break; ++ } ++ ++- event += sizeof(*event) + buf_len; +++ phyerr = (void *)phyerr + sizeof(*phyerr) + buf_len; ++ } ++ } ++ ++-static void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb) +++void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_ROAM_EVENTID\n"); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ROAM_EVENTID\n"); ++ } ++ ++-static void ath10k_wmi_event_profile_match(struct ath10k *ar, ++- struct sk_buff *skb) +++void ath10k_wmi_event_profile_match(struct ath10k *ar, struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_PROFILE_MATCH\n"); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PROFILE_MATCH\n"); ++ } ++ ++-static void ath10k_wmi_event_debug_print(struct ath10k *ar, ++- struct sk_buff *skb) +++void ath10k_wmi_event_debug_print(struct ath10k *ar, struct sk_buff *skb) ++ { ++ char buf[101], c; ++ int i; ++@@ -1748,7 +2901,7 @@ static void ath10k_wmi_event_debug_print ++ } ++ ++ if (i == sizeof(buf) - 1) ++- ath10k_warn("wmi debug print truncated: %d\n", skb->len); +++ ath10k_warn(ar, "wmi debug print truncated: %d\n", skb->len); ++ ++ /* for some reason the debug prints end with \n, remove that */ ++ if (skb->data[i - 1] == '\n') ++@@ -1757,112 +2910,99 @@ static void ath10k_wmi_event_debug_print ++ /* the last byte is always reserved for the null character */ ++ buf[i] = '\0'; ++ ++- ath10k_dbg(ATH10K_DBG_WMI, "wmi event debug print '%s'\n", buf); +++ ath10k_dbg(ar, ATH10K_DBG_WMI_PRINT, "wmi print '%s'\n", buf); ++ } ++ ++-static void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb) +++void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_QVIT_EVENTID\n"); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_QVIT_EVENTID\n"); ++ } ++ ++-static void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar, ++- struct sk_buff *skb) +++void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar, struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_WLAN_PROFILE_DATA_EVENTID\n"); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WLAN_PROFILE_DATA_EVENTID\n"); ++ } ++ ++-static void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar, +++void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar, ++ struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_RTT_MEASUREMENT_REPORT_EVENTID\n"); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_RTT_MEASUREMENT_REPORT_EVENTID\n"); ++ } ++ ++-static void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar, +++void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar, ++ struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_TSF_MEASUREMENT_REPORT_EVENTID\n"); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TSF_MEASUREMENT_REPORT_EVENTID\n"); ++ } ++ ++-static void ath10k_wmi_event_rtt_error_report(struct ath10k *ar, ++- struct sk_buff *skb) +++void ath10k_wmi_event_rtt_error_report(struct ath10k *ar, struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_RTT_ERROR_REPORT_EVENTID\n"); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_RTT_ERROR_REPORT_EVENTID\n"); ++ } ++ ++-static void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar, ++- struct sk_buff *skb) +++void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar, struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_WOW_WAKEUP_HOST_EVENTID\n"); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WOW_WAKEUP_HOST_EVENTID\n"); ++ } ++ ++-static void ath10k_wmi_event_dcs_interference(struct ath10k *ar, ++- struct sk_buff *skb) +++void ath10k_wmi_event_dcs_interference(struct ath10k *ar, struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_DCS_INTERFERENCE_EVENTID\n"); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_DCS_INTERFERENCE_EVENTID\n"); ++ } ++ ++-static void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, ++- struct sk_buff *skb) +++void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_TPC_CONFIG_EVENTID\n"); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_TPC_CONFIG_EVENTID\n"); ++ } ++ ++-static void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, ++- struct sk_buff *skb) +++void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n"); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n"); ++ } ++ ++-static void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar, ++- struct sk_buff *skb) +++void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar, struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_GTK_OFFLOAD_STATUS_EVENTID\n"); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_GTK_OFFLOAD_STATUS_EVENTID\n"); ++ } ++ ++-static void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar, ++- struct sk_buff *skb) +++void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar, struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_GTK_REKEY_FAIL_EVENTID\n"); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_GTK_REKEY_FAIL_EVENTID\n"); ++ } ++ ++-static void ath10k_wmi_event_delba_complete(struct ath10k *ar, ++- struct sk_buff *skb) +++void ath10k_wmi_event_delba_complete(struct ath10k *ar, struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_TX_DELBA_COMPLETE_EVENTID\n"); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TX_DELBA_COMPLETE_EVENTID\n"); ++ } ++ ++-static void ath10k_wmi_event_addba_complete(struct ath10k *ar, ++- struct sk_buff *skb) +++void ath10k_wmi_event_addba_complete(struct ath10k *ar, struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_TX_ADDBA_COMPLETE_EVENTID\n"); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TX_ADDBA_COMPLETE_EVENTID\n"); ++ } ++ ++-static void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar, +++void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar, ++ struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID\n"); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID\n"); ++ } ++ ++-static void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar, ++- struct sk_buff *skb) +++void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar, struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_INST_RSSI_STATS_EVENTID\n"); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_INST_RSSI_STATS_EVENTID\n"); ++ } ++ ++-static void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar, ++- struct sk_buff *skb) +++void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar, struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_STANDBY_REQ_EVENTID\n"); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_STANDBY_REQ_EVENTID\n"); ++ } ++ ++-static void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, ++- struct sk_buff *skb) +++void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb) ++ { ++- ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n"); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n"); ++ } ++ ++ static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id, ++- u32 num_units, u32 unit_len) +++ u32 num_units, u32 unit_len) ++ { ++ dma_addr_t paddr; ++ u32 pool_size; ++@@ -1878,7 +3018,7 @@ static int ath10k_wmi_alloc_host_mem(str ++ &paddr, ++ GFP_ATOMIC); ++ if (!ar->wmi.mem_chunks[idx].vaddr) { ++- ath10k_warn("failed to allocate memory chunk\n"); +++ ath10k_warn(ar, "failed to allocate memory chunk\n"); ++ return -ENOMEM; ++ } ++ ++@@ -1892,45 +3032,124 @@ static int ath10k_wmi_alloc_host_mem(str ++ return 0; ++ } ++ ++-static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar, ++- struct sk_buff *skb) +++static int +++ath10k_wmi_main_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_svc_rdy_ev_arg *arg) +++{ +++ struct wmi_service_ready_event *ev; +++ size_t i, n; +++ +++ if (skb->len < sizeof(*ev)) +++ return -EPROTO; +++ +++ ev = (void *)skb->data; +++ skb_pull(skb, sizeof(*ev)); +++ arg->min_tx_power = ev->hw_min_tx_power; +++ arg->max_tx_power = ev->hw_max_tx_power; +++ arg->ht_cap = ev->ht_cap_info; +++ arg->vht_cap = ev->vht_cap_info; +++ arg->sw_ver0 = ev->sw_version; +++ arg->sw_ver1 = ev->sw_version_1; +++ arg->phy_capab = ev->phy_capability; +++ arg->num_rf_chains = ev->num_rf_chains; +++ arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd; +++ arg->num_mem_reqs = ev->num_mem_reqs; +++ arg->service_map = ev->wmi_service_bitmap; +++ arg->service_map_len = sizeof(ev->wmi_service_bitmap); +++ +++ n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs), +++ ARRAY_SIZE(arg->mem_reqs)); +++ for (i = 0; i < n; i++) +++ arg->mem_reqs[i] = &ev->mem_reqs[i]; +++ +++ if (skb->len < +++ __le32_to_cpu(arg->num_mem_reqs) * sizeof(arg->mem_reqs[0])) +++ return -EPROTO; +++ +++ return 0; +++} +++ +++static int +++ath10k_wmi_10x_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_svc_rdy_ev_arg *arg) +++{ +++ struct wmi_10x_service_ready_event *ev; +++ int i, n; +++ +++ if (skb->len < sizeof(*ev)) +++ return -EPROTO; +++ +++ ev = (void *)skb->data; +++ skb_pull(skb, sizeof(*ev)); +++ arg->min_tx_power = ev->hw_min_tx_power; +++ arg->max_tx_power = ev->hw_max_tx_power; +++ arg->ht_cap = ev->ht_cap_info; +++ arg->vht_cap = ev->vht_cap_info; +++ arg->sw_ver0 = ev->sw_version; +++ arg->phy_capab = ev->phy_capability; +++ arg->num_rf_chains = ev->num_rf_chains; +++ arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd; +++ arg->num_mem_reqs = ev->num_mem_reqs; +++ arg->service_map = ev->wmi_service_bitmap; +++ arg->service_map_len = sizeof(ev->wmi_service_bitmap); +++ +++ n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs), +++ ARRAY_SIZE(arg->mem_reqs)); +++ for (i = 0; i < n; i++) +++ arg->mem_reqs[i] = &ev->mem_reqs[i]; +++ +++ if (skb->len < +++ __le32_to_cpu(arg->num_mem_reqs) * sizeof(arg->mem_reqs[0])) +++ return -EPROTO; +++ +++ return 0; +++} +++ +++void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb) ++ { ++- struct wmi_service_ready_event *ev = (void *)skb->data; +++ struct wmi_svc_rdy_ev_arg arg = {}; +++ u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i; +++ int ret; ++ ++- if (skb->len < sizeof(*ev)) { ++- ath10k_warn("Service ready event was %d B but expected %zu B. Wrong firmware version?\n", ++- skb->len, sizeof(*ev)); +++ ret = ath10k_wmi_pull_svc_rdy(ar, skb, &arg); +++ if (ret) { +++ ath10k_warn(ar, "failed to parse service ready: %d\n", ret); ++ return; ++ } ++ ++- ar->hw_min_tx_power = __le32_to_cpu(ev->hw_min_tx_power); ++- ar->hw_max_tx_power = __le32_to_cpu(ev->hw_max_tx_power); ++- ar->ht_cap_info = __le32_to_cpu(ev->ht_cap_info); ++- ar->vht_cap_info = __le32_to_cpu(ev->vht_cap_info); +++ memset(&ar->wmi.svc_map, 0, sizeof(ar->wmi.svc_map)); +++ ath10k_wmi_map_svc(ar, arg.service_map, ar->wmi.svc_map, +++ arg.service_map_len); +++ +++ ar->hw_min_tx_power = __le32_to_cpu(arg.min_tx_power); +++ ar->hw_max_tx_power = __le32_to_cpu(arg.max_tx_power); +++ ar->ht_cap_info = __le32_to_cpu(arg.ht_cap); +++ ar->vht_cap_info = __le32_to_cpu(arg.vht_cap); ++ ar->fw_version_major = ++- (__le32_to_cpu(ev->sw_version) & 0xff000000) >> 24; ++- ar->fw_version_minor = (__le32_to_cpu(ev->sw_version) & 0x00ffffff); +++ (__le32_to_cpu(arg.sw_ver0) & 0xff000000) >> 24; +++ ar->fw_version_minor = (__le32_to_cpu(arg.sw_ver0) & 0x00ffffff); ++ ar->fw_version_release = ++- (__le32_to_cpu(ev->sw_version_1) & 0xffff0000) >> 16; ++- ar->fw_version_build = (__le32_to_cpu(ev->sw_version_1) & 0x0000ffff); ++- ar->phy_capability = __le32_to_cpu(ev->phy_capability); ++- ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains); +++ (__le32_to_cpu(arg.sw_ver1) & 0xffff0000) >> 16; +++ ar->fw_version_build = (__le32_to_cpu(arg.sw_ver1) & 0x0000ffff); +++ ar->phy_capability = __le32_to_cpu(arg.phy_capab); +++ ar->num_rf_chains = __le32_to_cpu(arg.num_rf_chains); +++ ar->ath_common.regulatory.current_rd = __le32_to_cpu(arg.eeprom_rd); +++ +++ ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ", +++ arg.service_map, arg.service_map_len); ++ ++ /* only manually set fw features when not using FW IE format */ ++ if (ar->fw_api == 1 && ar->fw_version_build > 636) ++ set_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features); ++ ++ if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) { ++- ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n", +++ ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n", ++ ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM); ++ ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM; ++ } ++ ++- ar->ath_common.regulatory.current_rd = ++- __le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd); ++- ++- ath10k_debug_read_service_map(ar, ev->wmi_service_bitmap, ++- sizeof(ev->wmi_service_bitmap)); +++ ar->supp_tx_chainmask = (1 << ar->num_rf_chains) - 1; +++ ar->supp_rx_chainmask = (1 << ar->num_rf_chains) - 1; ++ ++ if (strlen(ar->hw->wiphy->fw_version) == 0) { ++ snprintf(ar->hw->wiphy->fw_version, ++@@ -1942,90 +3161,18 @@ static void ath10k_wmi_service_ready_eve ++ ar->fw_version_build); ++ } ++ ++- /* FIXME: it probably should be better to support this */ ++- if (__le32_to_cpu(ev->num_mem_reqs) > 0) { ++- ath10k_warn("target requested %d memory chunks; ignoring\n", ++- __le32_to_cpu(ev->num_mem_reqs)); ++- } ++- ++- ath10k_dbg(ATH10K_DBG_WMI, ++- "wmi event service ready sw_ver 0x%08x sw_ver1 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n", ++- __le32_to_cpu(ev->sw_version), ++- __le32_to_cpu(ev->sw_version_1), ++- __le32_to_cpu(ev->abi_version), ++- __le32_to_cpu(ev->phy_capability), ++- __le32_to_cpu(ev->ht_cap_info), ++- __le32_to_cpu(ev->vht_cap_info), ++- __le32_to_cpu(ev->vht_supp_mcs), ++- __le32_to_cpu(ev->sys_cap_info), ++- __le32_to_cpu(ev->num_mem_reqs), ++- __le32_to_cpu(ev->num_rf_chains)); ++- ++- complete(&ar->wmi.service_ready); ++-} ++- ++-static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar, ++- struct sk_buff *skb) ++-{ ++- u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i; ++- int ret; ++- struct wmi_service_ready_event_10x *ev = (void *)skb->data; ++- ++- if (skb->len < sizeof(*ev)) { ++- ath10k_warn("Service ready event was %d B but expected %zu B. Wrong firmware version?\n", ++- skb->len, sizeof(*ev)); ++- return; ++- } ++- ++- ar->hw_min_tx_power = __le32_to_cpu(ev->hw_min_tx_power); ++- ar->hw_max_tx_power = __le32_to_cpu(ev->hw_max_tx_power); ++- ar->ht_cap_info = __le32_to_cpu(ev->ht_cap_info); ++- ar->vht_cap_info = __le32_to_cpu(ev->vht_cap_info); ++- ar->fw_version_major = ++- (__le32_to_cpu(ev->sw_version) & 0xff000000) >> 24; ++- ar->fw_version_minor = (__le32_to_cpu(ev->sw_version) & 0x00ffffff); ++- ar->phy_capability = __le32_to_cpu(ev->phy_capability); ++- ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains); ++- ++- if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) { ++- ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n", ++- ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM); ++- ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM; ++- } ++- ++- ar->ath_common.regulatory.current_rd = ++- __le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd); ++- ++- ath10k_debug_read_service_map(ar, ev->wmi_service_bitmap, ++- sizeof(ev->wmi_service_bitmap)); ++- ++- if (strlen(ar->hw->wiphy->fw_version) == 0) { ++- snprintf(ar->hw->wiphy->fw_version, ++- sizeof(ar->hw->wiphy->fw_version), ++- "%u.%u", ++- ar->fw_version_major, ++- ar->fw_version_minor); ++- } ++- ++- num_mem_reqs = __le32_to_cpu(ev->num_mem_reqs); ++- ++- if (num_mem_reqs > ATH10K_MAX_MEM_REQS) { ++- ath10k_warn("requested memory chunks number (%d) exceeds the limit\n", +++ num_mem_reqs = __le32_to_cpu(arg.num_mem_reqs); +++ if (num_mem_reqs > WMI_MAX_MEM_REQS) { +++ ath10k_warn(ar, "requested memory chunks number (%d) exceeds the limit\n", ++ num_mem_reqs); ++ return; ++ } ++ ++- if (!num_mem_reqs) ++- goto exit; ++- ++- ath10k_dbg(ATH10K_DBG_WMI, "firmware has requested %d memory chunks\n", ++- num_mem_reqs); ++- ++ for (i = 0; i < num_mem_reqs; ++i) { ++- req_id = __le32_to_cpu(ev->mem_reqs[i].req_id); ++- num_units = __le32_to_cpu(ev->mem_reqs[i].num_units); ++- unit_size = __le32_to_cpu(ev->mem_reqs[i].unit_size); ++- num_unit_info = __le32_to_cpu(ev->mem_reqs[i].num_unit_info); +++ req_id = __le32_to_cpu(arg.mem_reqs[i]->req_id); +++ num_units = __le32_to_cpu(arg.mem_reqs[i]->num_units); +++ unit_size = __le32_to_cpu(arg.mem_reqs[i]->unit_size); +++ num_unit_info = __le32_to_cpu(arg.mem_reqs[i]->num_unit_info); ++ ++ if (num_unit_info & NUM_UNITS_IS_NUM_PEERS) ++ /* number of units to allocate is number of ++@@ -2036,10 +3183,10 @@ static void ath10k_wmi_10x_service_ready ++ else if (num_unit_info & NUM_UNITS_IS_NUM_VDEVS) ++ num_units = TARGET_10X_NUM_VDEVS + 1; ++ ++- ath10k_dbg(ATH10K_DBG_WMI, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "wmi mem_req_id %d num_units %d num_unit_info %d unit size %d actual units %d\n", ++ req_id, ++- __le32_to_cpu(ev->mem_reqs[i].num_units), +++ __le32_to_cpu(arg.mem_reqs[i]->num_units), ++ num_unit_info, ++ unit_size, ++ num_units); ++@@ -2050,47 +3197,79 @@ static void ath10k_wmi_10x_service_ready ++ return; ++ } ++ ++-exit: ++- ath10k_dbg(ATH10K_DBG_WMI, ++- "wmi event service ready sw_ver 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n", ++- __le32_to_cpu(ev->sw_version), ++- __le32_to_cpu(ev->abi_version), ++- __le32_to_cpu(ev->phy_capability), ++- __le32_to_cpu(ev->ht_cap_info), ++- __le32_to_cpu(ev->vht_cap_info), ++- __le32_to_cpu(ev->vht_supp_mcs), ++- __le32_to_cpu(ev->sys_cap_info), ++- __le32_to_cpu(ev->num_mem_reqs), ++- __le32_to_cpu(ev->num_rf_chains)); +++ 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), +++ __le32_to_cpu(arg.max_tx_power), +++ __le32_to_cpu(arg.ht_cap), +++ __le32_to_cpu(arg.vht_cap), +++ __le32_to_cpu(arg.sw_ver0), +++ __le32_to_cpu(arg.sw_ver1), +++ __le32_to_cpu(arg.fw_build), +++ __le32_to_cpu(arg.phy_capab), +++ __le32_to_cpu(arg.num_rf_chains), +++ __le32_to_cpu(arg.eeprom_rd), +++ __le32_to_cpu(arg.num_mem_reqs)); ++ ++ complete(&ar->wmi.service_ready); ++ } ++ ++-static int ath10k_wmi_ready_event_rx(struct ath10k *ar, struct sk_buff *skb) +++static int ath10k_wmi_op_pull_rdy_ev(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_rdy_ev_arg *arg) ++ { ++- struct wmi_ready_event *ev = (struct wmi_ready_event *)skb->data; +++ struct wmi_ready_event *ev = (void *)skb->data; ++ ++- if (WARN_ON(skb->len < sizeof(*ev))) ++- return -EINVAL; +++ if (skb->len < sizeof(*ev)) +++ return -EPROTO; +++ +++ skb_pull(skb, sizeof(*ev)); +++ arg->sw_version = ev->sw_version; +++ arg->abi_version = ev->abi_version; +++ arg->status = ev->status; +++ arg->mac_addr = ev->mac_addr.addr; +++ +++ return 0; +++} +++ +++int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb) +++{ +++ struct wmi_rdy_ev_arg arg = {}; +++ int ret; ++ ++- memcpy(ar->mac_addr, ev->mac_addr.addr, ETH_ALEN); +++ ret = ath10k_wmi_pull_rdy(ar, skb, &arg); +++ if (ret) { +++ ath10k_warn(ar, "failed to parse ready event: %d\n", ret); +++ return ret; +++ } ++ ++- ath10k_dbg(ATH10K_DBG_WMI, ++- "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d skb->len %i ev-sz %zu\n", ++- __le32_to_cpu(ev->sw_version), ++- __le32_to_cpu(ev->abi_version), ++- ev->mac_addr.addr, ++- __le32_to_cpu(ev->status), skb->len, sizeof(*ev)); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, +++ "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d\n", +++ __le32_to_cpu(arg.sw_version), +++ __le32_to_cpu(arg.abi_version), +++ arg.mac_addr, +++ __le32_to_cpu(arg.status)); ++ +++ ether_addr_copy(ar->mac_addr, arg.mac_addr); ++ complete(&ar->wmi.unified_ready); ++ return 0; ++ } ++ ++-static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb) +++static int ath10k_wmi_event_temperature(struct ath10k *ar, struct sk_buff *skb) +++{ +++ const struct wmi_pdev_temperature_event *ev; +++ +++ ev = (struct wmi_pdev_temperature_event *)skb->data; +++ if (WARN_ON(skb->len < sizeof(*ev))) +++ return -EPROTO; +++ +++ ath10k_thermal_event_temperature(ar, __le32_to_cpu(ev->temperature)); +++ return 0; +++} +++ +++static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb) ++ { ++ struct wmi_cmd_hdr *cmd_hdr; ++ enum wmi_event_id id; ++- u16 len; ++ ++ cmd_hdr = (struct wmi_cmd_hdr *)skb->data; ++ id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); ++@@ -2098,9 +3277,7 @@ static void ath10k_wmi_main_process_rx(s ++ if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) ++ return; ++ ++- len = skb->len; ++- ++- trace_ath10k_wmi_event(id, skb->data, skb->len); +++ trace_ath10k_wmi_event(ar, id, skb->data, skb->len); ++ ++ switch (id) { ++ case WMI_MGMT_RX_EVENTID: ++@@ -2192,24 +3369,24 @@ static void ath10k_wmi_main_process_rx(s ++ ath10k_wmi_event_vdev_install_key_complete(ar, skb); ++ break; ++ case WMI_SERVICE_READY_EVENTID: ++- ath10k_wmi_service_ready_event_rx(ar, skb); +++ ath10k_wmi_event_service_ready(ar, skb); ++ break; ++ case WMI_READY_EVENTID: ++- ath10k_wmi_ready_event_rx(ar, skb); +++ ath10k_wmi_event_ready(ar, skb); ++ break; ++ default: ++- ath10k_warn("Unknown eventid: %d\n", id); +++ ath10k_warn(ar, "Unknown eventid: %d\n", id); ++ break; ++ } ++ ++ dev_kfree_skb(skb); ++ } ++ ++-static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb) +++static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, struct sk_buff *skb) ++ { ++ struct wmi_cmd_hdr *cmd_hdr; ++ enum wmi_10x_event_id id; ++- u16 len; +++ bool consumed; ++ ++ cmd_hdr = (struct wmi_cmd_hdr *)skb->data; ++ id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); ++@@ -2217,9 +3394,19 @@ static void ath10k_wmi_10x_process_rx(st ++ if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) ++ return; ++ ++- len = skb->len; +++ trace_ath10k_wmi_event(ar, id, skb->data, skb->len); +++ +++ consumed = ath10k_tm_event_wmi(ar, id, skb); ++ ++- trace_ath10k_wmi_event(id, skb->data, skb->len); +++ /* Ready event must be handled normally also in UTF mode so that we +++ * know the UTF firmware has booted, others we are just bypass WMI +++ * events to testmode. +++ */ +++ if (consumed && id != WMI_10X_READY_EVENTID) { +++ ath10k_dbg(ar, ATH10K_DBG_WMI, +++ "wmi testmode consumed 0x%x\n", id); +++ goto out; +++ } ++ ++ switch (id) { ++ case WMI_10X_MGMT_RX_EVENTID: ++@@ -2302,64 +3489,153 @@ static void ath10k_wmi_10x_process_rx(st ++ ath10k_wmi_event_vdev_resume_req(ar, skb); ++ break; ++ case WMI_10X_SERVICE_READY_EVENTID: ++- ath10k_wmi_10x_service_ready_event_rx(ar, skb); +++ ath10k_wmi_event_service_ready(ar, skb); ++ break; ++ case WMI_10X_READY_EVENTID: ++- ath10k_wmi_ready_event_rx(ar, skb); +++ ath10k_wmi_event_ready(ar, skb); +++ break; +++ case WMI_10X_PDEV_UTF_EVENTID: +++ /* ignore utf events */ ++ break; ++ default: ++- ath10k_warn("Unknown eventid: %d\n", id); +++ ath10k_warn(ar, "Unknown eventid: %d\n", id); ++ break; ++ } ++ +++out: ++ dev_kfree_skb(skb); ++ } ++ ++- ++-static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb) +++static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb) ++ { ++- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) ++- ath10k_wmi_10x_process_rx(ar, skb); ++- else ++- ath10k_wmi_main_process_rx(ar, skb); ++-} +++ struct wmi_cmd_hdr *cmd_hdr; +++ enum wmi_10_2_event_id id; ++ ++-/* WMI Initialization functions */ ++-int ath10k_wmi_attach(struct ath10k *ar) ++-{ ++- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { ++- ar->wmi.cmd = &wmi_10x_cmd_map; ++- ar->wmi.vdev_param = &wmi_10x_vdev_param_map; ++- ar->wmi.pdev_param = &wmi_10x_pdev_param_map; ++- } else { ++- ar->wmi.cmd = &wmi_cmd_map; ++- ar->wmi.vdev_param = &wmi_vdev_param_map; ++- ar->wmi.pdev_param = &wmi_pdev_param_map; ++- } +++ cmd_hdr = (struct wmi_cmd_hdr *)skb->data; +++ id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); ++ ++- init_completion(&ar->wmi.service_ready); ++- init_completion(&ar->wmi.unified_ready); ++- init_waitqueue_head(&ar->wmi.tx_credits_wq); +++ if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) +++ return; ++ ++- return 0; +++ trace_ath10k_wmi_event(ar, id, skb->data, skb->len); +++ +++ switch (id) { +++ case WMI_10_2_MGMT_RX_EVENTID: +++ ath10k_wmi_event_mgmt_rx(ar, skb); +++ /* mgmt_rx() owns the skb now! */ +++ return; +++ case WMI_10_2_SCAN_EVENTID: +++ ath10k_wmi_event_scan(ar, skb); +++ break; +++ case WMI_10_2_CHAN_INFO_EVENTID: +++ ath10k_wmi_event_chan_info(ar, skb); +++ break; +++ case WMI_10_2_ECHO_EVENTID: +++ ath10k_wmi_event_echo(ar, skb); +++ break; +++ case WMI_10_2_DEBUG_MESG_EVENTID: +++ ath10k_wmi_event_debug_mesg(ar, skb); +++ break; +++ case WMI_10_2_UPDATE_STATS_EVENTID: +++ ath10k_wmi_event_update_stats(ar, skb); +++ break; +++ case WMI_10_2_VDEV_START_RESP_EVENTID: +++ ath10k_wmi_event_vdev_start_resp(ar, skb); +++ break; +++ case WMI_10_2_VDEV_STOPPED_EVENTID: +++ ath10k_wmi_event_vdev_stopped(ar, skb); +++ break; +++ case WMI_10_2_PEER_STA_KICKOUT_EVENTID: +++ ath10k_wmi_event_peer_sta_kickout(ar, skb); +++ break; +++ case WMI_10_2_HOST_SWBA_EVENTID: +++ ath10k_wmi_event_host_swba(ar, skb); +++ break; +++ case WMI_10_2_TBTTOFFSET_UPDATE_EVENTID: +++ ath10k_wmi_event_tbttoffset_update(ar, skb); +++ break; +++ case WMI_10_2_PHYERR_EVENTID: +++ ath10k_wmi_event_phyerr(ar, skb); +++ break; +++ case WMI_10_2_ROAM_EVENTID: +++ ath10k_wmi_event_roam(ar, skb); +++ break; +++ case WMI_10_2_PROFILE_MATCH: +++ ath10k_wmi_event_profile_match(ar, skb); +++ break; +++ case WMI_10_2_DEBUG_PRINT_EVENTID: +++ ath10k_wmi_event_debug_print(ar, skb); +++ break; +++ case WMI_10_2_PDEV_QVIT_EVENTID: +++ ath10k_wmi_event_pdev_qvit(ar, skb); +++ break; +++ case WMI_10_2_WLAN_PROFILE_DATA_EVENTID: +++ ath10k_wmi_event_wlan_profile_data(ar, skb); +++ break; +++ case WMI_10_2_RTT_MEASUREMENT_REPORT_EVENTID: +++ ath10k_wmi_event_rtt_measurement_report(ar, skb); +++ break; +++ case WMI_10_2_TSF_MEASUREMENT_REPORT_EVENTID: +++ ath10k_wmi_event_tsf_measurement_report(ar, skb); +++ break; +++ case WMI_10_2_RTT_ERROR_REPORT_EVENTID: +++ ath10k_wmi_event_rtt_error_report(ar, skb); +++ break; +++ case WMI_10_2_WOW_WAKEUP_HOST_EVENTID: +++ ath10k_wmi_event_wow_wakeup_host(ar, skb); +++ break; +++ case WMI_10_2_DCS_INTERFERENCE_EVENTID: +++ ath10k_wmi_event_dcs_interference(ar, skb); +++ break; +++ case WMI_10_2_PDEV_TPC_CONFIG_EVENTID: +++ ath10k_wmi_event_pdev_tpc_config(ar, skb); +++ break; +++ case WMI_10_2_INST_RSSI_STATS_EVENTID: +++ ath10k_wmi_event_inst_rssi_stats(ar, skb); +++ break; +++ case WMI_10_2_VDEV_STANDBY_REQ_EVENTID: +++ ath10k_wmi_event_vdev_standby_req(ar, skb); +++ break; +++ case WMI_10_2_VDEV_RESUME_REQ_EVENTID: +++ ath10k_wmi_event_vdev_resume_req(ar, skb); +++ break; +++ case WMI_10_2_SERVICE_READY_EVENTID: +++ ath10k_wmi_event_service_ready(ar, skb); +++ break; +++ case WMI_10_2_READY_EVENTID: +++ ath10k_wmi_event_ready(ar, skb); +++ break; +++ case WMI_10_2_PDEV_TEMPERATURE_EVENTID: +++ ath10k_wmi_event_temperature(ar, skb); +++ break; +++ case WMI_10_2_RTT_KEEPALIVE_EVENTID: +++ case WMI_10_2_GPIO_INPUT_EVENTID: +++ case WMI_10_2_PEER_RATECODE_LIST_EVENTID: +++ case WMI_10_2_GENERIC_BUFFER_EVENTID: +++ case WMI_10_2_MCAST_BUF_RELEASE_EVENTID: +++ case WMI_10_2_MCAST_LIST_AGEOUT_EVENTID: +++ case WMI_10_2_WDS_PEER_EVENTID: +++ ath10k_dbg(ar, ATH10K_DBG_WMI, +++ "received event id %d not implemented\n", id); +++ break; +++ default: +++ ath10k_warn(ar, "Unknown eventid: %d\n", id); +++ break; +++ } +++ +++ dev_kfree_skb(skb); ++ } ++ ++-void ath10k_wmi_detach(struct ath10k *ar) +++static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb) ++ { ++- int i; ++- ++- /* free the host memory chunks requested by firmware */ ++- for (i = 0; i < ar->wmi.num_mem_chunks; i++) { ++- dma_free_coherent(ar->dev, ++- ar->wmi.mem_chunks[i].len, ++- ar->wmi.mem_chunks[i].vaddr, ++- ar->wmi.mem_chunks[i].paddr); ++- } +++ int ret; ++ ++- ar->wmi.num_mem_chunks = 0; +++ ret = ath10k_wmi_rx(ar, skb); +++ if (ret) +++ ath10k_warn(ar, "failed to process wmi rx: %d\n", ret); ++ } ++ ++-int ath10k_wmi_connect_htc_service(struct ath10k *ar) +++int ath10k_wmi_connect(struct ath10k *ar) ++ { ++ int status; ++ struct ath10k_htc_svc_conn_req conn_req; ++@@ -2378,7 +3654,7 @@ int ath10k_wmi_connect_htc_service(struc ++ ++ status = ath10k_htc_connect_service(&ar->htc, &conn_req, &conn_resp); ++ if (status) { ++- ath10k_warn("failed to connect to WMI CONTROL service status: %d\n", +++ ath10k_warn(ar, "failed to connect to WMI CONTROL service status: %d\n", ++ status); ++ return status; ++ } ++@@ -2387,16 +3663,17 @@ int ath10k_wmi_connect_htc_service(struc ++ return 0; ++ } ++ ++-static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd, ++- u16 rd2g, u16 rd5g, u16 ctl2g, ++- u16 ctl5g) +++static struct sk_buff * +++ath10k_wmi_op_gen_pdev_set_rd(struct ath10k *ar, u16 rd, u16 rd2g, u16 rd5g, +++ u16 ctl2g, u16 ctl5g, +++ enum wmi_dfs_region dfs_reg) ++ { ++ struct wmi_pdev_set_regdomain_cmd *cmd; ++ struct sk_buff *skb; ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_pdev_set_regdomain_cmd *)skb->data; ++ cmd->reg_domain = __cpu_to_le32(rd); ++@@ -2405,25 +3682,23 @@ static int ath10k_wmi_main_pdev_set_regd ++ cmd->conformance_test_limit_2G = __cpu_to_le32(ctl2g); ++ cmd->conformance_test_limit_5G = __cpu_to_le32(ctl5g); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x\n", ++ rd, rd2g, rd5g, ctl2g, ctl5g); ++- ++- return ath10k_wmi_cmd_send(ar, skb, ++- ar->wmi.cmd->pdev_set_regdomain_cmdid); +++ return skb; ++ } ++ ++-static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd, ++- u16 rd2g, u16 rd5g, ++- u16 ctl2g, u16 ctl5g, ++- enum wmi_dfs_region dfs_reg) +++static struct sk_buff * +++ath10k_wmi_10x_op_gen_pdev_set_rd(struct ath10k *ar, u16 rd, u16 rd2g, u16 +++ rd5g, u16 ctl2g, u16 ctl5g, +++ enum wmi_dfs_region dfs_reg) ++ { ++ struct wmi_pdev_set_regdomain_cmd_10x *cmd; ++ struct sk_buff *skb; ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_pdev_set_regdomain_cmd_10x *)skb->data; ++ cmd->reg_domain = __cpu_to_le32(rd); ++@@ -2433,121 +3708,96 @@ static int ath10k_wmi_10x_pdev_set_regdo ++ cmd->conformance_test_limit_5G = __cpu_to_le32(ctl5g); ++ cmd->dfs_domain = __cpu_to_le32(dfs_reg); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x dfs_region %x\n", ++ rd, rd2g, rd5g, ctl2g, ctl5g, dfs_reg); ++- ++- return ath10k_wmi_cmd_send(ar, skb, ++- ar->wmi.cmd->pdev_set_regdomain_cmdid); ++-} ++- ++-int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, ++- u16 rd5g, u16 ctl2g, u16 ctl5g, ++- enum wmi_dfs_region dfs_reg) ++-{ ++- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) ++- return ath10k_wmi_10x_pdev_set_regdomain(ar, rd, rd2g, rd5g, ++- ctl2g, ctl5g, dfs_reg); ++- else ++- return ath10k_wmi_main_pdev_set_regdomain(ar, rd, rd2g, rd5g, ++- ctl2g, ctl5g); ++-} ++- ++-int ath10k_wmi_pdev_set_channel(struct ath10k *ar, ++- const struct wmi_channel_arg *arg) ++-{ ++- struct wmi_set_channel_cmd *cmd; ++- struct sk_buff *skb; ++- u32 ch_flags = 0; ++- ++- if (arg->passive) ++- return -EINVAL; ++- ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); ++- if (!skb) ++- return -ENOMEM; ++- ++- if (arg->chan_radar) ++- ch_flags |= WMI_CHAN_FLAG_DFS; ++- ++- cmd = (struct wmi_set_channel_cmd *)skb->data; ++- cmd->chan.mhz = __cpu_to_le32(arg->freq); ++- cmd->chan.band_center_freq1 = __cpu_to_le32(arg->freq); ++- cmd->chan.mode = arg->mode; ++- cmd->chan.flags |= __cpu_to_le32(ch_flags); ++- cmd->chan.min_power = arg->min_power; ++- cmd->chan.max_power = arg->max_power; ++- cmd->chan.reg_power = arg->max_reg_power; ++- cmd->chan.reg_classid = arg->reg_class_id; ++- cmd->chan.antenna_max = arg->max_antenna_gain; ++- ++- ath10k_dbg(ATH10K_DBG_WMI, ++- "wmi set channel mode %d freq %d\n", ++- arg->mode, arg->freq); ++- ++- return ath10k_wmi_cmd_send(ar, skb, ++- ar->wmi.cmd->pdev_set_channel_cmdid); +++ return skb; ++ } ++ ++-int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt) +++static struct sk_buff * +++ath10k_wmi_op_gen_pdev_suspend(struct ath10k *ar, u32 suspend_opt) ++ { ++ struct wmi_pdev_suspend_cmd *cmd; ++ struct sk_buff *skb; ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_pdev_suspend_cmd *)skb->data; ++ cmd->suspend_opt = __cpu_to_le32(suspend_opt); ++ ++- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_suspend_cmdid); +++ return skb; ++ } ++ ++-int ath10k_wmi_pdev_resume_target(struct ath10k *ar) +++static struct sk_buff * +++ath10k_wmi_op_gen_pdev_resume(struct ath10k *ar) ++ { ++ struct sk_buff *skb; ++ ++- skb = ath10k_wmi_alloc_skb(0); ++- if (skb == NULL) ++- return -ENOMEM; +++ skb = ath10k_wmi_alloc_skb(ar, 0); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); ++ ++- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_resume_cmdid); +++ return skb; ++ } ++ ++-int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value) +++static struct sk_buff * +++ath10k_wmi_op_gen_pdev_set_param(struct ath10k *ar, u32 id, u32 value) ++ { ++ struct wmi_pdev_set_param_cmd *cmd; ++ struct sk_buff *skb; ++ ++ if (id == WMI_PDEV_PARAM_UNSUPPORTED) { ++- ath10k_warn("pdev param %d not supported by firmware\n", id); ++- return -EOPNOTSUPP; +++ ath10k_warn(ar, "pdev param %d not supported by firmware\n", +++ id); +++ return ERR_PTR(-EOPNOTSUPP); ++ } ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_pdev_set_param_cmd *)skb->data; ++ cmd->param_id = __cpu_to_le32(id); ++ cmd->param_value = __cpu_to_le32(value); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, "wmi pdev set param %d value %d\n", +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set param %d value %d\n", ++ id, value); ++- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_param_cmdid); +++ return skb; ++ } ++ ++-static int ath10k_wmi_main_cmd_init(struct ath10k *ar) +++void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar, +++ struct wmi_host_mem_chunks *chunks) ++ { ++- struct wmi_init_cmd *cmd; ++- struct sk_buff *buf; ++- struct wmi_resource_config config = {}; ++- u32 len, val; +++ struct host_memory_chunk *chunk; ++ int i; ++ ++- config.num_vdevs = __cpu_to_le32(TARGET_NUM_VDEVS); ++- config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS + TARGET_NUM_VDEVS); +++ chunks->count = __cpu_to_le32(ar->wmi.num_mem_chunks); +++ +++ for (i = 0; i < ar->wmi.num_mem_chunks; i++) { +++ chunk = &chunks->items[i]; +++ chunk->ptr = __cpu_to_le32(ar->wmi.mem_chunks[i].paddr); +++ chunk->size = __cpu_to_le32(ar->wmi.mem_chunks[i].len); +++ chunk->req_id = __cpu_to_le32(ar->wmi.mem_chunks[i].req_id); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, +++ "wmi chunk %d len %d requested, addr 0x%llx\n", +++ i, +++ ar->wmi.mem_chunks[i].len, +++ (unsigned long long)ar->wmi.mem_chunks[i].paddr); +++ } +++} +++ +++static struct sk_buff *ath10k_wmi_op_gen_init(struct ath10k *ar) +++{ +++ struct wmi_init_cmd *cmd; +++ struct sk_buff *buf; +++ struct wmi_resource_config config = {}; +++ u32 len, val; +++ +++ config.num_vdevs = __cpu_to_le32(TARGET_NUM_VDEVS); +++ config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS); ++ config.num_offload_peers = __cpu_to_le32(TARGET_NUM_OFFLOAD_PEERS); ++ ++ config.num_offload_reorder_bufs = ++@@ -2600,50 +3850,25 @@ static int ath10k_wmi_main_cmd_init(stru ++ len = sizeof(*cmd) + ++ (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks); ++ ++- buf = ath10k_wmi_alloc_skb(len); +++ buf = ath10k_wmi_alloc_skb(ar, len); ++ if (!buf) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_init_cmd *)buf->data; ++ ++- if (ar->wmi.num_mem_chunks == 0) { ++- cmd->num_host_mem_chunks = 0; ++- goto out; ++- } ++- ++- ath10k_dbg(ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n", ++- ar->wmi.num_mem_chunks); ++- ++- cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks); ++- ++- for (i = 0; i < ar->wmi.num_mem_chunks; i++) { ++- cmd->host_mem_chunks[i].ptr = ++- __cpu_to_le32(ar->wmi.mem_chunks[i].paddr); ++- cmd->host_mem_chunks[i].size = ++- __cpu_to_le32(ar->wmi.mem_chunks[i].len); ++- cmd->host_mem_chunks[i].req_id = ++- __cpu_to_le32(ar->wmi.mem_chunks[i].req_id); ++- ++- ath10k_dbg(ATH10K_DBG_WMI, ++- "wmi chunk %d len %d requested, addr 0x%llx\n", ++- i, ++- ar->wmi.mem_chunks[i].len, ++- (unsigned long long)ar->wmi.mem_chunks[i].paddr); ++- } ++-out: ++ memcpy(&cmd->resource_config, &config, sizeof(config)); +++ ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, "wmi init\n"); ++- return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init\n"); +++ return buf; ++ } ++ ++-static int ath10k_wmi_10x_cmd_init(struct ath10k *ar) +++static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar) ++ { ++ struct wmi_init_cmd_10x *cmd; ++ struct sk_buff *buf; ++ struct wmi_resource_config_10x config = {}; ++ u32 len, val; ++- int i; ++ ++ config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS); ++ config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS); ++@@ -2691,101 +3916,132 @@ static int ath10k_wmi_10x_cmd_init(struc ++ len = sizeof(*cmd) + ++ (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks); ++ ++- buf = ath10k_wmi_alloc_skb(len); +++ buf = ath10k_wmi_alloc_skb(ar, len); ++ if (!buf) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_init_cmd_10x *)buf->data; ++ ++- if (ar->wmi.num_mem_chunks == 0) { ++- cmd->num_host_mem_chunks = 0; ++- goto out; ++- } +++ memcpy(&cmd->resource_config, &config, sizeof(config)); +++ ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n", ++- ar->wmi.num_mem_chunks); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10x\n"); +++ return buf; +++} ++ ++- cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks); +++static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar) +++{ +++ struct wmi_init_cmd_10_2 *cmd; +++ struct sk_buff *buf; +++ struct wmi_resource_config_10x config = {}; +++ u32 len, val, features; ++ ++- for (i = 0; i < ar->wmi.num_mem_chunks; i++) { ++- cmd->host_mem_chunks[i].ptr = ++- __cpu_to_le32(ar->wmi.mem_chunks[i].paddr); ++- cmd->host_mem_chunks[i].size = ++- __cpu_to_le32(ar->wmi.mem_chunks[i].len); ++- cmd->host_mem_chunks[i].req_id = ++- __cpu_to_le32(ar->wmi.mem_chunks[i].req_id); +++ config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS); +++ config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS); +++ config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS); +++ config.num_tids = __cpu_to_le32(TARGET_10X_NUM_TIDS); +++ config.ast_skid_limit = __cpu_to_le32(TARGET_10X_AST_SKID_LIMIT); +++ config.tx_chain_mask = __cpu_to_le32(TARGET_10X_TX_CHAIN_MASK); +++ config.rx_chain_mask = __cpu_to_le32(TARGET_10X_RX_CHAIN_MASK); +++ config.rx_timeout_pri_vo = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI); +++ config.rx_timeout_pri_vi = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI); +++ config.rx_timeout_pri_be = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI); +++ config.rx_timeout_pri_bk = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_HI_PRI); +++ config.rx_decap_mode = __cpu_to_le32(TARGET_10X_RX_DECAP_MODE); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, ++- "wmi chunk %d len %d requested, addr 0x%llx\n", ++- i, ++- ar->wmi.mem_chunks[i].len, ++- (unsigned long long)ar->wmi.mem_chunks[i].paddr); ++- } ++-out: ++- memcpy(&cmd->resource_config, &config, sizeof(config)); +++ config.scan_max_pending_reqs = +++ __cpu_to_le32(TARGET_10X_SCAN_MAX_PENDING_REQS); +++ +++ config.bmiss_offload_max_vdev = +++ __cpu_to_le32(TARGET_10X_BMISS_OFFLOAD_MAX_VDEV); +++ +++ config.roam_offload_max_vdev = +++ __cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_VDEV); +++ +++ config.roam_offload_max_ap_profiles = +++ __cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_AP_PROFILES); +++ +++ config.num_mcast_groups = __cpu_to_le32(TARGET_10X_NUM_MCAST_GROUPS); +++ config.num_mcast_table_elems = +++ __cpu_to_le32(TARGET_10X_NUM_MCAST_TABLE_ELEMS); +++ +++ config.mcast2ucast_mode = __cpu_to_le32(TARGET_10X_MCAST2UCAST_MODE); +++ config.tx_dbg_log_size = __cpu_to_le32(TARGET_10X_TX_DBG_LOG_SIZE); +++ config.num_wds_entries = __cpu_to_le32(TARGET_10X_NUM_WDS_ENTRIES); +++ config.dma_burst_size = __cpu_to_le32(TARGET_10_2_DMA_BURST_SIZE); +++ config.mac_aggr_delim = __cpu_to_le32(TARGET_10X_MAC_AGGR_DELIM); +++ +++ val = TARGET_10X_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK; +++ config.rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(val); +++ +++ config.vow_config = __cpu_to_le32(TARGET_10X_VOW_CONFIG); +++ +++ config.num_msdu_desc = __cpu_to_le32(TARGET_10X_NUM_MSDU_DESC); +++ config.max_frag_entries = __cpu_to_le32(TARGET_10X_MAX_FRAG_ENTRIES); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, "wmi init 10x\n"); ++- return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid); +++ len = sizeof(*cmd) + +++ (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks); +++ +++ buf = ath10k_wmi_alloc_skb(ar, len); +++ if (!buf) +++ return ERR_PTR(-ENOMEM); +++ +++ cmd = (struct wmi_init_cmd_10_2 *)buf->data; +++ +++ features = WMI_10_2_RX_BATCH_MODE; +++ cmd->resource_config.feature_mask = __cpu_to_le32(features); +++ +++ memcpy(&cmd->resource_config.common, &config, sizeof(config)); +++ ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10.2\n"); +++ return buf; ++ } ++ ++-int ath10k_wmi_cmd_init(struct ath10k *ar) +++int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg) ++ { ++- int ret; +++ if (arg->ie_len && !arg->ie) +++ return -EINVAL; +++ if (arg->n_channels && !arg->channels) +++ return -EINVAL; +++ if (arg->n_ssids && !arg->ssids) +++ return -EINVAL; +++ if (arg->n_bssids && !arg->bssids) +++ return -EINVAL; ++ ++- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) ++- ret = ath10k_wmi_10x_cmd_init(ar); ++- else ++- ret = ath10k_wmi_main_cmd_init(ar); +++ if (arg->ie_len > WLAN_SCAN_PARAMS_MAX_IE_LEN) +++ return -EINVAL; +++ if (arg->n_channels > ARRAY_SIZE(arg->channels)) +++ return -EINVAL; +++ if (arg->n_ssids > WLAN_SCAN_PARAMS_MAX_SSID) +++ return -EINVAL; +++ if (arg->n_bssids > WLAN_SCAN_PARAMS_MAX_BSSID) +++ return -EINVAL; ++ ++- return ret; +++ return 0; ++ } ++ ++-static int ath10k_wmi_start_scan_calc_len(struct ath10k *ar, ++- const struct wmi_start_scan_arg *arg) +++static size_t +++ath10k_wmi_start_scan_tlvs_len(const struct wmi_start_scan_arg *arg) ++ { ++- int len; ++- ++- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) ++- len = sizeof(struct wmi_start_scan_cmd_10x); ++- else ++- len = sizeof(struct wmi_start_scan_cmd); +++ int len = 0; ++ ++ if (arg->ie_len) { ++- if (!arg->ie) ++- return -EINVAL; ++- if (arg->ie_len > WLAN_SCAN_PARAMS_MAX_IE_LEN) ++- return -EINVAL; ++- ++ len += sizeof(struct wmi_ie_data); ++ len += roundup(arg->ie_len, 4); ++ } ++ ++ if (arg->n_channels) { ++- if (!arg->channels) ++- return -EINVAL; ++- if (arg->n_channels > ARRAY_SIZE(arg->channels)) ++- return -EINVAL; ++- ++ len += sizeof(struct wmi_chan_list); ++ len += sizeof(__le32) * arg->n_channels; ++ } ++ ++ if (arg->n_ssids) { ++- if (!arg->ssids) ++- return -EINVAL; ++- if (arg->n_ssids > WLAN_SCAN_PARAMS_MAX_SSID) ++- return -EINVAL; ++- ++ len += sizeof(struct wmi_ssid_list); ++ len += sizeof(struct wmi_ssid) * arg->n_ssids; ++ } ++ ++ if (arg->n_bssids) { ++- if (!arg->bssids) ++- return -EINVAL; ++- if (arg->n_bssids > WLAN_SCAN_PARAMS_MAX_BSSID) ++- return -EINVAL; ++- ++ len += sizeof(struct wmi_bssid_list); ++ len += sizeof(struct wmi_mac_addr) * arg->n_bssids; ++ } ++@@ -2793,28 +4049,11 @@ static int ath10k_wmi_start_scan_calc_le ++ return len; ++ } ++ ++-int ath10k_wmi_start_scan(struct ath10k *ar, ++- const struct wmi_start_scan_arg *arg) +++void ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn, +++ const struct wmi_start_scan_arg *arg) ++ { ++- struct wmi_start_scan_cmd *cmd; ++- struct sk_buff *skb; ++- struct wmi_ie_data *ie; ++- struct wmi_chan_list *channels; ++- struct wmi_ssid_list *ssids; ++- struct wmi_bssid_list *bssids; ++ u32 scan_id; ++ u32 scan_req_id; ++- int off; ++- int len = 0; ++- int i; ++- ++- len = ath10k_wmi_start_scan_calc_len(ar, arg); ++- if (len < 0) ++- return len; /* len contains error code here */ ++- ++- skb = ath10k_wmi_alloc_skb(len); ++- if (!skb) ++- return -ENOMEM; ++ ++ scan_id = WMI_HOST_SCAN_REQ_ID_PREFIX; ++ scan_id |= arg->scan_id; ++@@ -2822,48 +4061,49 @@ int ath10k_wmi_start_scan(struct ath10k ++ scan_req_id = WMI_HOST_SCAN_REQUESTOR_ID_PREFIX; ++ scan_req_id |= arg->scan_req_id; ++ ++- cmd = (struct wmi_start_scan_cmd *)skb->data; ++- cmd->scan_id = __cpu_to_le32(scan_id); ++- cmd->scan_req_id = __cpu_to_le32(scan_req_id); ++- cmd->vdev_id = __cpu_to_le32(arg->vdev_id); ++- cmd->scan_priority = __cpu_to_le32(arg->scan_priority); ++- cmd->notify_scan_events = __cpu_to_le32(arg->notify_scan_events); ++- cmd->dwell_time_active = __cpu_to_le32(arg->dwell_time_active); ++- cmd->dwell_time_passive = __cpu_to_le32(arg->dwell_time_passive); ++- cmd->min_rest_time = __cpu_to_le32(arg->min_rest_time); ++- cmd->max_rest_time = __cpu_to_le32(arg->max_rest_time); ++- cmd->repeat_probe_time = __cpu_to_le32(arg->repeat_probe_time); ++- cmd->probe_spacing_time = __cpu_to_le32(arg->probe_spacing_time); ++- cmd->idle_time = __cpu_to_le32(arg->idle_time); ++- cmd->max_scan_time = __cpu_to_le32(arg->max_scan_time); ++- cmd->probe_delay = __cpu_to_le32(arg->probe_delay); ++- cmd->scan_ctrl_flags = __cpu_to_le32(arg->scan_ctrl_flags); ++- ++- /* TLV list starts after fields included in the struct */ ++- /* There's just one filed that differes the two start_scan ++- * structures - burst_duration, which we are not using btw, ++- no point to make the split here, just shift the buffer to fit with ++- given FW */ ++- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) ++- off = sizeof(struct wmi_start_scan_cmd_10x); ++- else ++- off = sizeof(struct wmi_start_scan_cmd); +++ cmn->scan_id = __cpu_to_le32(scan_id); +++ cmn->scan_req_id = __cpu_to_le32(scan_req_id); +++ cmn->vdev_id = __cpu_to_le32(arg->vdev_id); +++ cmn->scan_priority = __cpu_to_le32(arg->scan_priority); +++ cmn->notify_scan_events = __cpu_to_le32(arg->notify_scan_events); +++ cmn->dwell_time_active = __cpu_to_le32(arg->dwell_time_active); +++ cmn->dwell_time_passive = __cpu_to_le32(arg->dwell_time_passive); +++ cmn->min_rest_time = __cpu_to_le32(arg->min_rest_time); +++ cmn->max_rest_time = __cpu_to_le32(arg->max_rest_time); +++ cmn->repeat_probe_time = __cpu_to_le32(arg->repeat_probe_time); +++ cmn->probe_spacing_time = __cpu_to_le32(arg->probe_spacing_time); +++ cmn->idle_time = __cpu_to_le32(arg->idle_time); +++ cmn->max_scan_time = __cpu_to_le32(arg->max_scan_time); +++ cmn->probe_delay = __cpu_to_le32(arg->probe_delay); +++ cmn->scan_ctrl_flags = __cpu_to_le32(arg->scan_ctrl_flags); +++} +++ +++static void +++ath10k_wmi_put_start_scan_tlvs(struct wmi_start_scan_tlvs *tlvs, +++ const struct wmi_start_scan_arg *arg) +++{ +++ struct wmi_ie_data *ie; +++ struct wmi_chan_list *channels; +++ struct wmi_ssid_list *ssids; +++ struct wmi_bssid_list *bssids; +++ void *ptr = tlvs->tlvs; +++ int i; ++ ++ if (arg->n_channels) { ++- channels = (void *)skb->data + off; +++ channels = ptr; ++ channels->tag = __cpu_to_le32(WMI_CHAN_LIST_TAG); ++ channels->num_chan = __cpu_to_le32(arg->n_channels); ++ ++ for (i = 0; i < arg->n_channels; i++) ++- channels->channel_list[i] = ++- __cpu_to_le32(arg->channels[i]); +++ channels->channel_list[i].freq = +++ __cpu_to_le16(arg->channels[i]); ++ ++- off += sizeof(*channels); ++- off += sizeof(__le32) * arg->n_channels; +++ ptr += sizeof(*channels); +++ ptr += sizeof(__le32) * arg->n_channels; ++ } ++ ++ if (arg->n_ssids) { ++- ssids = (void *)skb->data + off; +++ ssids = ptr; ++ ssids->tag = __cpu_to_le32(WMI_SSID_LIST_TAG); ++ ssids->num_ssids = __cpu_to_le32(arg->n_ssids); ++ ++@@ -2875,12 +4115,12 @@ int ath10k_wmi_start_scan(struct ath10k ++ arg->ssids[i].len); ++ } ++ ++- off += sizeof(*ssids); ++- off += sizeof(struct wmi_ssid) * arg->n_ssids; +++ ptr += sizeof(*ssids); +++ ptr += sizeof(struct wmi_ssid) * arg->n_ssids; ++ } ++ ++ if (arg->n_bssids) { ++- bssids = (void *)skb->data + off; +++ bssids = ptr; ++ bssids->tag = __cpu_to_le32(WMI_BSSID_LIST_TAG); ++ bssids->num_bssid = __cpu_to_le32(arg->n_bssids); ++ ++@@ -2889,27 +4129,75 @@ int ath10k_wmi_start_scan(struct ath10k ++ arg->bssids[i].bssid, ++ ETH_ALEN); ++ ++- off += sizeof(*bssids); ++- off += sizeof(struct wmi_mac_addr) * arg->n_bssids; +++ ptr += sizeof(*bssids); +++ ptr += sizeof(struct wmi_mac_addr) * arg->n_bssids; ++ } ++ ++ if (arg->ie_len) { ++- ie = (void *)skb->data + off; +++ ie = ptr; ++ ie->tag = __cpu_to_le32(WMI_IE_TAG); ++ ie->ie_len = __cpu_to_le32(arg->ie_len); ++ memcpy(ie->ie_data, arg->ie, arg->ie_len); ++ ++- off += sizeof(*ie); ++- off += roundup(arg->ie_len, 4); +++ ptr += sizeof(*ie); +++ ptr += roundup(arg->ie_len, 4); ++ } +++} ++ ++- if (off != skb->len) { ++- dev_kfree_skb(skb); ++- return -EINVAL; ++- } +++static struct sk_buff * +++ath10k_wmi_op_gen_start_scan(struct ath10k *ar, +++ const struct wmi_start_scan_arg *arg) +++{ +++ struct wmi_start_scan_cmd *cmd; +++ struct sk_buff *skb; +++ size_t len; +++ int ret; +++ +++ ret = ath10k_wmi_start_scan_verify(arg); +++ if (ret) +++ return ERR_PTR(ret); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, "wmi start scan\n"); ++- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->start_scan_cmdid); +++ len = sizeof(*cmd) + ath10k_wmi_start_scan_tlvs_len(arg); +++ skb = ath10k_wmi_alloc_skb(ar, len); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ cmd = (struct wmi_start_scan_cmd *)skb->data; +++ +++ ath10k_wmi_put_start_scan_common(&cmd->common, arg); +++ ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg); +++ +++ cmd->burst_duration_ms = __cpu_to_le32(0); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi start scan\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_10x_op_gen_start_scan(struct ath10k *ar, +++ const struct wmi_start_scan_arg *arg) +++{ +++ struct wmi_10x_start_scan_cmd *cmd; +++ struct sk_buff *skb; +++ size_t len; +++ int ret; +++ +++ ret = ath10k_wmi_start_scan_verify(arg); +++ if (ret) +++ return ERR_PTR(ret); +++ +++ len = sizeof(*cmd) + ath10k_wmi_start_scan_tlvs_len(arg); +++ skb = ath10k_wmi_alloc_skb(ar, len); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ cmd = (struct wmi_10x_start_scan_cmd *)skb->data; +++ +++ ath10k_wmi_put_start_scan_common(&cmd->common, arg); +++ ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi 10x start scan\n"); +++ return skb; ++ } ++ ++ void ath10k_wmi_start_scan_init(struct ath10k *ar, ++@@ -2938,7 +4226,9 @@ void ath10k_wmi_start_scan_init(struct a ++ arg->bssids[0].bssid = "\xFF\xFF\xFF\xFF\xFF\xFF"; ++ } ++ ++-int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg) +++static struct sk_buff * +++ath10k_wmi_op_gen_stop_scan(struct ath10k *ar, +++ const struct wmi_stop_scan_arg *arg) ++ { ++ struct wmi_stop_scan_cmd *cmd; ++ struct sk_buff *skb; ++@@ -2946,13 +4236,13 @@ int ath10k_wmi_stop_scan(struct ath10k * ++ u32 req_id; ++ ++ if (arg->req_id > 0xFFF) ++- return -EINVAL; +++ return ERR_PTR(-EINVAL); ++ if (arg->req_type == WMI_SCAN_STOP_ONE && arg->u.scan_id > 0xFFF) ++- return -EINVAL; +++ return ERR_PTR(-EINVAL); ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ scan_id = arg->u.scan_id; ++ scan_id |= WMI_HOST_SCAN_REQ_ID_PREFIX; ++@@ -2966,92 +4256,85 @@ int ath10k_wmi_stop_scan(struct ath10k * ++ cmd->scan_id = __cpu_to_le32(scan_id); ++ cmd->scan_req_id = __cpu_to_le32(req_id); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "wmi stop scan reqid %d req_type %d vdev/scan_id %d\n", ++ arg->req_id, arg->req_type, arg->u.scan_id); ++- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->stop_scan_cmdid); +++ return skb; ++ } ++ ++-int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id, ++- enum wmi_vdev_type type, ++- enum wmi_vdev_subtype subtype, ++- const u8 macaddr[ETH_ALEN]) +++static struct sk_buff * +++ath10k_wmi_op_gen_vdev_create(struct ath10k *ar, u32 vdev_id, +++ enum wmi_vdev_type type, +++ enum wmi_vdev_subtype subtype, +++ const u8 macaddr[ETH_ALEN]) ++ { ++ struct wmi_vdev_create_cmd *cmd; ++ struct sk_buff *skb; ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_vdev_create_cmd *)skb->data; ++ cmd->vdev_id = __cpu_to_le32(vdev_id); ++ cmd->vdev_type = __cpu_to_le32(type); ++ cmd->vdev_subtype = __cpu_to_le32(subtype); ++- memcpy(cmd->vdev_macaddr.addr, macaddr, ETH_ALEN); +++ ether_addr_copy(cmd->vdev_macaddr.addr, macaddr); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "WMI vdev create: id %d type %d subtype %d macaddr %pM\n", ++ vdev_id, type, subtype, macaddr); ++- ++- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_create_cmdid); +++ return skb; ++ } ++ ++-int ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id) +++static struct sk_buff * +++ath10k_wmi_op_gen_vdev_delete(struct ath10k *ar, u32 vdev_id) ++ { ++ struct wmi_vdev_delete_cmd *cmd; ++ struct sk_buff *skb; ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_vdev_delete_cmd *)skb->data; ++ cmd->vdev_id = __cpu_to_le32(vdev_id); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "WMI vdev delete id %d\n", vdev_id); ++- ++- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_delete_cmdid); +++ return skb; ++ } ++ ++-static int ath10k_wmi_vdev_start_restart(struct ath10k *ar, ++- const struct wmi_vdev_start_request_arg *arg, ++- u32 cmd_id) +++static struct sk_buff * +++ath10k_wmi_op_gen_vdev_start(struct ath10k *ar, +++ const struct wmi_vdev_start_request_arg *arg, +++ bool restart) ++ { ++ struct wmi_vdev_start_request_cmd *cmd; ++ struct sk_buff *skb; ++ const char *cmdname; ++ u32 flags = 0; ++- u32 ch_flags = 0; ++ ++- if (cmd_id != ar->wmi.cmd->vdev_start_request_cmdid && ++- cmd_id != ar->wmi.cmd->vdev_restart_request_cmdid) ++- return -EINVAL; ++ if (WARN_ON(arg->ssid && arg->ssid_len == 0)) ++- return -EINVAL; +++ return ERR_PTR(-EINVAL); ++ if (WARN_ON(arg->hidden_ssid && !arg->ssid)) ++- return -EINVAL; +++ return ERR_PTR(-EINVAL); ++ if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid))) ++- return -EINVAL; +++ return ERR_PTR(-EINVAL); ++ ++- if (cmd_id == ar->wmi.cmd->vdev_start_request_cmdid) ++- cmdname = "start"; ++- else if (cmd_id == ar->wmi.cmd->vdev_restart_request_cmdid) +++ if (restart) ++ cmdname = "restart"; ++ else ++- return -EINVAL; /* should not happen, we already check cmd_id */ +++ cmdname = "start"; ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ if (arg->hidden_ssid) ++ flags |= WMI_VDEV_START_HIDDEN_SSID; ++ if (arg->pmf_enabled) ++ flags |= WMI_VDEV_START_PMF_ENABLED; ++- if (arg->channel.chan_radar) ++- ch_flags |= WMI_CHAN_FLAG_DFS; ++ ++ cmd = (struct wmi_vdev_start_request_cmd *)skb->data; ++ cmd->vdev_id = __cpu_to_le32(arg->vdev_id); ++@@ -3067,143 +4350,118 @@ static int ath10k_wmi_vdev_start_restart ++ memcpy(cmd->ssid.ssid, arg->ssid, arg->ssid_len); ++ } ++ ++- cmd->chan.mhz = __cpu_to_le32(arg->channel.freq); +++ ath10k_wmi_put_wmi_channel(&cmd->chan, &arg->channel); ++ ++- cmd->chan.band_center_freq1 = ++- __cpu_to_le32(arg->channel.band_center_freq1); ++- ++- cmd->chan.mode = arg->channel.mode; ++- cmd->chan.flags |= __cpu_to_le32(ch_flags); ++- cmd->chan.min_power = arg->channel.min_power; ++- cmd->chan.max_power = arg->channel.max_power; ++- cmd->chan.reg_power = arg->channel.max_reg_power; ++- cmd->chan.reg_classid = arg->channel.reg_class_id; ++- cmd->chan.antenna_max = arg->channel.max_antenna_gain; ++- ++- ath10k_dbg(ATH10K_DBG_WMI, ++- "wmi vdev %s id 0x%x flags: 0x%0X, freq %d, mode %d, " ++- "ch_flags: 0x%0X, max_power: %d\n", cmdname, arg->vdev_id, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, +++ "wmi vdev %s id 0x%x flags: 0x%0X, freq %d, mode %d, ch_flags: 0x%0X, max_power: %d\n", +++ cmdname, arg->vdev_id, ++ flags, arg->channel.freq, arg->channel.mode, ++ cmd->chan.flags, arg->channel.max_power); ++ ++- return ath10k_wmi_cmd_send(ar, skb, cmd_id); ++-} ++- ++-int ath10k_wmi_vdev_start(struct ath10k *ar, ++- const struct wmi_vdev_start_request_arg *arg) ++-{ ++- u32 cmd_id = ar->wmi.cmd->vdev_start_request_cmdid; ++- ++- return ath10k_wmi_vdev_start_restart(ar, arg, cmd_id); ++-} ++- ++-int ath10k_wmi_vdev_restart(struct ath10k *ar, ++- const struct wmi_vdev_start_request_arg *arg) ++-{ ++- u32 cmd_id = ar->wmi.cmd->vdev_restart_request_cmdid; ++- ++- return ath10k_wmi_vdev_start_restart(ar, arg, cmd_id); +++ return skb; ++ } ++ ++-int ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id) +++static struct sk_buff * +++ath10k_wmi_op_gen_vdev_stop(struct ath10k *ar, u32 vdev_id) ++ { ++ struct wmi_vdev_stop_cmd *cmd; ++ struct sk_buff *skb; ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_vdev_stop_cmd *)skb->data; ++ cmd->vdev_id = __cpu_to_le32(vdev_id); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, "wmi vdev stop id 0x%x\n", vdev_id); ++- ++- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_stop_cmdid); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi vdev stop id 0x%x\n", vdev_id); +++ return skb; ++ } ++ ++-int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid) +++static struct sk_buff * +++ath10k_wmi_op_gen_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, +++ const u8 *bssid) ++ { ++ struct wmi_vdev_up_cmd *cmd; ++ struct sk_buff *skb; ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_vdev_up_cmd *)skb->data; ++ cmd->vdev_id = __cpu_to_le32(vdev_id); ++ cmd->vdev_assoc_id = __cpu_to_le32(aid); ++- memcpy(&cmd->vdev_bssid.addr, bssid, ETH_ALEN); +++ ether_addr_copy(cmd->vdev_bssid.addr, bssid); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "wmi mgmt vdev up id 0x%x assoc id %d bssid %pM\n", ++ vdev_id, aid, bssid); ++- ++- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_up_cmdid); +++ return skb; ++ } ++ ++-int ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id) +++static struct sk_buff * +++ath10k_wmi_op_gen_vdev_down(struct ath10k *ar, u32 vdev_id) ++ { ++ struct wmi_vdev_down_cmd *cmd; ++ struct sk_buff *skb; ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_vdev_down_cmd *)skb->data; ++ cmd->vdev_id = __cpu_to_le32(vdev_id); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "wmi mgmt vdev down id 0x%x\n", vdev_id); ++- ++- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_down_cmdid); +++ return skb; ++ } ++ ++-int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id, ++- u32 param_id, u32 param_value) +++static struct sk_buff * +++ath10k_wmi_op_gen_vdev_set_param(struct ath10k *ar, u32 vdev_id, +++ u32 param_id, u32 param_value) ++ { ++ struct wmi_vdev_set_param_cmd *cmd; ++ struct sk_buff *skb; ++ ++ if (param_id == WMI_VDEV_PARAM_UNSUPPORTED) { ++- ath10k_dbg(ATH10K_DBG_WMI, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "vdev param %d not supported by firmware\n", ++ param_id); ++- return -EOPNOTSUPP; +++ return ERR_PTR(-EOPNOTSUPP); ++ } ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_vdev_set_param_cmd *)skb->data; ++ cmd->vdev_id = __cpu_to_le32(vdev_id); ++ cmd->param_id = __cpu_to_le32(param_id); ++ cmd->param_value = __cpu_to_le32(param_value); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "wmi vdev id 0x%x set param %d value %d\n", ++ vdev_id, param_id, param_value); ++- ++- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_set_param_cmdid); +++ return skb; ++ } ++ ++-int ath10k_wmi_vdev_install_key(struct ath10k *ar, ++- const struct wmi_vdev_install_key_arg *arg) +++static struct sk_buff * +++ath10k_wmi_op_gen_vdev_install_key(struct ath10k *ar, +++ const struct wmi_vdev_install_key_arg *arg) ++ { ++ struct wmi_vdev_install_key_cmd *cmd; ++ struct sk_buff *skb; ++ ++ if (arg->key_cipher == WMI_CIPHER_NONE && arg->key_data != NULL) ++- return -EINVAL; +++ return ERR_PTR(-EINVAL); ++ if (arg->key_cipher != WMI_CIPHER_NONE && arg->key_data == NULL) ++- return -EINVAL; +++ return ERR_PTR(-EINVAL); ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd) + arg->key_len); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd) + arg->key_len); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_vdev_install_key_cmd *)skb->data; ++ cmd->vdev_id = __cpu_to_le32(arg->vdev_id); ++@@ -3215,176 +4473,232 @@ int ath10k_wmi_vdev_install_key(struct a ++ cmd->key_rxmic_len = __cpu_to_le32(arg->key_rxmic_len); ++ ++ if (arg->macaddr) ++- memcpy(cmd->peer_macaddr.addr, arg->macaddr, ETH_ALEN); +++ ether_addr_copy(cmd->peer_macaddr.addr, arg->macaddr); ++ if (arg->key_data) ++ memcpy(cmd->key_data, arg->key_data, arg->key_len); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "wmi vdev install key idx %d cipher %d len %d\n", ++ arg->key_idx, arg->key_cipher, arg->key_len); ++- return ath10k_wmi_cmd_send(ar, skb, ++- ar->wmi.cmd->vdev_install_key_cmdid); +++ return skb; ++ } ++ ++-int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id, ++- const u8 peer_addr[ETH_ALEN]) +++static struct sk_buff * +++ath10k_wmi_op_gen_vdev_spectral_conf(struct ath10k *ar, +++ const struct wmi_vdev_spectral_conf_arg *arg) +++{ +++ struct wmi_vdev_spectral_conf_cmd *cmd; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ cmd = (struct wmi_vdev_spectral_conf_cmd *)skb->data; +++ cmd->vdev_id = __cpu_to_le32(arg->vdev_id); +++ cmd->scan_count = __cpu_to_le32(arg->scan_count); +++ cmd->scan_period = __cpu_to_le32(arg->scan_period); +++ cmd->scan_priority = __cpu_to_le32(arg->scan_priority); +++ cmd->scan_fft_size = __cpu_to_le32(arg->scan_fft_size); +++ cmd->scan_gc_ena = __cpu_to_le32(arg->scan_gc_ena); +++ cmd->scan_restart_ena = __cpu_to_le32(arg->scan_restart_ena); +++ cmd->scan_noise_floor_ref = __cpu_to_le32(arg->scan_noise_floor_ref); +++ cmd->scan_init_delay = __cpu_to_le32(arg->scan_init_delay); +++ cmd->scan_nb_tone_thr = __cpu_to_le32(arg->scan_nb_tone_thr); +++ cmd->scan_str_bin_thr = __cpu_to_le32(arg->scan_str_bin_thr); +++ cmd->scan_wb_rpt_mode = __cpu_to_le32(arg->scan_wb_rpt_mode); +++ cmd->scan_rssi_rpt_mode = __cpu_to_le32(arg->scan_rssi_rpt_mode); +++ cmd->scan_rssi_thr = __cpu_to_le32(arg->scan_rssi_thr); +++ cmd->scan_pwr_format = __cpu_to_le32(arg->scan_pwr_format); +++ cmd->scan_rpt_mode = __cpu_to_le32(arg->scan_rpt_mode); +++ cmd->scan_bin_scale = __cpu_to_le32(arg->scan_bin_scale); +++ cmd->scan_dbm_adj = __cpu_to_le32(arg->scan_dbm_adj); +++ cmd->scan_chn_mask = __cpu_to_le32(arg->scan_chn_mask); +++ +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_op_gen_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, +++ u32 trigger, u32 enable) +++{ +++ struct wmi_vdev_spectral_enable_cmd *cmd; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ cmd = (struct wmi_vdev_spectral_enable_cmd *)skb->data; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ cmd->trigger_cmd = __cpu_to_le32(trigger); +++ cmd->enable_cmd = __cpu_to_le32(enable); +++ +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_op_gen_peer_create(struct ath10k *ar, u32 vdev_id, +++ const u8 peer_addr[ETH_ALEN]) ++ { ++ struct wmi_peer_create_cmd *cmd; ++ struct sk_buff *skb; ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_peer_create_cmd *)skb->data; ++ cmd->vdev_id = __cpu_to_le32(vdev_id); ++- memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN); +++ ether_addr_copy(cmd->peer_macaddr.addr, peer_addr); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "wmi peer create vdev_id %d peer_addr %pM\n", ++ vdev_id, peer_addr); ++- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_create_cmdid); +++ return skb; ++ } ++ ++-int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id, ++- const u8 peer_addr[ETH_ALEN]) +++static struct sk_buff * +++ath10k_wmi_op_gen_peer_delete(struct ath10k *ar, u32 vdev_id, +++ const u8 peer_addr[ETH_ALEN]) ++ { ++ struct wmi_peer_delete_cmd *cmd; ++ struct sk_buff *skb; ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_peer_delete_cmd *)skb->data; ++ cmd->vdev_id = __cpu_to_le32(vdev_id); ++- memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN); +++ ether_addr_copy(cmd->peer_macaddr.addr, peer_addr); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "wmi peer delete vdev_id %d peer_addr %pM\n", ++ vdev_id, peer_addr); ++- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_delete_cmdid); +++ return skb; ++ } ++ ++-int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id, ++- const u8 peer_addr[ETH_ALEN], u32 tid_bitmap) +++static struct sk_buff * +++ath10k_wmi_op_gen_peer_flush(struct ath10k *ar, u32 vdev_id, +++ const u8 peer_addr[ETH_ALEN], u32 tid_bitmap) ++ { ++ struct wmi_peer_flush_tids_cmd *cmd; ++ struct sk_buff *skb; ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_peer_flush_tids_cmd *)skb->data; ++ cmd->vdev_id = __cpu_to_le32(vdev_id); ++ cmd->peer_tid_bitmap = __cpu_to_le32(tid_bitmap); ++- memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN); +++ ether_addr_copy(cmd->peer_macaddr.addr, peer_addr); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "wmi peer flush vdev_id %d peer_addr %pM tids %08x\n", ++ vdev_id, peer_addr, tid_bitmap); ++- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_flush_tids_cmdid); +++ return skb; ++ } ++ ++-int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id, ++- const u8 *peer_addr, enum wmi_peer_param param_id, ++- u32 param_value) +++static struct sk_buff * +++ath10k_wmi_op_gen_peer_set_param(struct ath10k *ar, u32 vdev_id, +++ const u8 *peer_addr, +++ enum wmi_peer_param param_id, +++ u32 param_value) ++ { ++ struct wmi_peer_set_param_cmd *cmd; ++ struct sk_buff *skb; ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_peer_set_param_cmd *)skb->data; ++ cmd->vdev_id = __cpu_to_le32(vdev_id); ++ cmd->param_id = __cpu_to_le32(param_id); ++ cmd->param_value = __cpu_to_le32(param_value); ++- memcpy(&cmd->peer_macaddr.addr, peer_addr, ETH_ALEN); +++ ether_addr_copy(cmd->peer_macaddr.addr, peer_addr); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "wmi vdev %d peer 0x%pM set param %d value %d\n", ++ vdev_id, peer_addr, param_id, param_value); ++- ++- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_set_param_cmdid); +++ return skb; ++ } ++ ++-int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id, ++- enum wmi_sta_ps_mode psmode) +++static struct sk_buff * +++ath10k_wmi_op_gen_set_psmode(struct ath10k *ar, u32 vdev_id, +++ enum wmi_sta_ps_mode psmode) ++ { ++ struct wmi_sta_powersave_mode_cmd *cmd; ++ struct sk_buff *skb; ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_sta_powersave_mode_cmd *)skb->data; ++ cmd->vdev_id = __cpu_to_le32(vdev_id); ++ cmd->sta_ps_mode = __cpu_to_le32(psmode); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "wmi set powersave id 0x%x mode %d\n", ++ vdev_id, psmode); ++- ++- return ath10k_wmi_cmd_send(ar, skb, ++- ar->wmi.cmd->sta_powersave_mode_cmdid); +++ return skb; ++ } ++ ++-int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id, ++- enum wmi_sta_powersave_param param_id, ++- u32 value) +++static struct sk_buff * +++ath10k_wmi_op_gen_set_sta_ps(struct ath10k *ar, u32 vdev_id, +++ enum wmi_sta_powersave_param param_id, +++ u32 value) ++ { ++ struct wmi_sta_powersave_param_cmd *cmd; ++ struct sk_buff *skb; ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_sta_powersave_param_cmd *)skb->data; ++ cmd->vdev_id = __cpu_to_le32(vdev_id); ++ cmd->param_id = __cpu_to_le32(param_id); ++ cmd->param_value = __cpu_to_le32(value); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "wmi sta ps param vdev_id 0x%x param %d value %d\n", ++ vdev_id, param_id, value); ++- return ath10k_wmi_cmd_send(ar, skb, ++- ar->wmi.cmd->sta_powersave_param_cmdid); +++ return skb; ++ } ++ ++-int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac, ++- enum wmi_ap_ps_peer_param param_id, u32 value) +++static struct sk_buff * +++ath10k_wmi_op_gen_set_ap_ps(struct ath10k *ar, u32 vdev_id, const u8 *mac, +++ enum wmi_ap_ps_peer_param param_id, u32 value) ++ { ++ struct wmi_ap_ps_peer_cmd *cmd; ++ struct sk_buff *skb; ++ ++ if (!mac) ++- return -EINVAL; +++ return ERR_PTR(-EINVAL); ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_ap_ps_peer_cmd *)skb->data; ++ cmd->vdev_id = __cpu_to_le32(vdev_id); ++ cmd->param_id = __cpu_to_le32(param_id); ++ cmd->param_value = __cpu_to_le32(value); ++- memcpy(&cmd->peer_macaddr, mac, ETH_ALEN); +++ ether_addr_copy(cmd->peer_macaddr.addr, mac); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "wmi ap ps param vdev_id 0x%X param %d value %d mac_addr %pM\n", ++ vdev_id, param_id, value, mac); ++- ++- return ath10k_wmi_cmd_send(ar, skb, ++- ar->wmi.cmd->ap_ps_peer_param_cmdid); +++ return skb; ++ } ++ ++-int ath10k_wmi_scan_chan_list(struct ath10k *ar, ++- const struct wmi_scan_chan_list_arg *arg) +++static struct sk_buff * +++ath10k_wmi_op_gen_scan_chan_list(struct ath10k *ar, +++ const struct wmi_scan_chan_list_arg *arg) ++ { ++ struct wmi_scan_chan_list_cmd *cmd; ++ struct sk_buff *skb; ++@@ -3395,66 +4709,29 @@ int ath10k_wmi_scan_chan_list(struct ath ++ ++ len = sizeof(*cmd) + arg->n_channels * sizeof(struct wmi_channel); ++ ++- skb = ath10k_wmi_alloc_skb(len); +++ skb = ath10k_wmi_alloc_skb(ar, len); ++ if (!skb) ++- return -EINVAL; +++ return ERR_PTR(-EINVAL); ++ ++ cmd = (struct wmi_scan_chan_list_cmd *)skb->data; ++ cmd->num_scan_chans = __cpu_to_le32(arg->n_channels); ++ ++ for (i = 0; i < arg->n_channels; i++) { ++- u32 flags = 0; ++- ++ ch = &arg->channels[i]; ++ ci = &cmd->chan_info[i]; ++ ++- if (ch->passive) ++- flags |= WMI_CHAN_FLAG_PASSIVE; ++- if (ch->allow_ibss) ++- flags |= WMI_CHAN_FLAG_ADHOC_ALLOWED; ++- if (ch->allow_ht) ++- flags |= WMI_CHAN_FLAG_ALLOW_HT; ++- if (ch->allow_vht) ++- flags |= WMI_CHAN_FLAG_ALLOW_VHT; ++- if (ch->ht40plus) ++- flags |= WMI_CHAN_FLAG_HT40_PLUS; ++- if (ch->chan_radar) ++- flags |= WMI_CHAN_FLAG_DFS; ++- ++- ci->mhz = __cpu_to_le32(ch->freq); ++- ci->band_center_freq1 = __cpu_to_le32(ch->freq); ++- ci->band_center_freq2 = 0; ++- ci->min_power = ch->min_power; ++- ci->max_power = ch->max_power; ++- ci->reg_power = ch->max_reg_power; ++- ci->antenna_max = ch->max_antenna_gain; ++- ++- /* mode & flags share storage */ ++- ci->mode = ch->mode; ++- ci->flags |= __cpu_to_le32(flags); +++ ath10k_wmi_put_wmi_channel(ci, ch); ++ } ++ ++- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid); +++ return skb; ++ } ++ ++-int ath10k_wmi_peer_assoc(struct ath10k *ar, ++- const struct wmi_peer_assoc_complete_arg *arg) +++static void +++ath10k_wmi_peer_assoc_fill(struct ath10k *ar, void *buf, +++ const struct wmi_peer_assoc_complete_arg *arg) ++ { ++- struct wmi_peer_assoc_complete_cmd *cmd; ++- struct sk_buff *skb; +++ struct wmi_common_peer_assoc_complete_cmd *cmd = buf; ++ ++- if (arg->peer_mpdu_density > 16) ++- return -EINVAL; ++- if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES) ++- return -EINVAL; ++- if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES) ++- return -EINVAL; ++- ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); ++- if (!skb) ++- return -ENOMEM; ++- ++- cmd = (struct wmi_peer_assoc_complete_cmd *)skb->data; ++ cmd->vdev_id = __cpu_to_le32(arg->vdev_id); ++ cmd->peer_new_assoc = __cpu_to_le32(arg->peer_reassoc ? 0 : 1); ++ cmd->peer_associd = __cpu_to_le32(arg->peer_aid); ++@@ -3469,7 +4746,7 @@ int ath10k_wmi_peer_assoc(struct ath10k ++ cmd->peer_vht_caps = __cpu_to_le32(arg->peer_vht_caps); ++ cmd->peer_phymode = __cpu_to_le32(arg->peer_phymode); ++ ++- memcpy(cmd->peer_macaddr.addr, arg->addr, ETH_ALEN); +++ ether_addr_copy(cmd->peer_macaddr.addr, arg->addr); ++ ++ cmd->peer_legacy_rates.num_rates = ++ __cpu_to_le32(arg->peer_legacy_rates.num_rates); ++@@ -3489,57 +4766,183 @@ int ath10k_wmi_peer_assoc(struct ath10k ++ __cpu_to_le32(arg->peer_vht_rates.tx_max_rate); ++ cmd->peer_vht_rates.tx_mcs_set = ++ __cpu_to_le32(arg->peer_vht_rates.tx_mcs_set); +++} +++ +++static void +++ath10k_wmi_peer_assoc_fill_main(struct ath10k *ar, void *buf, +++ const struct wmi_peer_assoc_complete_arg *arg) +++{ +++ struct wmi_main_peer_assoc_complete_cmd *cmd = buf; ++ ++- ath10k_dbg(ATH10K_DBG_WMI, +++ ath10k_wmi_peer_assoc_fill(ar, buf, arg); +++ memset(cmd->peer_ht_info, 0, sizeof(cmd->peer_ht_info)); +++} +++ +++static void +++ath10k_wmi_peer_assoc_fill_10_1(struct ath10k *ar, void *buf, +++ const struct wmi_peer_assoc_complete_arg *arg) +++{ +++ ath10k_wmi_peer_assoc_fill(ar, buf, arg); +++} +++ +++static void +++ath10k_wmi_peer_assoc_fill_10_2(struct ath10k *ar, void *buf, +++ const struct wmi_peer_assoc_complete_arg *arg) +++{ +++ struct wmi_10_2_peer_assoc_complete_cmd *cmd = buf; +++ int max_mcs, max_nss; +++ u32 info0; +++ +++ /* TODO: Is using max values okay with firmware? */ +++ max_mcs = 0xf; +++ max_nss = 0xf; +++ +++ info0 = SM(max_mcs, WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX) | +++ SM(max_nss, WMI_PEER_ASSOC_INFO0_MAX_NSS); +++ +++ ath10k_wmi_peer_assoc_fill(ar, buf, arg); +++ cmd->info0 = __cpu_to_le32(info0); +++} +++ +++static int +++ath10k_wmi_peer_assoc_check_arg(const struct wmi_peer_assoc_complete_arg *arg) +++{ +++ if (arg->peer_mpdu_density > 16) +++ return -EINVAL; +++ if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES) +++ return -EINVAL; +++ if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES) +++ return -EINVAL; +++ +++ return 0; +++} +++ +++static struct sk_buff * +++ath10k_wmi_op_gen_peer_assoc(struct ath10k *ar, +++ const struct wmi_peer_assoc_complete_arg *arg) +++{ +++ size_t len = sizeof(struct wmi_main_peer_assoc_complete_cmd); +++ struct sk_buff *skb; +++ int ret; +++ +++ ret = ath10k_wmi_peer_assoc_check_arg(arg); +++ if (ret) +++ return ERR_PTR(ret); +++ +++ skb = ath10k_wmi_alloc_skb(ar, len); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ ath10k_wmi_peer_assoc_fill_main(ar, skb->data, arg); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, +++ "wmi peer assoc vdev %d addr %pM (%s)\n", +++ arg->vdev_id, arg->addr, +++ arg->peer_reassoc ? "reassociate" : "new"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_10_1_op_gen_peer_assoc(struct ath10k *ar, +++ const struct wmi_peer_assoc_complete_arg *arg) +++{ +++ size_t len = sizeof(struct wmi_10_1_peer_assoc_complete_cmd); +++ struct sk_buff *skb; +++ int ret; +++ +++ ret = ath10k_wmi_peer_assoc_check_arg(arg); +++ if (ret) +++ return ERR_PTR(ret); +++ +++ skb = ath10k_wmi_alloc_skb(ar, len); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, +++ "wmi peer assoc vdev %d addr %pM (%s)\n", +++ arg->vdev_id, arg->addr, +++ arg->peer_reassoc ? "reassociate" : "new"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_10_2_op_gen_peer_assoc(struct ath10k *ar, +++ const struct wmi_peer_assoc_complete_arg *arg) +++{ +++ size_t len = sizeof(struct wmi_10_2_peer_assoc_complete_cmd); +++ struct sk_buff *skb; +++ int ret; +++ +++ ret = ath10k_wmi_peer_assoc_check_arg(arg); +++ if (ret) +++ return ERR_PTR(ret); +++ +++ skb = ath10k_wmi_alloc_skb(ar, len); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ ath10k_wmi_peer_assoc_fill_10_2(ar, skb->data, arg); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "wmi peer assoc vdev %d addr %pM (%s)\n", ++ arg->vdev_id, arg->addr, ++ arg->peer_reassoc ? "reassociate" : "new"); ++- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_10_2_op_gen_pdev_get_temperature(struct ath10k *ar) +++{ +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, 0); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev get temperature\n"); +++ return skb; ++ } ++ ++ /* This function assumes the beacon is already DMA mapped */ ++-int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif) +++static struct sk_buff * +++ath10k_wmi_op_gen_beacon_dma(struct ath10k *ar, u32 vdev_id, const void *bcn, +++ size_t bcn_len, u32 bcn_paddr, bool dtim_zero, +++ bool deliver_cab) ++ { ++ struct wmi_bcn_tx_ref_cmd *cmd; ++ struct sk_buff *skb; ++- struct sk_buff *beacon = arvif->beacon; ++- struct ath10k *ar = arvif->ar; ++ struct ieee80211_hdr *hdr; ++- int ret; ++ u16 fc; ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++- hdr = (struct ieee80211_hdr *)beacon->data; +++ hdr = (struct ieee80211_hdr *)bcn; ++ fc = le16_to_cpu(hdr->frame_control); ++ ++ cmd = (struct wmi_bcn_tx_ref_cmd *)skb->data; ++- cmd->vdev_id = __cpu_to_le32(arvif->vdev_id); ++- cmd->data_len = __cpu_to_le32(beacon->len); ++- cmd->data_ptr = __cpu_to_le32(ATH10K_SKB_CB(beacon)->paddr); +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ cmd->data_len = __cpu_to_le32(bcn_len); +++ cmd->data_ptr = __cpu_to_le32(bcn_paddr); ++ cmd->msdu_id = 0; ++ cmd->frame_control = __cpu_to_le32(fc); ++ cmd->flags = 0; +++ cmd->antenna_mask = __cpu_to_le32(WMI_BCN_TX_REF_DEF_ANTENNA); ++ ++- if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero) +++ if (dtim_zero) ++ cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO); ++ ++- if (ATH10K_SKB_CB(beacon)->bcn.deliver_cab) +++ if (deliver_cab) ++ cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DELIVER_CAB); ++ ++- ret = ath10k_wmi_cmd_send_nowait(ar, skb, ++- ar->wmi.cmd->pdev_send_bcn_cmdid); ++- ++- if (ret) ++- dev_kfree_skb(skb); ++- ++- return ret; +++ return skb; ++ } ++ ++-static void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params, ++- const struct wmi_wmm_params_arg *arg) +++void ath10k_wmi_set_wmm_param(struct wmi_wmm_params *params, +++ const struct wmi_wmm_params_arg *arg) ++ { ++ params->cwmin = __cpu_to_le32(arg->cwmin); ++ params->cwmax = __cpu_to_le32(arg->cwmax); ++@@ -3549,76 +4952,81 @@ static void ath10k_wmi_pdev_set_wmm_para ++ params->no_ack = __cpu_to_le32(arg->no_ack); ++ } ++ ++-int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, ++- const struct wmi_pdev_set_wmm_params_arg *arg) +++static struct sk_buff * +++ath10k_wmi_op_gen_pdev_set_wmm(struct ath10k *ar, +++ const struct wmi_wmm_params_all_arg *arg) ++ { ++ struct wmi_pdev_set_wmm_params *cmd; ++ struct sk_buff *skb; ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_pdev_set_wmm_params *)skb->data; ++- ath10k_wmi_pdev_set_wmm_param(&cmd->ac_be, &arg->ac_be); ++- ath10k_wmi_pdev_set_wmm_param(&cmd->ac_bk, &arg->ac_bk); ++- ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vi, &arg->ac_vi); ++- ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vo, &arg->ac_vo); +++ ath10k_wmi_set_wmm_param(&cmd->ac_be, &arg->ac_be); +++ ath10k_wmi_set_wmm_param(&cmd->ac_bk, &arg->ac_bk); +++ ath10k_wmi_set_wmm_param(&cmd->ac_vi, &arg->ac_vi); +++ ath10k_wmi_set_wmm_param(&cmd->ac_vo, &arg->ac_vo); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, "wmi pdev set wmm params\n"); ++- return ath10k_wmi_cmd_send(ar, skb, ++- ar->wmi.cmd->pdev_set_wmm_params_cmdid); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set wmm params\n"); +++ return skb; ++ } ++ ++-int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id) +++static struct sk_buff * +++ath10k_wmi_op_gen_request_stats(struct ath10k *ar, u32 stats_mask) ++ { ++ struct wmi_request_stats_cmd *cmd; ++ struct sk_buff *skb; ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_request_stats_cmd *)skb->data; ++- cmd->stats_id = __cpu_to_le32(stats_id); +++ cmd->stats_id = __cpu_to_le32(stats_mask); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id); ++- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_stats_cmdid); +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi request stats 0x%08x\n", +++ stats_mask); +++ return skb; ++ } ++ ++-int ath10k_wmi_force_fw_hang(struct ath10k *ar, ++- enum wmi_force_fw_hang_type type, u32 delay_ms) +++static struct sk_buff * +++ath10k_wmi_op_gen_force_fw_hang(struct ath10k *ar, +++ enum wmi_force_fw_hang_type type, u32 delay_ms) ++ { ++ struct wmi_force_fw_hang_cmd *cmd; ++ struct sk_buff *skb; ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_force_fw_hang_cmd *)skb->data; ++ cmd->type = __cpu_to_le32(type); ++ cmd->delay_ms = __cpu_to_le32(delay_ms); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, "wmi force fw hang %d delay %d\n", +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi force fw hang %d delay %d\n", ++ type, delay_ms); ++- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid); +++ return skb; ++ } ++ ++-int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable) +++static struct sk_buff * +++ath10k_wmi_op_gen_dbglog_cfg(struct ath10k *ar, u32 module_enable, +++ u32 log_level) ++ { ++ struct wmi_dbglog_cfg_cmd *cmd; ++ struct sk_buff *skb; ++ u32 cfg; ++ ++- skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++- return -ENOMEM; +++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_dbglog_cfg_cmd *)skb->data; ++ ++ if (module_enable) { ++- cfg = SM(ATH10K_DBGLOG_LEVEL_VERBOSE, +++ cfg = SM(log_level, ++ ATH10K_DBGLOG_CFG_LOG_LVL); ++ } else { ++ /* set back defaults, all modules with WARN level */ ++@@ -3632,12 +5040,474 @@ int ath10k_wmi_dbglog_cfg(struct ath10k ++ cmd->config_enable = __cpu_to_le32(cfg); ++ cmd->config_valid = __cpu_to_le32(ATH10K_DBGLOG_CFG_LOG_LVL_MASK); ++ ++- ath10k_dbg(ATH10K_DBG_WMI, +++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "wmi dbglog cfg modules %08x %08x config %08x %08x\n", ++ __le32_to_cpu(cmd->module_enable), ++ __le32_to_cpu(cmd->module_valid), ++ __le32_to_cpu(cmd->config_enable), ++ __le32_to_cpu(cmd->config_valid)); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_op_gen_pktlog_enable(struct ath10k *ar, u32 ev_bitmap) +++{ +++ struct wmi_pdev_pktlog_enable_cmd *cmd; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ ev_bitmap &= ATH10K_PKTLOG_ANY; +++ +++ cmd = (struct wmi_pdev_pktlog_enable_cmd *)skb->data; +++ cmd->ev_bitmap = __cpu_to_le32(ev_bitmap); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi enable pktlog filter 0x%08x\n", +++ ev_bitmap); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_op_gen_pktlog_disable(struct ath10k *ar) +++{ +++ struct sk_buff *skb; ++ ++- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->dbglog_cfg_cmdid); +++ skb = ath10k_wmi_alloc_skb(ar, 0); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi disable pktlog\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_op_gen_pdev_set_quiet_mode(struct ath10k *ar, u32 period, +++ u32 duration, u32 next_offset, +++ u32 enabled) +++{ +++ struct wmi_pdev_set_quiet_cmd *cmd; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ cmd = (struct wmi_pdev_set_quiet_cmd *)skb->data; +++ cmd->period = __cpu_to_le32(period); +++ cmd->duration = __cpu_to_le32(duration); +++ cmd->next_start = __cpu_to_le32(next_offset); +++ cmd->enabled = __cpu_to_le32(enabled); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, +++ "wmi quiet param: period %u duration %u enabled %d\n", +++ period, duration, enabled); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_op_gen_addba_clear_resp(struct ath10k *ar, u32 vdev_id, +++ const u8 *mac) +++{ +++ struct wmi_addba_clear_resp_cmd *cmd; +++ struct sk_buff *skb; +++ +++ if (!mac) +++ return ERR_PTR(-EINVAL); +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ cmd = (struct wmi_addba_clear_resp_cmd *)skb->data; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ ether_addr_copy(cmd->peer_macaddr.addr, mac); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, +++ "wmi addba clear resp vdev_id 0x%X mac_addr %pM\n", +++ vdev_id, mac); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_op_gen_addba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac, +++ u32 tid, u32 buf_size) +++{ +++ struct wmi_addba_send_cmd *cmd; +++ struct sk_buff *skb; +++ +++ if (!mac) +++ return ERR_PTR(-EINVAL); +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ cmd = (struct wmi_addba_send_cmd *)skb->data; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ ether_addr_copy(cmd->peer_macaddr.addr, mac); +++ cmd->tid = __cpu_to_le32(tid); +++ cmd->buffersize = __cpu_to_le32(buf_size); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, +++ "wmi addba send vdev_id 0x%X mac_addr %pM tid %u bufsize %u\n", +++ vdev_id, mac, tid, buf_size); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_op_gen_addba_set_resp(struct ath10k *ar, u32 vdev_id, const u8 *mac, +++ u32 tid, u32 status) +++{ +++ struct wmi_addba_setresponse_cmd *cmd; +++ struct sk_buff *skb; +++ +++ if (!mac) +++ return ERR_PTR(-EINVAL); +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ cmd = (struct wmi_addba_setresponse_cmd *)skb->data; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ ether_addr_copy(cmd->peer_macaddr.addr, mac); +++ cmd->tid = __cpu_to_le32(tid); +++ cmd->statuscode = __cpu_to_le32(status); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, +++ "wmi addba set resp vdev_id 0x%X mac_addr %pM tid %u status %u\n", +++ vdev_id, mac, tid, status); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_op_gen_delba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac, +++ u32 tid, u32 initiator, u32 reason) +++{ +++ struct wmi_delba_send_cmd *cmd; +++ struct sk_buff *skb; +++ +++ if (!mac) +++ return ERR_PTR(-EINVAL); +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ cmd = (struct wmi_delba_send_cmd *)skb->data; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ ether_addr_copy(cmd->peer_macaddr.addr, mac); +++ cmd->tid = __cpu_to_le32(tid); +++ cmd->initiator = __cpu_to_le32(initiator); +++ cmd->reasoncode = __cpu_to_le32(reason); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, +++ "wmi delba send vdev_id 0x%X mac_addr %pM tid %u initiator %u reason %u\n", +++ vdev_id, mac, tid, initiator, reason); +++ return skb; +++} +++ +++static const struct wmi_ops wmi_ops = { +++ .rx = ath10k_wmi_op_rx, +++ .map_svc = wmi_main_svc_map, +++ +++ .pull_scan = ath10k_wmi_op_pull_scan_ev, +++ .pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev, +++ .pull_ch_info = ath10k_wmi_op_pull_ch_info_ev, +++ .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, +++ .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, +++ .pull_swba = ath10k_wmi_op_pull_swba_ev, +++ .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev, +++ .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev, +++ .pull_rdy = ath10k_wmi_op_pull_rdy_ev, +++ .pull_fw_stats = ath10k_wmi_main_op_pull_fw_stats, +++ +++ .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend, +++ .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume, +++ .gen_pdev_set_rd = ath10k_wmi_op_gen_pdev_set_rd, +++ .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param, +++ .gen_init = ath10k_wmi_op_gen_init, +++ .gen_start_scan = ath10k_wmi_op_gen_start_scan, +++ .gen_stop_scan = ath10k_wmi_op_gen_stop_scan, +++ .gen_vdev_create = ath10k_wmi_op_gen_vdev_create, +++ .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete, +++ .gen_vdev_start = ath10k_wmi_op_gen_vdev_start, +++ .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop, +++ .gen_vdev_up = ath10k_wmi_op_gen_vdev_up, +++ .gen_vdev_down = ath10k_wmi_op_gen_vdev_down, +++ .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param, +++ .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key, +++ .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf, +++ .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable, +++ /* .gen_vdev_wmm_conf not implemented */ +++ .gen_peer_create = ath10k_wmi_op_gen_peer_create, +++ .gen_peer_delete = ath10k_wmi_op_gen_peer_delete, +++ .gen_peer_flush = ath10k_wmi_op_gen_peer_flush, +++ .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param, +++ .gen_peer_assoc = ath10k_wmi_op_gen_peer_assoc, +++ .gen_set_psmode = ath10k_wmi_op_gen_set_psmode, +++ .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps, +++ .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps, +++ .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list, +++ .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma, +++ .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm, +++ .gen_request_stats = ath10k_wmi_op_gen_request_stats, +++ .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang, +++ .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx, +++ .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg, +++ .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, +++ .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, +++ .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, +++ /* .gen_pdev_get_temperature not implemented */ +++ .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, +++ .gen_addba_send = ath10k_wmi_op_gen_addba_send, +++ .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, +++ .gen_delba_send = ath10k_wmi_op_gen_delba_send, +++ /* .gen_bcn_tmpl not implemented */ +++ /* .gen_prb_tmpl not implemented */ +++ /* .gen_p2p_go_bcn_ie not implemented */ +++}; +++ +++static const struct wmi_ops wmi_10_1_ops = { +++ .rx = ath10k_wmi_10_1_op_rx, +++ .map_svc = wmi_10x_svc_map, +++ .pull_svc_rdy = ath10k_wmi_10x_op_pull_svc_rdy_ev, +++ .pull_fw_stats = ath10k_wmi_10x_op_pull_fw_stats, +++ .gen_init = ath10k_wmi_10_1_op_gen_init, +++ .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd, +++ .gen_start_scan = ath10k_wmi_10x_op_gen_start_scan, +++ .gen_peer_assoc = ath10k_wmi_10_1_op_gen_peer_assoc, +++ /* .gen_pdev_get_temperature not implemented */ +++ +++ /* shared with main branch */ +++ .pull_scan = ath10k_wmi_op_pull_scan_ev, +++ .pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev, +++ .pull_ch_info = ath10k_wmi_op_pull_ch_info_ev, +++ .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, +++ .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, +++ .pull_swba = ath10k_wmi_op_pull_swba_ev, +++ .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev, +++ .pull_rdy = ath10k_wmi_op_pull_rdy_ev, +++ +++ .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend, +++ .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume, +++ .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param, +++ .gen_stop_scan = ath10k_wmi_op_gen_stop_scan, +++ .gen_vdev_create = ath10k_wmi_op_gen_vdev_create, +++ .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete, +++ .gen_vdev_start = ath10k_wmi_op_gen_vdev_start, +++ .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop, +++ .gen_vdev_up = ath10k_wmi_op_gen_vdev_up, +++ .gen_vdev_down = ath10k_wmi_op_gen_vdev_down, +++ .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param, +++ .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key, +++ .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf, +++ .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable, +++ /* .gen_vdev_wmm_conf not implemented */ +++ .gen_peer_create = ath10k_wmi_op_gen_peer_create, +++ .gen_peer_delete = ath10k_wmi_op_gen_peer_delete, +++ .gen_peer_flush = ath10k_wmi_op_gen_peer_flush, +++ .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param, +++ .gen_set_psmode = ath10k_wmi_op_gen_set_psmode, +++ .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps, +++ .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps, +++ .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list, +++ .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma, +++ .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm, +++ .gen_request_stats = ath10k_wmi_op_gen_request_stats, +++ .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang, +++ .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx, +++ .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg, +++ .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, +++ .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, +++ .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, +++ .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, +++ .gen_addba_send = ath10k_wmi_op_gen_addba_send, +++ .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, +++ .gen_delba_send = ath10k_wmi_op_gen_delba_send, +++ /* .gen_bcn_tmpl not implemented */ +++ /* .gen_prb_tmpl not implemented */ +++ /* .gen_p2p_go_bcn_ie not implemented */ +++}; +++ +++static const struct wmi_ops wmi_10_2_ops = { +++ .rx = ath10k_wmi_10_2_op_rx, +++ .pull_fw_stats = ath10k_wmi_10_2_op_pull_fw_stats, +++ .gen_init = ath10k_wmi_10_2_op_gen_init, +++ .gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc, +++ /* .gen_pdev_get_temperature not implemented */ +++ +++ /* shared with 10.1 */ +++ .map_svc = wmi_10x_svc_map, +++ .pull_svc_rdy = ath10k_wmi_10x_op_pull_svc_rdy_ev, +++ .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd, +++ .gen_start_scan = ath10k_wmi_10x_op_gen_start_scan, +++ +++ .pull_scan = ath10k_wmi_op_pull_scan_ev, +++ .pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev, +++ .pull_ch_info = ath10k_wmi_op_pull_ch_info_ev, +++ .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, +++ .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, +++ .pull_swba = ath10k_wmi_op_pull_swba_ev, +++ .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev, +++ .pull_rdy = ath10k_wmi_op_pull_rdy_ev, +++ +++ .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend, +++ .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume, +++ .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param, +++ .gen_stop_scan = ath10k_wmi_op_gen_stop_scan, +++ .gen_vdev_create = ath10k_wmi_op_gen_vdev_create, +++ .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete, +++ .gen_vdev_start = ath10k_wmi_op_gen_vdev_start, +++ .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop, +++ .gen_vdev_up = ath10k_wmi_op_gen_vdev_up, +++ .gen_vdev_down = ath10k_wmi_op_gen_vdev_down, +++ .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param, +++ .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key, +++ .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf, +++ .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable, +++ /* .gen_vdev_wmm_conf not implemented */ +++ .gen_peer_create = ath10k_wmi_op_gen_peer_create, +++ .gen_peer_delete = ath10k_wmi_op_gen_peer_delete, +++ .gen_peer_flush = ath10k_wmi_op_gen_peer_flush, +++ .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param, +++ .gen_set_psmode = ath10k_wmi_op_gen_set_psmode, +++ .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps, +++ .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps, +++ .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list, +++ .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma, +++ .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm, +++ .gen_request_stats = ath10k_wmi_op_gen_request_stats, +++ .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang, +++ .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx, +++ .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg, +++ .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, +++ .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, +++ .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, +++ .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, +++ .gen_addba_send = ath10k_wmi_op_gen_addba_send, +++ .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, +++ .gen_delba_send = ath10k_wmi_op_gen_delba_send, +++}; +++ +++static const struct wmi_ops wmi_10_2_4_ops = { +++ .rx = ath10k_wmi_10_2_op_rx, +++ .pull_fw_stats = ath10k_wmi_10_2_4_op_pull_fw_stats, +++ .gen_init = ath10k_wmi_10_2_op_gen_init, +++ .gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc, +++ .gen_pdev_get_temperature = ath10k_wmi_10_2_op_gen_pdev_get_temperature, +++ +++ /* shared with 10.1 */ +++ .map_svc = wmi_10x_svc_map, +++ .pull_svc_rdy = ath10k_wmi_10x_op_pull_svc_rdy_ev, +++ .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd, +++ .gen_start_scan = ath10k_wmi_10x_op_gen_start_scan, +++ +++ .pull_scan = ath10k_wmi_op_pull_scan_ev, +++ .pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev, +++ .pull_ch_info = ath10k_wmi_op_pull_ch_info_ev, +++ .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, +++ .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, +++ .pull_swba = ath10k_wmi_op_pull_swba_ev, +++ .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev, +++ .pull_rdy = ath10k_wmi_op_pull_rdy_ev, +++ +++ .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend, +++ .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume, +++ .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param, +++ .gen_stop_scan = ath10k_wmi_op_gen_stop_scan, +++ .gen_vdev_create = ath10k_wmi_op_gen_vdev_create, +++ .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete, +++ .gen_vdev_start = ath10k_wmi_op_gen_vdev_start, +++ .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop, +++ .gen_vdev_up = ath10k_wmi_op_gen_vdev_up, +++ .gen_vdev_down = ath10k_wmi_op_gen_vdev_down, +++ .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param, +++ .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key, +++ .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf, +++ .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable, +++ .gen_peer_create = ath10k_wmi_op_gen_peer_create, +++ .gen_peer_delete = ath10k_wmi_op_gen_peer_delete, +++ .gen_peer_flush = ath10k_wmi_op_gen_peer_flush, +++ .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param, +++ .gen_set_psmode = ath10k_wmi_op_gen_set_psmode, +++ .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps, +++ .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps, +++ .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list, +++ .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma, +++ .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm, +++ .gen_request_stats = ath10k_wmi_op_gen_request_stats, +++ .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang, +++ .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx, +++ .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg, +++ .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, +++ .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, +++ .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, +++ .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, +++ .gen_addba_send = ath10k_wmi_op_gen_addba_send, +++ .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, +++ .gen_delba_send = ath10k_wmi_op_gen_delba_send, +++ /* .gen_bcn_tmpl not implemented */ +++ /* .gen_prb_tmpl not implemented */ +++ /* .gen_p2p_go_bcn_ie not implemented */ +++}; +++ +++int ath10k_wmi_attach(struct ath10k *ar) +++{ +++ switch (ar->wmi.op_version) { +++ case ATH10K_FW_WMI_OP_VERSION_10_2_4: +++ ar->wmi.cmd = &wmi_10_2_4_cmd_map; +++ ar->wmi.ops = &wmi_10_2_4_ops; +++ ar->wmi.vdev_param = &wmi_10_2_4_vdev_param_map; +++ ar->wmi.pdev_param = &wmi_10_2_4_pdev_param_map; +++ break; +++ case ATH10K_FW_WMI_OP_VERSION_10_2: +++ ar->wmi.cmd = &wmi_10_2_cmd_map; +++ ar->wmi.ops = &wmi_10_2_ops; +++ ar->wmi.vdev_param = &wmi_10x_vdev_param_map; +++ ar->wmi.pdev_param = &wmi_10x_pdev_param_map; +++ break; +++ case ATH10K_FW_WMI_OP_VERSION_10_1: +++ ar->wmi.cmd = &wmi_10x_cmd_map; +++ ar->wmi.ops = &wmi_10_1_ops; +++ ar->wmi.vdev_param = &wmi_10x_vdev_param_map; +++ ar->wmi.pdev_param = &wmi_10x_pdev_param_map; +++ break; +++ case ATH10K_FW_WMI_OP_VERSION_MAIN: +++ ar->wmi.cmd = &wmi_cmd_map; +++ ar->wmi.ops = &wmi_ops; +++ ar->wmi.vdev_param = &wmi_vdev_param_map; +++ ar->wmi.pdev_param = &wmi_pdev_param_map; +++ break; +++ case ATH10K_FW_WMI_OP_VERSION_TLV: +++ ath10k_wmi_tlv_attach(ar); +++ break; +++ case ATH10K_FW_WMI_OP_VERSION_UNSET: +++ case ATH10K_FW_WMI_OP_VERSION_MAX: +++ ath10k_err(ar, "unsupported WMI op version: %d\n", +++ ar->wmi.op_version); +++ return -EINVAL; +++ } +++ +++ init_completion(&ar->wmi.service_ready); +++ init_completion(&ar->wmi.unified_ready); +++ +++ return 0; +++} +++ +++void ath10k_wmi_detach(struct ath10k *ar) +++{ +++ int i; +++ +++ /* free the host memory chunks requested by firmware */ +++ for (i = 0; i < ar->wmi.num_mem_chunks; i++) { +++ dma_free_coherent(ar->dev, +++ ar->wmi.mem_chunks[i].len, +++ ar->wmi.mem_chunks[i].vaddr, +++ ar->wmi.mem_chunks[i].paddr); +++ } +++ +++ ar->wmi.num_mem_chunks = 0; ++ } ++--- a/drivers/net/wireless/ath/ath10k/wmi.h +++++ b/drivers/net/wireless/ath/ath10k/wmi.h ++@@ -73,119 +73,361 @@ struct wmi_cmd_hdr { ++ #define HTC_PROTOCOL_VERSION 0x0002 ++ #define WMI_PROTOCOL_VERSION 0x0002 ++ ++-enum wmi_service_id { ++- WMI_SERVICE_BEACON_OFFLOAD = 0, /* beacon offload */ ++- WMI_SERVICE_SCAN_OFFLOAD, /* scan offload */ ++- WMI_SERVICE_ROAM_OFFLOAD, /* roam offload */ ++- WMI_SERVICE_BCN_MISS_OFFLOAD, /* beacon miss offload */ ++- WMI_SERVICE_STA_PWRSAVE, /* fake sleep + basic power save */ ++- WMI_SERVICE_STA_ADVANCED_PWRSAVE, /* uapsd, pspoll, force sleep */ ++- WMI_SERVICE_AP_UAPSD, /* uapsd on AP */ ++- WMI_SERVICE_AP_DFS, /* DFS on AP */ ++- WMI_SERVICE_11AC, /* supports 11ac */ ++- WMI_SERVICE_BLOCKACK, /* Supports triggering ADDBA/DELBA from host*/ ++- WMI_SERVICE_PHYERR, /* PHY error */ ++- WMI_SERVICE_BCN_FILTER, /* Beacon filter support */ ++- WMI_SERVICE_RTT, /* RTT (round trip time) support */ ++- WMI_SERVICE_RATECTRL, /* Rate-control */ ++- WMI_SERVICE_WOW, /* WOW Support */ ++- WMI_SERVICE_RATECTRL_CACHE, /* Rate-control caching */ ++- WMI_SERVICE_IRAM_TIDS, /* TIDs in IRAM */ ++- WMI_SERVICE_ARPNS_OFFLOAD, /* ARP NS Offload support */ ++- WMI_SERVICE_NLO, /* Network list offload service */ ++- WMI_SERVICE_GTK_OFFLOAD, /* GTK offload */ ++- WMI_SERVICE_SCAN_SCH, /* Scan Scheduler Service */ ++- WMI_SERVICE_CSA_OFFLOAD, /* CSA offload service */ ++- WMI_SERVICE_CHATTER, /* Chatter service */ ++- WMI_SERVICE_COEX_FREQAVOID, /* FW report freq range to avoid */ ++- WMI_SERVICE_PACKET_POWER_SAVE, /* packet power save service */ ++- WMI_SERVICE_FORCE_FW_HANG, /* To test fw recovery mechanism */ ++- WMI_SERVICE_GPIO, /* GPIO service */ ++- WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM, /* Modulated DTIM support */ ++- WMI_STA_UAPSD_BASIC_AUTO_TRIG, /* UAPSD AC Trigger Generation */ ++- WMI_STA_UAPSD_VAR_AUTO_TRIG, /* -do- */ ++- WMI_SERVICE_STA_KEEP_ALIVE, /* STA keep alive mechanism support */ ++- WMI_SERVICE_TX_ENCAP, /* Packet type for TX encapsulation */ ++- ++- WMI_SERVICE_LAST, ++- WMI_MAX_SERVICE = 64 /* max service */ +++enum wmi_service { +++ WMI_SERVICE_BEACON_OFFLOAD = 0, +++ WMI_SERVICE_SCAN_OFFLOAD, +++ WMI_SERVICE_ROAM_OFFLOAD, +++ WMI_SERVICE_BCN_MISS_OFFLOAD, +++ WMI_SERVICE_STA_PWRSAVE, +++ WMI_SERVICE_STA_ADVANCED_PWRSAVE, +++ WMI_SERVICE_AP_UAPSD, +++ WMI_SERVICE_AP_DFS, +++ WMI_SERVICE_11AC, +++ WMI_SERVICE_BLOCKACK, +++ WMI_SERVICE_PHYERR, +++ WMI_SERVICE_BCN_FILTER, +++ WMI_SERVICE_RTT, +++ WMI_SERVICE_RATECTRL, +++ WMI_SERVICE_WOW, +++ WMI_SERVICE_RATECTRL_CACHE, +++ WMI_SERVICE_IRAM_TIDS, +++ WMI_SERVICE_ARPNS_OFFLOAD, +++ WMI_SERVICE_NLO, +++ WMI_SERVICE_GTK_OFFLOAD, +++ WMI_SERVICE_SCAN_SCH, +++ WMI_SERVICE_CSA_OFFLOAD, +++ WMI_SERVICE_CHATTER, +++ WMI_SERVICE_COEX_FREQAVOID, +++ WMI_SERVICE_PACKET_POWER_SAVE, +++ WMI_SERVICE_FORCE_FW_HANG, +++ WMI_SERVICE_GPIO, +++ WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM, +++ WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, +++ WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, +++ WMI_SERVICE_STA_KEEP_ALIVE, +++ WMI_SERVICE_TX_ENCAP, +++ WMI_SERVICE_BURST, +++ WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT, +++ WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT, +++ WMI_SERVICE_ROAM_SCAN_OFFLOAD, +++ WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, +++ WMI_SERVICE_EARLY_RX, +++ WMI_SERVICE_STA_SMPS, +++ WMI_SERVICE_FWTEST, +++ WMI_SERVICE_STA_WMMAC, +++ WMI_SERVICE_TDLS, +++ WMI_SERVICE_MCC_BCN_INTERVAL_CHANGE, +++ WMI_SERVICE_ADAPTIVE_OCS, +++ WMI_SERVICE_BA_SSN_SUPPORT, +++ WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE, +++ WMI_SERVICE_WLAN_HB, +++ WMI_SERVICE_LTE_ANT_SHARE_SUPPORT, +++ WMI_SERVICE_BATCH_SCAN, +++ WMI_SERVICE_QPOWER, +++ WMI_SERVICE_PLMREQ, +++ WMI_SERVICE_THERMAL_MGMT, +++ WMI_SERVICE_RMC, +++ WMI_SERVICE_MHF_OFFLOAD, +++ WMI_SERVICE_COEX_SAR, +++ WMI_SERVICE_BCN_TXRATE_OVERRIDE, +++ WMI_SERVICE_NAN, +++ WMI_SERVICE_L1SS_STAT, +++ WMI_SERVICE_ESTIMATE_LINKSPEED, +++ WMI_SERVICE_OBSS_SCAN, +++ WMI_SERVICE_TDLS_OFFCHAN, +++ WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, +++ WMI_SERVICE_TDLS_UAPSD_SLEEP_STA, +++ WMI_SERVICE_IBSS_PWRSAVE, +++ WMI_SERVICE_LPASS, +++ WMI_SERVICE_EXTSCAN, +++ WMI_SERVICE_D0WOW, +++ WMI_SERVICE_HSOFFLOAD, +++ WMI_SERVICE_ROAM_HO_OFFLOAD, +++ WMI_SERVICE_RX_FULL_REORDER, +++ WMI_SERVICE_DHCP_OFFLOAD, +++ WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT, +++ WMI_SERVICE_MDNS_OFFLOAD, +++ WMI_SERVICE_SAP_AUTH_OFFLOAD, +++ +++ /* keep last */ +++ WMI_SERVICE_MAX, +++}; +++ +++enum wmi_10x_service { +++ WMI_10X_SERVICE_BEACON_OFFLOAD = 0, +++ WMI_10X_SERVICE_SCAN_OFFLOAD, +++ WMI_10X_SERVICE_ROAM_OFFLOAD, +++ WMI_10X_SERVICE_BCN_MISS_OFFLOAD, +++ WMI_10X_SERVICE_STA_PWRSAVE, +++ WMI_10X_SERVICE_STA_ADVANCED_PWRSAVE, +++ WMI_10X_SERVICE_AP_UAPSD, +++ WMI_10X_SERVICE_AP_DFS, +++ WMI_10X_SERVICE_11AC, +++ WMI_10X_SERVICE_BLOCKACK, +++ WMI_10X_SERVICE_PHYERR, +++ WMI_10X_SERVICE_BCN_FILTER, +++ WMI_10X_SERVICE_RTT, +++ WMI_10X_SERVICE_RATECTRL, +++ WMI_10X_SERVICE_WOW, +++ WMI_10X_SERVICE_RATECTRL_CACHE, +++ WMI_10X_SERVICE_IRAM_TIDS, +++ WMI_10X_SERVICE_BURST, +++ +++ /* introduced in 10.2 */ +++ WMI_10X_SERVICE_SMART_ANTENNA_SW_SUPPORT, +++ WMI_10X_SERVICE_FORCE_FW_HANG, +++ WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT, +++}; +++ +++enum wmi_main_service { +++ WMI_MAIN_SERVICE_BEACON_OFFLOAD = 0, +++ WMI_MAIN_SERVICE_SCAN_OFFLOAD, +++ WMI_MAIN_SERVICE_ROAM_OFFLOAD, +++ WMI_MAIN_SERVICE_BCN_MISS_OFFLOAD, +++ WMI_MAIN_SERVICE_STA_PWRSAVE, +++ WMI_MAIN_SERVICE_STA_ADVANCED_PWRSAVE, +++ WMI_MAIN_SERVICE_AP_UAPSD, +++ WMI_MAIN_SERVICE_AP_DFS, +++ WMI_MAIN_SERVICE_11AC, +++ WMI_MAIN_SERVICE_BLOCKACK, +++ WMI_MAIN_SERVICE_PHYERR, +++ WMI_MAIN_SERVICE_BCN_FILTER, +++ WMI_MAIN_SERVICE_RTT, +++ WMI_MAIN_SERVICE_RATECTRL, +++ WMI_MAIN_SERVICE_WOW, +++ WMI_MAIN_SERVICE_RATECTRL_CACHE, +++ WMI_MAIN_SERVICE_IRAM_TIDS, +++ WMI_MAIN_SERVICE_ARPNS_OFFLOAD, +++ WMI_MAIN_SERVICE_NLO, +++ WMI_MAIN_SERVICE_GTK_OFFLOAD, +++ WMI_MAIN_SERVICE_SCAN_SCH, +++ WMI_MAIN_SERVICE_CSA_OFFLOAD, +++ WMI_MAIN_SERVICE_CHATTER, +++ WMI_MAIN_SERVICE_COEX_FREQAVOID, +++ WMI_MAIN_SERVICE_PACKET_POWER_SAVE, +++ WMI_MAIN_SERVICE_FORCE_FW_HANG, +++ WMI_MAIN_SERVICE_GPIO, +++ WMI_MAIN_SERVICE_STA_DTIM_PS_MODULATED_DTIM, +++ WMI_MAIN_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, +++ WMI_MAIN_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, +++ WMI_MAIN_SERVICE_STA_KEEP_ALIVE, +++ WMI_MAIN_SERVICE_TX_ENCAP, ++ }; ++ ++ static inline char *wmi_service_name(int service_id) ++ { +++#define SVCSTR(x) case x: return #x +++ ++ switch (service_id) { ++- case WMI_SERVICE_BEACON_OFFLOAD: ++- return "BEACON_OFFLOAD"; ++- case WMI_SERVICE_SCAN_OFFLOAD: ++- return "SCAN_OFFLOAD"; ++- case WMI_SERVICE_ROAM_OFFLOAD: ++- return "ROAM_OFFLOAD"; ++- case WMI_SERVICE_BCN_MISS_OFFLOAD: ++- return "BCN_MISS_OFFLOAD"; ++- case WMI_SERVICE_STA_PWRSAVE: ++- return "STA_PWRSAVE"; ++- case WMI_SERVICE_STA_ADVANCED_PWRSAVE: ++- return "STA_ADVANCED_PWRSAVE"; ++- case WMI_SERVICE_AP_UAPSD: ++- return "AP_UAPSD"; ++- case WMI_SERVICE_AP_DFS: ++- return "AP_DFS"; ++- case WMI_SERVICE_11AC: ++- return "11AC"; ++- case WMI_SERVICE_BLOCKACK: ++- return "BLOCKACK"; ++- case WMI_SERVICE_PHYERR: ++- return "PHYERR"; ++- case WMI_SERVICE_BCN_FILTER: ++- return "BCN_FILTER"; ++- case WMI_SERVICE_RTT: ++- return "RTT"; ++- case WMI_SERVICE_RATECTRL: ++- return "RATECTRL"; ++- case WMI_SERVICE_WOW: ++- return "WOW"; ++- case WMI_SERVICE_RATECTRL_CACHE: ++- return "RATECTRL CACHE"; ++- case WMI_SERVICE_IRAM_TIDS: ++- return "IRAM TIDS"; ++- case WMI_SERVICE_ARPNS_OFFLOAD: ++- return "ARPNS_OFFLOAD"; ++- case WMI_SERVICE_NLO: ++- return "NLO"; ++- case WMI_SERVICE_GTK_OFFLOAD: ++- return "GTK_OFFLOAD"; ++- case WMI_SERVICE_SCAN_SCH: ++- return "SCAN_SCH"; ++- case WMI_SERVICE_CSA_OFFLOAD: ++- return "CSA_OFFLOAD"; ++- case WMI_SERVICE_CHATTER: ++- return "CHATTER"; ++- case WMI_SERVICE_COEX_FREQAVOID: ++- return "COEX_FREQAVOID"; ++- case WMI_SERVICE_PACKET_POWER_SAVE: ++- return "PACKET_POWER_SAVE"; ++- case WMI_SERVICE_FORCE_FW_HANG: ++- return "FORCE FW HANG"; ++- case WMI_SERVICE_GPIO: ++- return "GPIO"; ++- case WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM: ++- return "MODULATED DTIM"; ++- case WMI_STA_UAPSD_BASIC_AUTO_TRIG: ++- return "BASIC UAPSD"; ++- case WMI_STA_UAPSD_VAR_AUTO_TRIG: ++- return "VAR UAPSD"; ++- case WMI_SERVICE_STA_KEEP_ALIVE: ++- return "STA KEEP ALIVE"; ++- case WMI_SERVICE_TX_ENCAP: ++- return "TX ENCAP"; +++ SVCSTR(WMI_SERVICE_BEACON_OFFLOAD); +++ SVCSTR(WMI_SERVICE_SCAN_OFFLOAD); +++ SVCSTR(WMI_SERVICE_ROAM_OFFLOAD); +++ SVCSTR(WMI_SERVICE_BCN_MISS_OFFLOAD); +++ SVCSTR(WMI_SERVICE_STA_PWRSAVE); +++ SVCSTR(WMI_SERVICE_STA_ADVANCED_PWRSAVE); +++ SVCSTR(WMI_SERVICE_AP_UAPSD); +++ SVCSTR(WMI_SERVICE_AP_DFS); +++ SVCSTR(WMI_SERVICE_11AC); +++ SVCSTR(WMI_SERVICE_BLOCKACK); +++ SVCSTR(WMI_SERVICE_PHYERR); +++ SVCSTR(WMI_SERVICE_BCN_FILTER); +++ SVCSTR(WMI_SERVICE_RTT); +++ SVCSTR(WMI_SERVICE_RATECTRL); +++ SVCSTR(WMI_SERVICE_WOW); +++ SVCSTR(WMI_SERVICE_RATECTRL_CACHE); +++ SVCSTR(WMI_SERVICE_IRAM_TIDS); +++ SVCSTR(WMI_SERVICE_ARPNS_OFFLOAD); +++ SVCSTR(WMI_SERVICE_NLO); +++ SVCSTR(WMI_SERVICE_GTK_OFFLOAD); +++ SVCSTR(WMI_SERVICE_SCAN_SCH); +++ SVCSTR(WMI_SERVICE_CSA_OFFLOAD); +++ SVCSTR(WMI_SERVICE_CHATTER); +++ SVCSTR(WMI_SERVICE_COEX_FREQAVOID); +++ SVCSTR(WMI_SERVICE_PACKET_POWER_SAVE); +++ SVCSTR(WMI_SERVICE_FORCE_FW_HANG); +++ SVCSTR(WMI_SERVICE_GPIO); +++ SVCSTR(WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM); +++ SVCSTR(WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG); +++ SVCSTR(WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG); +++ SVCSTR(WMI_SERVICE_STA_KEEP_ALIVE); +++ SVCSTR(WMI_SERVICE_TX_ENCAP); +++ SVCSTR(WMI_SERVICE_BURST); +++ SVCSTR(WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT); +++ SVCSTR(WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT); +++ SVCSTR(WMI_SERVICE_ROAM_SCAN_OFFLOAD); +++ SVCSTR(WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC); +++ SVCSTR(WMI_SERVICE_EARLY_RX); +++ SVCSTR(WMI_SERVICE_STA_SMPS); +++ SVCSTR(WMI_SERVICE_FWTEST); +++ SVCSTR(WMI_SERVICE_STA_WMMAC); +++ SVCSTR(WMI_SERVICE_TDLS); +++ SVCSTR(WMI_SERVICE_MCC_BCN_INTERVAL_CHANGE); +++ SVCSTR(WMI_SERVICE_ADAPTIVE_OCS); +++ SVCSTR(WMI_SERVICE_BA_SSN_SUPPORT); +++ SVCSTR(WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE); +++ SVCSTR(WMI_SERVICE_WLAN_HB); +++ SVCSTR(WMI_SERVICE_LTE_ANT_SHARE_SUPPORT); +++ SVCSTR(WMI_SERVICE_BATCH_SCAN); +++ SVCSTR(WMI_SERVICE_QPOWER); +++ SVCSTR(WMI_SERVICE_PLMREQ); +++ SVCSTR(WMI_SERVICE_THERMAL_MGMT); +++ SVCSTR(WMI_SERVICE_RMC); +++ SVCSTR(WMI_SERVICE_MHF_OFFLOAD); +++ SVCSTR(WMI_SERVICE_COEX_SAR); +++ SVCSTR(WMI_SERVICE_BCN_TXRATE_OVERRIDE); +++ SVCSTR(WMI_SERVICE_NAN); +++ SVCSTR(WMI_SERVICE_L1SS_STAT); +++ SVCSTR(WMI_SERVICE_ESTIMATE_LINKSPEED); +++ SVCSTR(WMI_SERVICE_OBSS_SCAN); +++ SVCSTR(WMI_SERVICE_TDLS_OFFCHAN); +++ SVCSTR(WMI_SERVICE_TDLS_UAPSD_BUFFER_STA); +++ SVCSTR(WMI_SERVICE_TDLS_UAPSD_SLEEP_STA); +++ SVCSTR(WMI_SERVICE_IBSS_PWRSAVE); +++ SVCSTR(WMI_SERVICE_LPASS); +++ SVCSTR(WMI_SERVICE_EXTSCAN); +++ SVCSTR(WMI_SERVICE_D0WOW); +++ SVCSTR(WMI_SERVICE_HSOFFLOAD); +++ SVCSTR(WMI_SERVICE_ROAM_HO_OFFLOAD); +++ SVCSTR(WMI_SERVICE_RX_FULL_REORDER); +++ SVCSTR(WMI_SERVICE_DHCP_OFFLOAD); +++ SVCSTR(WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT); +++ SVCSTR(WMI_SERVICE_MDNS_OFFLOAD); +++ SVCSTR(WMI_SERVICE_SAP_AUTH_OFFLOAD); ++ default: ++- return "UNKNOWN SERVICE\n"; +++ return NULL; ++ } +++ +++#undef SVCSTR ++ } ++ +++#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \ +++ ((svc_id) < (len) && \ +++ __le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \ +++ BIT((svc_id)%(sizeof(u32)))) +++ +++#define SVCMAP(x, y, len) \ +++ do { \ +++ if (WMI_SERVICE_IS_ENABLED((in), (x), (len))) \ +++ __set_bit(y, out); \ +++ } while (0) +++ +++static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out, +++ size_t len) +++{ +++ SVCMAP(WMI_10X_SERVICE_BEACON_OFFLOAD, +++ WMI_SERVICE_BEACON_OFFLOAD, len); +++ SVCMAP(WMI_10X_SERVICE_SCAN_OFFLOAD, +++ WMI_SERVICE_SCAN_OFFLOAD, len); +++ SVCMAP(WMI_10X_SERVICE_ROAM_OFFLOAD, +++ WMI_SERVICE_ROAM_OFFLOAD, len); +++ SVCMAP(WMI_10X_SERVICE_BCN_MISS_OFFLOAD, +++ WMI_SERVICE_BCN_MISS_OFFLOAD, len); +++ SVCMAP(WMI_10X_SERVICE_STA_PWRSAVE, +++ WMI_SERVICE_STA_PWRSAVE, len); +++ SVCMAP(WMI_10X_SERVICE_STA_ADVANCED_PWRSAVE, +++ WMI_SERVICE_STA_ADVANCED_PWRSAVE, len); +++ SVCMAP(WMI_10X_SERVICE_AP_UAPSD, +++ WMI_SERVICE_AP_UAPSD, len); +++ SVCMAP(WMI_10X_SERVICE_AP_DFS, +++ WMI_SERVICE_AP_DFS, len); +++ SVCMAP(WMI_10X_SERVICE_11AC, +++ WMI_SERVICE_11AC, len); +++ SVCMAP(WMI_10X_SERVICE_BLOCKACK, +++ WMI_SERVICE_BLOCKACK, len); +++ SVCMAP(WMI_10X_SERVICE_PHYERR, +++ WMI_SERVICE_PHYERR, len); +++ SVCMAP(WMI_10X_SERVICE_BCN_FILTER, +++ WMI_SERVICE_BCN_FILTER, len); +++ SVCMAP(WMI_10X_SERVICE_RTT, +++ WMI_SERVICE_RTT, len); +++ SVCMAP(WMI_10X_SERVICE_RATECTRL, +++ WMI_SERVICE_RATECTRL, len); +++ SVCMAP(WMI_10X_SERVICE_WOW, +++ WMI_SERVICE_WOW, len); +++ SVCMAP(WMI_10X_SERVICE_RATECTRL_CACHE, +++ WMI_SERVICE_RATECTRL_CACHE, len); +++ SVCMAP(WMI_10X_SERVICE_IRAM_TIDS, +++ WMI_SERVICE_IRAM_TIDS, len); +++ SVCMAP(WMI_10X_SERVICE_BURST, +++ WMI_SERVICE_BURST, len); +++ SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_SW_SUPPORT, +++ WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT, len); +++ SVCMAP(WMI_10X_SERVICE_FORCE_FW_HANG, +++ WMI_SERVICE_FORCE_FW_HANG, len); +++ SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT, +++ WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT, len); +++} +++ +++static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out, +++ size_t len) +++{ +++ SVCMAP(WMI_MAIN_SERVICE_BEACON_OFFLOAD, +++ WMI_SERVICE_BEACON_OFFLOAD, len); +++ SVCMAP(WMI_MAIN_SERVICE_SCAN_OFFLOAD, +++ WMI_SERVICE_SCAN_OFFLOAD, len); +++ SVCMAP(WMI_MAIN_SERVICE_ROAM_OFFLOAD, +++ WMI_SERVICE_ROAM_OFFLOAD, len); +++ SVCMAP(WMI_MAIN_SERVICE_BCN_MISS_OFFLOAD, +++ WMI_SERVICE_BCN_MISS_OFFLOAD, len); +++ SVCMAP(WMI_MAIN_SERVICE_STA_PWRSAVE, +++ WMI_SERVICE_STA_PWRSAVE, len); +++ SVCMAP(WMI_MAIN_SERVICE_STA_ADVANCED_PWRSAVE, +++ WMI_SERVICE_STA_ADVANCED_PWRSAVE, len); +++ SVCMAP(WMI_MAIN_SERVICE_AP_UAPSD, +++ WMI_SERVICE_AP_UAPSD, len); +++ SVCMAP(WMI_MAIN_SERVICE_AP_DFS, +++ WMI_SERVICE_AP_DFS, len); +++ SVCMAP(WMI_MAIN_SERVICE_11AC, +++ WMI_SERVICE_11AC, len); +++ SVCMAP(WMI_MAIN_SERVICE_BLOCKACK, +++ WMI_SERVICE_BLOCKACK, len); +++ SVCMAP(WMI_MAIN_SERVICE_PHYERR, +++ WMI_SERVICE_PHYERR, len); +++ SVCMAP(WMI_MAIN_SERVICE_BCN_FILTER, +++ WMI_SERVICE_BCN_FILTER, len); +++ SVCMAP(WMI_MAIN_SERVICE_RTT, +++ WMI_SERVICE_RTT, len); +++ SVCMAP(WMI_MAIN_SERVICE_RATECTRL, +++ WMI_SERVICE_RATECTRL, len); +++ SVCMAP(WMI_MAIN_SERVICE_WOW, +++ WMI_SERVICE_WOW, len); +++ SVCMAP(WMI_MAIN_SERVICE_RATECTRL_CACHE, +++ WMI_SERVICE_RATECTRL_CACHE, len); +++ SVCMAP(WMI_MAIN_SERVICE_IRAM_TIDS, +++ WMI_SERVICE_IRAM_TIDS, len); +++ SVCMAP(WMI_MAIN_SERVICE_ARPNS_OFFLOAD, +++ WMI_SERVICE_ARPNS_OFFLOAD, len); +++ SVCMAP(WMI_MAIN_SERVICE_NLO, +++ WMI_SERVICE_NLO, len); +++ SVCMAP(WMI_MAIN_SERVICE_GTK_OFFLOAD, +++ WMI_SERVICE_GTK_OFFLOAD, len); +++ SVCMAP(WMI_MAIN_SERVICE_SCAN_SCH, +++ WMI_SERVICE_SCAN_SCH, len); +++ SVCMAP(WMI_MAIN_SERVICE_CSA_OFFLOAD, +++ WMI_SERVICE_CSA_OFFLOAD, len); +++ SVCMAP(WMI_MAIN_SERVICE_CHATTER, +++ WMI_SERVICE_CHATTER, len); +++ SVCMAP(WMI_MAIN_SERVICE_COEX_FREQAVOID, +++ WMI_SERVICE_COEX_FREQAVOID, len); +++ SVCMAP(WMI_MAIN_SERVICE_PACKET_POWER_SAVE, +++ WMI_SERVICE_PACKET_POWER_SAVE, len); +++ SVCMAP(WMI_MAIN_SERVICE_FORCE_FW_HANG, +++ WMI_SERVICE_FORCE_FW_HANG, len); +++ SVCMAP(WMI_MAIN_SERVICE_GPIO, +++ WMI_SERVICE_GPIO, len); +++ SVCMAP(WMI_MAIN_SERVICE_STA_DTIM_PS_MODULATED_DTIM, +++ WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM, len); +++ SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, +++ WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, len); +++ SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, +++ WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, len); +++ SVCMAP(WMI_MAIN_SERVICE_STA_KEEP_ALIVE, +++ WMI_SERVICE_STA_KEEP_ALIVE, len); +++ SVCMAP(WMI_MAIN_SERVICE_TX_ENCAP, +++ WMI_SERVICE_TX_ENCAP, len); +++} ++ ++-#define WMI_SERVICE_BM_SIZE \ ++- ((WMI_MAX_SERVICE + sizeof(u32) - 1)/sizeof(u32)) +++#undef SVCMAP ++ ++ /* 2 word representation of MAC addr */ ++ struct wmi_mac_addr { ++@@ -308,6 +550,8 @@ struct wmi_cmd_map { ++ u32 force_fw_hang_cmdid; ++ u32 gpio_config_cmdid; ++ u32 gpio_output_cmdid; +++ u32 pdev_get_temperature_cmdid; +++ u32 vdev_set_wmm_params_cmdid; ++ }; ++ ++ /* ++@@ -803,6 +1047,166 @@ enum wmi_10x_event_id { ++ WMI_10X_PDEV_UTF_EVENTID = WMI_10X_END_EVENTID-1, ++ }; ++ +++enum wmi_10_2_cmd_id { +++ WMI_10_2_START_CMDID = 0x9000, +++ WMI_10_2_END_CMDID = 0x9FFF, +++ WMI_10_2_INIT_CMDID, +++ WMI_10_2_START_SCAN_CMDID = WMI_10_2_START_CMDID, +++ WMI_10_2_STOP_SCAN_CMDID, +++ WMI_10_2_SCAN_CHAN_LIST_CMDID, +++ WMI_10_2_ECHO_CMDID, +++ WMI_10_2_PDEV_SET_REGDOMAIN_CMDID, +++ WMI_10_2_PDEV_SET_CHANNEL_CMDID, +++ WMI_10_2_PDEV_SET_PARAM_CMDID, +++ WMI_10_2_PDEV_PKTLOG_ENABLE_CMDID, +++ WMI_10_2_PDEV_PKTLOG_DISABLE_CMDID, +++ WMI_10_2_PDEV_SET_WMM_PARAMS_CMDID, +++ WMI_10_2_PDEV_SET_HT_CAP_IE_CMDID, +++ WMI_10_2_PDEV_SET_VHT_CAP_IE_CMDID, +++ WMI_10_2_PDEV_SET_BASE_MACADDR_CMDID, +++ WMI_10_2_PDEV_SET_QUIET_MODE_CMDID, +++ WMI_10_2_PDEV_GREEN_AP_PS_ENABLE_CMDID, +++ WMI_10_2_PDEV_GET_TPC_CONFIG_CMDID, +++ WMI_10_2_VDEV_CREATE_CMDID, +++ WMI_10_2_VDEV_DELETE_CMDID, +++ WMI_10_2_VDEV_START_REQUEST_CMDID, +++ WMI_10_2_VDEV_RESTART_REQUEST_CMDID, +++ WMI_10_2_VDEV_UP_CMDID, +++ WMI_10_2_VDEV_STOP_CMDID, +++ WMI_10_2_VDEV_DOWN_CMDID, +++ WMI_10_2_VDEV_STANDBY_RESPONSE_CMDID, +++ WMI_10_2_VDEV_RESUME_RESPONSE_CMDID, +++ WMI_10_2_VDEV_SET_PARAM_CMDID, +++ WMI_10_2_VDEV_INSTALL_KEY_CMDID, +++ WMI_10_2_VDEV_SET_DSCP_TID_MAP_CMDID, +++ WMI_10_2_PEER_CREATE_CMDID, +++ WMI_10_2_PEER_DELETE_CMDID, +++ WMI_10_2_PEER_FLUSH_TIDS_CMDID, +++ WMI_10_2_PEER_SET_PARAM_CMDID, +++ WMI_10_2_PEER_ASSOC_CMDID, +++ WMI_10_2_PEER_ADD_WDS_ENTRY_CMDID, +++ WMI_10_2_PEER_UPDATE_WDS_ENTRY_CMDID, +++ WMI_10_2_PEER_REMOVE_WDS_ENTRY_CMDID, +++ WMI_10_2_PEER_MCAST_GROUP_CMDID, +++ WMI_10_2_BCN_TX_CMDID, +++ WMI_10_2_BCN_PRB_TMPL_CMDID, +++ WMI_10_2_BCN_FILTER_RX_CMDID, +++ WMI_10_2_PRB_REQ_FILTER_RX_CMDID, +++ WMI_10_2_MGMT_TX_CMDID, +++ WMI_10_2_ADDBA_CLEAR_RESP_CMDID, +++ WMI_10_2_ADDBA_SEND_CMDID, +++ WMI_10_2_ADDBA_STATUS_CMDID, +++ WMI_10_2_DELBA_SEND_CMDID, +++ WMI_10_2_ADDBA_SET_RESP_CMDID, +++ WMI_10_2_SEND_SINGLEAMSDU_CMDID, +++ WMI_10_2_STA_POWERSAVE_MODE_CMDID, +++ WMI_10_2_STA_POWERSAVE_PARAM_CMDID, +++ WMI_10_2_STA_MIMO_PS_MODE_CMDID, +++ WMI_10_2_DBGLOG_CFG_CMDID, +++ WMI_10_2_PDEV_DFS_ENABLE_CMDID, +++ WMI_10_2_PDEV_DFS_DISABLE_CMDID, +++ WMI_10_2_PDEV_QVIT_CMDID, +++ WMI_10_2_ROAM_SCAN_MODE, +++ WMI_10_2_ROAM_SCAN_RSSI_THRESHOLD, +++ WMI_10_2_ROAM_SCAN_PERIOD, +++ WMI_10_2_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, +++ WMI_10_2_ROAM_AP_PROFILE, +++ WMI_10_2_OFL_SCAN_ADD_AP_PROFILE, +++ WMI_10_2_OFL_SCAN_REMOVE_AP_PROFILE, +++ WMI_10_2_OFL_SCAN_PERIOD, +++ WMI_10_2_P2P_DEV_SET_DEVICE_INFO, +++ WMI_10_2_P2P_DEV_SET_DISCOVERABILITY, +++ WMI_10_2_P2P_GO_SET_BEACON_IE, +++ WMI_10_2_P2P_GO_SET_PROBE_RESP_IE, +++ WMI_10_2_AP_PS_PEER_PARAM_CMDID, +++ WMI_10_2_AP_PS_PEER_UAPSD_COEX_CMDID, +++ WMI_10_2_PEER_RATE_RETRY_SCHED_CMDID, +++ WMI_10_2_WLAN_PROFILE_TRIGGER_CMDID, +++ WMI_10_2_WLAN_PROFILE_SET_HIST_INTVL_CMDID, +++ WMI_10_2_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, +++ WMI_10_2_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, +++ WMI_10_2_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, +++ WMI_10_2_PDEV_SUSPEND_CMDID, +++ WMI_10_2_PDEV_RESUME_CMDID, +++ WMI_10_2_ADD_BCN_FILTER_CMDID, +++ WMI_10_2_RMV_BCN_FILTER_CMDID, +++ WMI_10_2_WOW_ADD_WAKE_PATTERN_CMDID, +++ WMI_10_2_WOW_DEL_WAKE_PATTERN_CMDID, +++ WMI_10_2_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, +++ WMI_10_2_WOW_ENABLE_CMDID, +++ WMI_10_2_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, +++ WMI_10_2_RTT_MEASREQ_CMDID, +++ WMI_10_2_RTT_TSF_CMDID, +++ WMI_10_2_RTT_KEEPALIVE_CMDID, +++ WMI_10_2_PDEV_SEND_BCN_CMDID, +++ WMI_10_2_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID, +++ WMI_10_2_VDEV_SPECTRAL_SCAN_ENABLE_CMDID, +++ WMI_10_2_REQUEST_STATS_CMDID, +++ WMI_10_2_GPIO_CONFIG_CMDID, +++ WMI_10_2_GPIO_OUTPUT_CMDID, +++ WMI_10_2_VDEV_RATEMASK_CMDID, +++ WMI_10_2_PDEV_SMART_ANT_ENABLE_CMDID, +++ WMI_10_2_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID, +++ WMI_10_2_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID, +++ WMI_10_2_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID, +++ WMI_10_2_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID, +++ WMI_10_2_FORCE_FW_HANG_CMDID, +++ WMI_10_2_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID, +++ WMI_10_2_PDEV_SET_CTL_TABLE_CMDID, +++ WMI_10_2_PDEV_SET_MIMOGAIN_TABLE_CMDID, +++ WMI_10_2_PDEV_RATEPWR_TABLE_CMDID, +++ WMI_10_2_PDEV_RATEPWR_CHAINMSK_TABLE_CMDID, +++ WMI_10_2_PDEV_GET_INFO, +++ WMI_10_2_VDEV_GET_INFO, +++ WMI_10_2_VDEV_ATF_REQUEST_CMDID, +++ WMI_10_2_PEER_ATF_REQUEST_CMDID, +++ WMI_10_2_PDEV_GET_TEMPERATURE_CMDID, +++ WMI_10_2_PDEV_UTF_CMDID = WMI_10_2_END_CMDID - 1, +++}; +++ +++enum wmi_10_2_event_id { +++ WMI_10_2_SERVICE_READY_EVENTID = 0x8000, +++ WMI_10_2_READY_EVENTID, +++ WMI_10_2_DEBUG_MESG_EVENTID, +++ WMI_10_2_START_EVENTID = 0x9000, +++ WMI_10_2_END_EVENTID = 0x9FFF, +++ WMI_10_2_SCAN_EVENTID = WMI_10_2_START_EVENTID, +++ WMI_10_2_ECHO_EVENTID, +++ WMI_10_2_UPDATE_STATS_EVENTID, +++ WMI_10_2_INST_RSSI_STATS_EVENTID, +++ WMI_10_2_VDEV_START_RESP_EVENTID, +++ WMI_10_2_VDEV_STANDBY_REQ_EVENTID, +++ WMI_10_2_VDEV_RESUME_REQ_EVENTID, +++ WMI_10_2_VDEV_STOPPED_EVENTID, +++ WMI_10_2_PEER_STA_KICKOUT_EVENTID, +++ WMI_10_2_HOST_SWBA_EVENTID, +++ WMI_10_2_TBTTOFFSET_UPDATE_EVENTID, +++ WMI_10_2_MGMT_RX_EVENTID, +++ WMI_10_2_CHAN_INFO_EVENTID, +++ WMI_10_2_PHYERR_EVENTID, +++ WMI_10_2_ROAM_EVENTID, +++ WMI_10_2_PROFILE_MATCH, +++ WMI_10_2_DEBUG_PRINT_EVENTID, +++ WMI_10_2_PDEV_QVIT_EVENTID, +++ WMI_10_2_WLAN_PROFILE_DATA_EVENTID, +++ WMI_10_2_RTT_MEASUREMENT_REPORT_EVENTID, +++ WMI_10_2_TSF_MEASUREMENT_REPORT_EVENTID, +++ WMI_10_2_RTT_ERROR_REPORT_EVENTID, +++ WMI_10_2_RTT_KEEPALIVE_EVENTID, +++ WMI_10_2_WOW_WAKEUP_HOST_EVENTID, +++ WMI_10_2_DCS_INTERFERENCE_EVENTID, +++ WMI_10_2_PDEV_TPC_CONFIG_EVENTID, +++ WMI_10_2_GPIO_INPUT_EVENTID, +++ WMI_10_2_PEER_RATECODE_LIST_EVENTID, +++ WMI_10_2_GENERIC_BUFFER_EVENTID, +++ WMI_10_2_MCAST_BUF_RELEASE_EVENTID, +++ WMI_10_2_MCAST_LIST_AGEOUT_EVENTID, +++ WMI_10_2_WDS_PEER_EVENTID, +++ WMI_10_2_PEER_STA_PS_STATECHG_EVENTID, +++ WMI_10_2_PDEV_TEMPERATURE_EVENTID, +++ WMI_10_2_PDEV_UTF_EVENTID = WMI_10_2_END_EVENTID - 1, +++}; +++ ++ enum wmi_phy_mode { ++ MODE_11A = 0, /* 11a Mode */ ++ MODE_11G = 1, /* 11b/g Mode */ ++@@ -955,7 +1359,6 @@ enum wmi_channel_change_cause { ++ WMI_HT_CAP_RX_STBC | \ ++ WMI_HT_CAP_LDPC) ++ ++- ++ /* ++ * WMI_VHT_CAP_* these maps to ieee 802.11ac vht capability information ++ * field. The fields not defined here are not supported, or reserved. ++@@ -1076,10 +1479,6 @@ struct wlan_host_mem_req { ++ __le32 num_units; ++ } __packed; ++ ++-#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id) \ ++- ((((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \ ++- (1 << ((svc_id)%(sizeof(u32))))) != 0) ++- ++ /* ++ * The following struct holds optional payload for ++ * wmi_service_ready_event,e.g., 11ac pass some of the ++@@ -1093,7 +1492,7 @@ struct wmi_service_ready_event { ++ __le32 phy_capability; ++ /* Maximum number of frag table entries that SW will populate less 1 */ ++ __le32 max_frag_entry; ++- __le32 wmi_service_bitmap[WMI_SERVICE_BM_SIZE]; +++ __le32 wmi_service_bitmap[16]; ++ __le32 num_rf_chains; ++ /* ++ * The following field is only valid for service type ++@@ -1119,11 +1518,11 @@ struct wmi_service_ready_event { ++ * where FW can access this memory directly (or) by DMA. ++ */ ++ __le32 num_mem_reqs; ++- struct wlan_host_mem_req mem_reqs[1]; +++ struct wlan_host_mem_req mem_reqs[0]; ++ } __packed; ++ ++ /* This is the definition from 10.X firmware branch */ ++-struct wmi_service_ready_event_10x { +++struct wmi_10x_service_ready_event { ++ __le32 sw_version; ++ __le32 abi_version; ++ ++@@ -1132,7 +1531,7 @@ struct wmi_service_ready_event_10x { ++ ++ /* Maximum number of frag table entries that SW will populate less 1 */ ++ __le32 max_frag_entry; ++- __le32 wmi_service_bitmap[WMI_SERVICE_BM_SIZE]; +++ __le32 wmi_service_bitmap[16]; ++ __le32 num_rf_chains; ++ ++ /* ++@@ -1158,10 +1557,9 @@ struct wmi_service_ready_event_10x { ++ */ ++ __le32 num_mem_reqs; ++ ++- struct wlan_host_mem_req mem_reqs[1]; +++ struct wlan_host_mem_req mem_reqs[0]; ++ } __packed; ++ ++- ++ #define WMI_SERVICE_READY_TIMEOUT_HZ (5*HZ) ++ #define WMI_UNIFIED_READY_TIMEOUT_HZ (5*HZ) ++ ++@@ -1255,7 +1653,7 @@ struct wmi_resource_config { ++ */ ++ __le32 rx_decap_mode; ++ ++- /* what is the maximum scan requests than can be queued */ +++ /* what is the maximum number of scan requests that can be queued */ ++ __le32 scan_max_pending_reqs; ++ ++ /* maximum VDEV that could use BMISS offload */ ++@@ -1440,7 +1838,7 @@ struct wmi_resource_config_10x { ++ */ ++ __le32 rx_decap_mode; ++ ++- /* what is the maximum scan requests than can be queued */ +++ /* what is the maximum number of scan requests that can be queued */ ++ __le32 scan_max_pending_reqs; ++ ++ /* maximum VDEV that could use BMISS offload */ ++@@ -1551,6 +1949,21 @@ struct wmi_resource_config_10x { ++ __le32 max_frag_entries; ++ } __packed; ++ +++enum wmi_10_2_feature_mask { +++ WMI_10_2_RX_BATCH_MODE = BIT(0), +++ WMI_10_2_ATF_CONFIG = BIT(1), +++}; +++ +++struct wmi_resource_config_10_2 { +++ struct wmi_resource_config_10x common; +++ __le32 max_peer_ext_stats; +++ __le32 smart_ant_cap; /* 0-disable, 1-enable */ +++ __le32 bk_min_free; +++ __le32 be_min_free; +++ __le32 vi_min_free; +++ __le32 vo_min_free; +++ __le32 feature_mask; +++} __packed; ++ ++ #define NUM_UNITS_IS_NUM_VDEVS 0x1 ++ #define NUM_UNITS_IS_NUM_PEERS 0x2 ++@@ -1565,34 +1978,39 @@ struct host_memory_chunk { ++ __le32 size; ++ } __packed; ++ +++struct wmi_host_mem_chunks { +++ __le32 count; +++ /* some fw revisions require at least 1 chunk regardless of count */ +++ struct host_memory_chunk items[1]; +++} __packed; +++ ++ struct wmi_init_cmd { ++ struct wmi_resource_config resource_config; ++- __le32 num_host_mem_chunks; ++- ++- /* ++- * variable number of host memory chunks. ++- * This should be the last element in the structure ++- */ ++- struct host_memory_chunk host_mem_chunks[1]; +++ struct wmi_host_mem_chunks mem_chunks; ++ } __packed; ++ ++ /* _10x stucture is from 10.X FW API */ ++ struct wmi_init_cmd_10x { ++ struct wmi_resource_config_10x resource_config; ++- __le32 num_host_mem_chunks; +++ struct wmi_host_mem_chunks mem_chunks; +++} __packed; ++ ++- /* ++- * variable number of host memory chunks. ++- * This should be the last element in the structure ++- */ ++- struct host_memory_chunk host_mem_chunks[1]; +++struct wmi_init_cmd_10_2 { +++ struct wmi_resource_config_10_2 resource_config; +++ struct wmi_host_mem_chunks mem_chunks; +++} __packed; +++ +++struct wmi_chan_list_entry { +++ __le16 freq; +++ u8 phy_mode; /* valid for 10.2 only */ +++ u8 reserved; ++ } __packed; ++ ++ /* TLV for channel list */ ++ struct wmi_chan_list { ++ __le32 tag; /* WMI_CHAN_LIST_TAG */ ++ __le32 num_chan; ++- __le32 channel_list[0]; +++ struct wmi_chan_list_entry channel_list[0]; ++ } __packed; ++ ++ struct wmi_bssid_list { ++@@ -1629,6 +2047,11 @@ struct wmi_ssid_list { ++ #define WLAN_SCAN_PARAMS_MAX_BSSID 4 ++ #define WLAN_SCAN_PARAMS_MAX_IE_LEN 256 ++ +++/* Values lower than this may be refused by some firmware revisions with a scan +++ * completion with a timedout reason. +++ */ +++#define WMI_SCAN_CHAN_MIN_TIME_MSEC 40 +++ ++ /* Scan priority numbers must be sequential, starting with 0 */ ++ enum wmi_scan_priority { ++ WMI_SCAN_PRIORITY_VERY_LOW = 0, ++@@ -1639,7 +2062,7 @@ enum wmi_scan_priority { ++ WMI_SCAN_PRIORITY_COUNT /* number of priorities supported */ ++ }; ++ ++-struct wmi_start_scan_cmd { +++struct wmi_start_scan_common { ++ /* Scan ID */ ++ __le32 scan_id; ++ /* Scan requestor ID */ ++@@ -1697,97 +2120,26 @@ struct wmi_start_scan_cmd { ++ __le32 probe_delay; ++ /* Scan control flags */ ++ __le32 scan_ctrl_flags; ++- ++- /* Burst duration time in msecs */ ++- __le32 burst_duration; ++- /* ++- * TLV (tag length value ) paramerters follow the scan_cmd structure. ++- * TLV can contain channel list, bssid list, ssid list and ++- * ie. the TLV tags are defined above; ++- */ ++ } __packed; ++ ++-/* This is the definition from 10.X firmware branch */ ++-struct wmi_start_scan_cmd_10x { ++- /* Scan ID */ ++- __le32 scan_id; ++- ++- /* Scan requestor ID */ ++- __le32 scan_req_id; ++- ++- /* VDEV id(interface) that is requesting scan */ ++- __le32 vdev_id; ++- ++- /* Scan Priority, input to scan scheduler */ ++- __le32 scan_priority; ++- ++- /* Scan events subscription */ ++- __le32 notify_scan_events; ++- ++- /* dwell time in msec on active channels */ ++- __le32 dwell_time_active; ++- ++- /* dwell time in msec on passive channels */ ++- __le32 dwell_time_passive; ++- ++- /* ++- * min time in msec on the BSS channel,only valid if atleast one ++- * VDEV is active ++- */ ++- __le32 min_rest_time; ++- ++- /* ++- * max rest time in msec on the BSS channel,only valid if at least ++- * one VDEV is active ++- */ ++- /* ++- * the scanner will rest on the bss channel at least min_rest_time ++- * after min_rest_time the scanner will start checking for tx/rx ++- * activity on all VDEVs. if there is no activity the scanner will ++- * switch to off channel. if there is activity the scanner will let ++- * the radio on the bss channel until max_rest_time expires.at ++- * max_rest_time scanner will switch to off channel irrespective of ++- * activity. activity is determined by the idle_time parameter. ++- */ ++- __le32 max_rest_time; ++- ++- /* ++- * time before sending next set of probe requests. ++- * The scanner keeps repeating probe requests transmission with ++- * period specified by repeat_probe_time. ++- * The number of probe requests specified depends on the ssid_list ++- * and bssid_list ++- */ ++- __le32 repeat_probe_time; ++- ++- /* time in msec between 2 consequetive probe requests with in a set. */ ++- __le32 probe_spacing_time; ++- ++- /* ++- * data inactivity time in msec on bss channel that will be used by ++- * scanner for measuring the inactivity. +++struct wmi_start_scan_tlvs { +++ /* TLV parameters. These includes channel list, ssid list, bssid list, +++ * extra ies. ++ */ ++- __le32 idle_time; ++- ++- /* maximum time in msec allowed for scan */ ++- __le32 max_scan_time; ++- ++- /* ++- * delay in msec before sending first probe request after switching ++- * to a channel ++- */ ++- __le32 probe_delay; ++- ++- /* Scan control flags */ ++- __le32 scan_ctrl_flags; +++ u8 tlvs[0]; +++} __packed; ++ ++- /* ++- * TLV (tag length value ) paramerters follow the scan_cmd structure. ++- * TLV can contain channel list, bssid list, ssid list and ++- * ie. the TLV tags are defined above; ++- */ +++struct wmi_start_scan_cmd { +++ struct wmi_start_scan_common common; +++ __le32 burst_duration_ms; +++ struct wmi_start_scan_tlvs tlvs; ++ } __packed; ++ +++/* This is the definition from 10.X firmware branch */ +++struct wmi_10x_start_scan_cmd { +++ struct wmi_start_scan_common common; +++ struct wmi_start_scan_tlvs tlvs; +++} __packed; ++ ++ struct wmi_ssid_arg { ++ int len; ++@@ -1821,7 +2173,7 @@ struct wmi_start_scan_arg { ++ u32 n_bssids; ++ ++ u8 ie[WLAN_SCAN_PARAMS_MAX_IE_LEN]; ++- u32 channels[64]; +++ u16 channels[64]; ++ struct wmi_ssid_arg ssids[WLAN_SCAN_PARAMS_MAX_SSID]; ++ struct wmi_bssid_arg bssids[WLAN_SCAN_PARAMS_MAX_BSSID]; ++ }; ++@@ -1849,7 +2201,6 @@ struct wmi_start_scan_arg { ++ /* WMI_SCAN_CLASS_MASK must be the same value as IEEE80211_SCAN_CLASS_MASK */ ++ #define WMI_SCAN_CLASS_MASK 0xFF000000 ++ ++- ++ enum wmi_stop_scan_type { ++ WMI_SCAN_STOP_ONE = 0x00000000, /* stop by scan_id */ ++ WMI_SCAN_STOP_VDEV_ALL = 0x01000000, /* stop by vdev_id */ ++@@ -1973,100 +2324,31 @@ struct wmi_mgmt_rx_event_v2 { ++ #define PHY_ERROR_FALSE_RADAR_EXT 0x24 ++ #define PHY_ERROR_RADAR 0x05 ++ ++-struct wmi_single_phyerr_rx_hdr { ++- /* TSF timestamp */ +++struct wmi_phyerr { ++ __le32 tsf_timestamp; ++- ++- /* ++- * Current freq1, freq2 ++- * ++- * [7:0]: freq1[lo] ++- * [15:8] : freq1[hi] ++- * [23:16]: freq2[lo] ++- * [31:24]: freq2[hi] ++- */ ++ __le16 freq1; ++ __le16 freq2; ++- ++- /* ++- * Combined RSSI over all chains and channel width for this PHY error ++- * ++- * [7:0]: RSSI combined ++- * [15:8]: Channel width (MHz) ++- * [23:16]: PHY error code ++- * [24:16]: reserved (future use) ++- */ ++ u8 rssi_combined; ++ u8 chan_width_mhz; ++ u8 phy_err_code; ++ u8 rsvd0; ++- ++- /* ++- * RSSI on chain 0 through 3 ++- * ++- * This is formatted the same as the PPDU_START RX descriptor ++- * field: ++- * ++- * [7:0]: pri20 ++- * [15:8]: sec20 ++- * [23:16]: sec40 ++- * [31:24]: sec80 ++- */ ++- ++- __le32 rssi_chain0; ++- __le32 rssi_chain1; ++- __le32 rssi_chain2; ++- __le32 rssi_chain3; ++- ++- /* ++- * Last calibrated NF value for chain 0 through 3 ++- * ++- * nf_list_1: ++- * ++- * + [15:0] - chain 0 ++- * + [31:16] - chain 1 ++- * ++- * nf_list_2: ++- * ++- * + [15:0] - chain 2 ++- * + [31:16] - chain 3 ++- */ ++- __le32 nf_list_1; ++- __le32 nf_list_2; ++- ++- ++- /* Length of the frame */ +++ __le32 rssi_chains[4]; +++ __le16 nf_chains[4]; ++ __le32 buf_len; +++ u8 buf[0]; ++ } __packed; ++ ++-struct wmi_single_phyerr_rx_event { ++- /* Phy error event header */ ++- struct wmi_single_phyerr_rx_hdr hdr; ++- /* frame buffer */ ++- u8 bufp[0]; ++-} __packed; ++- ++-struct wmi_comb_phyerr_rx_hdr { ++- /* Phy error phy error count */ ++- __le32 num_phyerr_events; +++struct wmi_phyerr_event { +++ __le32 num_phyerrs; ++ __le32 tsf_l32; ++ __le32 tsf_u32; ++-} __packed; ++- ++-struct wmi_comb_phyerr_rx_event { ++- /* Phy error phy error count */ ++- struct wmi_comb_phyerr_rx_hdr hdr; ++- /* ++- * frame buffer - contains multiple payloads in the order: ++- * header - payload, header - payload... ++- * (The header is of type: wmi_single_phyerr_rx_hdr) ++- */ ++- u8 bufp[0]; +++ struct wmi_phyerr phyerrs[0]; ++ } __packed; ++ ++ #define PHYERR_TLV_SIG 0xBB ++ #define PHYERR_TLV_TAG_SEARCH_FFT_REPORT 0xFB ++ #define PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY 0xF8 +++#define PHYERR_TLV_TAG_SPECTRAL_SUMMARY_REPORT 0xF9 ++ ++ struct phyerr_radar_report { ++ __le32 reg0; /* RADAR_REPORT_REG0_* */ ++@@ -2135,7 +2417,6 @@ struct phyerr_fft_report { ++ #define SEARCH_FFT_REPORT_REG1_NUM_STR_BINS_IB_MASK 0x000000FF ++ #define SEARCH_FFT_REPORT_REG1_NUM_STR_BINS_IB_LSB 0 ++ ++- ++ struct phyerr_tlv { ++ __le16 len; ++ u8 tag; ++@@ -2166,7 +2447,6 @@ struct wmi_echo_cmd { ++ __le32 value; ++ } __packed; ++ ++- ++ struct wmi_pdev_set_regdomain_cmd { ++ __le32 reg_domain; ++ __le32 reg_domain_2G; ++@@ -2215,7 +2495,6 @@ struct wmi_pdev_set_quiet_cmd { ++ __le32 enabled; ++ } __packed; ++ ++- ++ /* ++ * 802.11g protection mode. ++ */ ++@@ -2318,14 +2597,15 @@ struct wmi_pdev_param_map { ++ u32 fast_channel_reset; ++ u32 burst_dur; ++ u32 burst_enable; +++ u32 cal_period; ++ }; ++ ++ #define WMI_PDEV_PARAM_UNSUPPORTED 0 ++ ++ enum wmi_pdev_param { ++- /* TX chian mask */ +++ /* TX chain mask */ ++ WMI_PDEV_PARAM_TX_CHAIN_MASK = 0x1, ++- /* RX chian mask */ +++ /* RX chain mask */ ++ WMI_PDEV_PARAM_RX_CHAIN_MASK, ++ /* TX power limit for 2G Radio */ ++ WMI_PDEV_PARAM_TXPOWER_LIMIT2G, ++@@ -2515,6 +2795,22 @@ enum wmi_10x_pdev_param { ++ WMI_10X_PDEV_PARAM_BURST_DUR, ++ /* Set Bursting Enable*/ ++ WMI_10X_PDEV_PARAM_BURST_ENABLE, +++ +++ /* following are available as of firmware 10.2 */ +++ WMI_10X_PDEV_PARAM_SMART_ANTENNA_DEFAULT_ANTENNA, +++ WMI_10X_PDEV_PARAM_IGMPMLD_OVERRIDE, +++ WMI_10X_PDEV_PARAM_IGMPMLD_TID, +++ WMI_10X_PDEV_PARAM_ANTENNA_GAIN, +++ WMI_10X_PDEV_PARAM_RX_DECAP_MODE, +++ WMI_10X_PDEV_PARAM_RX_FILTER, +++ WMI_10X_PDEV_PARAM_SET_MCAST_TO_UCAST_TID, +++ WMI_10X_PDEV_PARAM_PROXY_STA_MODE, +++ WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_MODE, +++ WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_BUFFER, +++ WMI_10X_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER, +++ WMI_10X_PDEV_PARAM_PEER_STA_PS_STATECHG_ENABLE, +++ WMI_10X_PDEV_PARAM_RTS_FIXED_RATE, +++ WMI_10X_PDEV_PARAM_CAL_PERIOD ++ }; ++ ++ struct wmi_pdev_set_param_cmd { ++@@ -2522,6 +2818,9 @@ struct wmi_pdev_set_param_cmd { ++ __le32 param_value; ++ } __packed; ++ +++/* valid period is 1 ~ 60000ms, unit in millisecond */ +++#define WMI_PDEV_PARAM_CAL_PERIOD_MAX 60000 +++ ++ struct wmi_pdev_get_tpc_config_cmd { ++ /* parameter */ ++ __le32 param; ++@@ -2565,11 +2864,6 @@ enum wmi_tp_scale { ++ WMI_TP_SCALE_SIZE = 5, /* max num of enum */ ++ }; ++ ++-struct wmi_set_channel_cmd { ++- /* channel (only frequency and mode info are used) */ ++- struct wmi_channel chan; ++-} __packed; ++- ++ struct wmi_pdev_chanlist_update_event { ++ /* number of channels */ ++ __le32 num_chan; ++@@ -2600,6 +2894,10 @@ struct wmi_pdev_set_channel_cmd { ++ struct wmi_channel chan; ++ } __packed; ++ +++struct wmi_pdev_pktlog_enable_cmd { +++ __le32 ev_bitmap; +++} __packed; +++ ++ /* Customize the DSCP (bit) to TID (0-7) mapping for QOS */ ++ #define WMI_DSCP_MAP_MAX (64) ++ struct wmi_pdev_set_dscp_tid_map_cmd { ++@@ -2642,14 +2940,14 @@ struct wmi_wmm_params_arg { ++ u32 no_ack; ++ }; ++ ++-struct wmi_pdev_set_wmm_params_arg { +++struct wmi_wmm_params_all_arg { ++ struct wmi_wmm_params_arg ac_be; ++ struct wmi_wmm_params_arg ac_bk; ++ struct wmi_wmm_params_arg ac_vi; ++ struct wmi_wmm_params_arg ac_vo; ++ }; ++ ++-struct wal_dbg_tx_stats { +++struct wmi_pdev_stats_tx { ++ /* Num HTT cookies queued to dispatch list */ ++ __le32 comp_queued; ++ ++@@ -2719,7 +3017,7 @@ struct wal_dbg_tx_stats { ++ __le32 txop_ovf; ++ } __packed; ++ ++-struct wal_dbg_rx_stats { +++struct wmi_pdev_stats_rx { ++ /* Cnts any change in ring routing mid-ppdu */ ++ __le32 mid_ppdu_route_change; ++ ++@@ -2753,20 +3051,18 @@ struct wal_dbg_rx_stats { ++ __le32 mpdu_errs; ++ } __packed; ++ ++-struct wal_dbg_peer_stats { +++struct wmi_pdev_stats_peer { ++ /* REMOVE THIS ONCE REAL PEER STAT COUNTERS ARE ADDED */ ++ __le32 dummy; ++ } __packed; ++ ++-struct wal_dbg_stats { ++- struct wal_dbg_tx_stats tx; ++- struct wal_dbg_rx_stats rx; ++- struct wal_dbg_peer_stats peer; ++-} __packed; ++- ++ enum wmi_stats_id { ++- WMI_REQUEST_PEER_STAT = 0x01, ++- WMI_REQUEST_AP_STAT = 0x02 +++ WMI_STAT_PEER = BIT(0), +++ WMI_STAT_AP = BIT(1), +++ WMI_STAT_PDEV = BIT(2), +++ WMI_STAT_VDEV = BIT(3), +++ WMI_STAT_BCNFLT = BIT(4), +++ WMI_STAT_VDEV_RATE = BIT(5), ++ }; ++ ++ struct wlan_inst_rssi_args { ++@@ -2801,7 +3097,7 @@ struct wmi_pdev_suspend_cmd { ++ } __packed; ++ ++ struct wmi_stats_event { ++- __le32 stats_id; /* %WMI_REQUEST_ */ +++ __le32 stats_id; /* WMI_STAT_ */ ++ /* ++ * number of pdev stats event structures ++ * (wmi_pdev_stats) 0 or 1 ++@@ -2830,30 +3126,38 @@ struct wmi_stats_event { ++ u8 data[0]; ++ } __packed; ++ +++struct wmi_10_2_stats_event { +++ __le32 stats_id; /* %WMI_REQUEST_ */ +++ __le32 num_pdev_stats; +++ __le32 num_pdev_ext_stats; +++ __le32 num_vdev_stats; +++ __le32 num_peer_stats; +++ __le32 num_bcnflt_stats; +++ u8 data[0]; +++} __packed; +++ ++ /* ++ * PDEV statistics ++ * TODO: add all PDEV stats here ++ */ ++-struct wmi_pdev_stats_old { ++- __le32 chan_nf; /* Channel noise floor */ ++- __le32 tx_frame_count; /* TX frame count */ ++- __le32 rx_frame_count; /* RX frame count */ ++- __le32 rx_clear_count; /* rx clear count */ ++- __le32 cycle_count; /* cycle count */ ++- __le32 phy_err_count; /* Phy error count */ ++- __le32 chan_tx_pwr; /* channel tx power */ ++- struct wal_dbg_stats wal; /* WAL dbg stats */ ++-} __packed; ++- ++-struct wmi_pdev_stats_10x { ++- __le32 chan_nf; /* Channel noise floor */ ++- __le32 tx_frame_count; /* TX frame count */ ++- __le32 rx_frame_count; /* RX frame count */ ++- __le32 rx_clear_count; /* rx clear count */ ++- __le32 cycle_count; /* cycle count */ ++- __le32 phy_err_count; /* Phy error count */ ++- __le32 chan_tx_pwr; /* channel tx power */ ++- struct wal_dbg_stats wal; /* WAL dbg stats */ +++struct wmi_pdev_stats_base { +++ __le32 chan_nf; +++ __le32 tx_frame_count; +++ __le32 rx_frame_count; +++ __le32 rx_clear_count; +++ __le32 cycle_count; +++ __le32 phy_err_count; +++ __le32 chan_tx_pwr; +++} __packed; +++ +++struct wmi_pdev_stats { +++ struct wmi_pdev_stats_base base; +++ struct wmi_pdev_stats_tx tx; +++ struct wmi_pdev_stats_rx rx; +++ struct wmi_pdev_stats_peer peer; +++} __packed; +++ +++struct wmi_pdev_stats_extra { ++ __le32 ack_rx_bad; ++ __le32 rts_bad; ++ __le32 rts_good; ++@@ -2862,6 +3166,30 @@ struct wmi_pdev_stats_10x { ++ __le32 mib_int_count; ++ } __packed; ++ +++struct wmi_10x_pdev_stats { +++ struct wmi_pdev_stats_base base; +++ struct wmi_pdev_stats_tx tx; +++ struct wmi_pdev_stats_rx rx; +++ struct wmi_pdev_stats_peer peer; +++ struct wmi_pdev_stats_extra extra; +++} __packed; +++ +++struct wmi_pdev_stats_mem { +++ __le32 dram_free; +++ __le32 iram_free; +++} __packed; +++ +++struct wmi_10_2_pdev_stats { +++ struct wmi_pdev_stats_base base; +++ struct wmi_pdev_stats_tx tx; +++ __le32 mc_drop; +++ struct wmi_pdev_stats_rx rx; +++ __le32 pdev_rx_timeout; +++ struct wmi_pdev_stats_mem mem; +++ struct wmi_pdev_stats_peer peer; +++ struct wmi_pdev_stats_extra extra; +++} __packed; +++ ++ /* ++ * VDEV statistics ++ * TODO: add all VDEV stats here ++@@ -2874,19 +3202,43 @@ struct wmi_vdev_stats { ++ * peer statistics. ++ * TODO: add more stats ++ */ ++-struct wmi_peer_stats_old { +++struct wmi_peer_stats { ++ struct wmi_mac_addr peer_macaddr; ++ __le32 peer_rssi; ++ __le32 peer_tx_rate; ++ } __packed; ++ ++-struct wmi_peer_stats_10x { ++- struct wmi_mac_addr peer_macaddr; ++- __le32 peer_rssi; ++- __le32 peer_tx_rate; +++struct wmi_10x_peer_stats { +++ struct wmi_peer_stats old; ++ __le32 peer_rx_rate; ++ } __packed; ++ +++struct wmi_10_2_peer_stats { +++ struct wmi_peer_stats old; +++ __le32 peer_rx_rate; +++ __le32 current_per; +++ __le32 retries; +++ __le32 tx_rate_count; +++ __le32 max_4ms_frame_len; +++ __le32 total_sub_frames; +++ __le32 tx_bytes; +++ __le32 num_pkt_loss_overflow[4]; +++ __le32 num_pkt_loss_excess_retry[4]; +++} __packed; +++ +++struct wmi_10_2_4_peer_stats { +++ struct wmi_10_2_peer_stats common; +++ __le32 unknown_value; /* FIXME: what is this word? */ +++} __packed; +++ +++struct wmi_10_2_pdev_ext_stats { +++ __le32 rx_rssi_comb; +++ __le32 rx_rssi[4]; +++ __le32 rx_mcs[10]; +++ __le32 tx_mcs[10]; +++ __le32 ack_rssi; +++} __packed; +++ ++ struct wmi_vdev_create_cmd { ++ __le32 vdev_id; ++ __le32 vdev_type; ++@@ -3387,8 +3739,21 @@ enum wmi_10x_vdev_param { ++ WMI_10X_VDEV_PARAM_ENABLE_RTSCTS, ++ ++ WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, +++ +++ /* following are available as of firmware 10.2 */ +++ WMI_10X_VDEV_PARAM_TX_ENCAP_TYPE, +++ WMI_10X_VDEV_PARAM_CABQ_MAXDUR, +++ WMI_10X_VDEV_PARAM_MFPTEST_SET, +++ WMI_10X_VDEV_PARAM_RTS_FIXED_RATE, +++ WMI_10X_VDEV_PARAM_VHT_SGIMASK, +++ WMI_10X_VDEV_PARAM_VHT80_RATEMASK, ++ }; ++ +++#define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0) +++#define WMI_VDEV_PARAM_TXBF_MU_TX_BFEE BIT(1) +++#define WMI_VDEV_PARAM_TXBF_SU_TX_BFER BIT(2) +++#define WMI_VDEV_PARAM_TXBF_MU_TX_BFER BIT(3) +++ ++ /* slot time long */ ++ #define WMI_VDEV_SLOT_TIME_LONG 0x1 ++ /* slot time short */ ++@@ -3444,6 +3809,98 @@ struct wmi_vdev_simple_event { ++ /* unsupported VDEV combination */ ++ #define WMI_INIFIED_VDEV_START_RESPONSE_NOT_SUPPORTED 0x2 ++ +++/* TODO: please add more comments if you have in-depth information */ +++struct wmi_vdev_spectral_conf_cmd { +++ __le32 vdev_id; +++ +++ /* number of fft samples to send (0 for infinite) */ +++ __le32 scan_count; +++ __le32 scan_period; +++ __le32 scan_priority; +++ +++ /* number of bins in the FFT: 2^(fft_size - bin_scale) */ +++ __le32 scan_fft_size; +++ __le32 scan_gc_ena; +++ __le32 scan_restart_ena; +++ __le32 scan_noise_floor_ref; +++ __le32 scan_init_delay; +++ __le32 scan_nb_tone_thr; +++ __le32 scan_str_bin_thr; +++ __le32 scan_wb_rpt_mode; +++ __le32 scan_rssi_rpt_mode; +++ __le32 scan_rssi_thr; +++ __le32 scan_pwr_format; +++ +++ /* rpt_mode: Format of FFT report to software for spectral scan +++ * triggered FFTs: +++ * 0: No FFT report (only spectral scan summary report) +++ * 1: 2-dword summary of metrics for each completed FFT + spectral +++ * scan summary report +++ * 2: 2-dword summary of metrics for each completed FFT + +++ * 1x- oversampled bins(in-band) per FFT + spectral scan summary +++ * report +++ * 3: 2-dword summary of metrics for each completed FFT + +++ * 2x- oversampled bins (all) per FFT + spectral scan summary +++ */ +++ __le32 scan_rpt_mode; +++ __le32 scan_bin_scale; +++ __le32 scan_dbm_adj; +++ __le32 scan_chn_mask; +++} __packed; +++ +++struct wmi_vdev_spectral_conf_arg { +++ u32 vdev_id; +++ u32 scan_count; +++ u32 scan_period; +++ u32 scan_priority; +++ u32 scan_fft_size; +++ u32 scan_gc_ena; +++ u32 scan_restart_ena; +++ u32 scan_noise_floor_ref; +++ u32 scan_init_delay; +++ u32 scan_nb_tone_thr; +++ u32 scan_str_bin_thr; +++ u32 scan_wb_rpt_mode; +++ u32 scan_rssi_rpt_mode; +++ u32 scan_rssi_thr; +++ u32 scan_pwr_format; +++ u32 scan_rpt_mode; +++ u32 scan_bin_scale; +++ u32 scan_dbm_adj; +++ u32 scan_chn_mask; +++}; +++ +++#define WMI_SPECTRAL_ENABLE_DEFAULT 0 +++#define WMI_SPECTRAL_COUNT_DEFAULT 0 +++#define WMI_SPECTRAL_PERIOD_DEFAULT 35 +++#define WMI_SPECTRAL_PRIORITY_DEFAULT 1 +++#define WMI_SPECTRAL_FFT_SIZE_DEFAULT 7 +++#define WMI_SPECTRAL_GC_ENA_DEFAULT 1 +++#define WMI_SPECTRAL_RESTART_ENA_DEFAULT 0 +++#define WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT -96 +++#define WMI_SPECTRAL_INIT_DELAY_DEFAULT 80 +++#define WMI_SPECTRAL_NB_TONE_THR_DEFAULT 12 +++#define WMI_SPECTRAL_STR_BIN_THR_DEFAULT 8 +++#define WMI_SPECTRAL_WB_RPT_MODE_DEFAULT 0 +++#define WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT 0 +++#define WMI_SPECTRAL_RSSI_THR_DEFAULT 0xf0 +++#define WMI_SPECTRAL_PWR_FORMAT_DEFAULT 0 +++#define WMI_SPECTRAL_RPT_MODE_DEFAULT 2 +++#define WMI_SPECTRAL_BIN_SCALE_DEFAULT 1 +++#define WMI_SPECTRAL_DBM_ADJ_DEFAULT 1 +++#define WMI_SPECTRAL_CHN_MASK_DEFAULT 1 +++ +++struct wmi_vdev_spectral_enable_cmd { +++ __le32 vdev_id; +++ __le32 trigger_cmd; +++ __le32 enable_cmd; +++} __packed; +++ +++#define WMI_SPECTRAL_TRIGGER_CMD_TRIGGER 1 +++#define WMI_SPECTRAL_TRIGGER_CMD_CLEAR 2 +++#define WMI_SPECTRAL_ENABLE_CMD_ENABLE 1 +++#define WMI_SPECTRAL_ENABLE_CMD_DISABLE 2 +++ ++ /* Beacon processing related command and event structures */ ++ struct wmi_bcn_tx_hdr { ++ __le32 vdev_id; ++@@ -3470,6 +3927,11 @@ enum wmi_bcn_tx_ref_flags { ++ WMI_BCN_TX_REF_FLAG_DELIVER_CAB = 0x2, ++ }; ++ +++/* TODO: It is unclear why "no antenna" works while any other seemingly valid +++ * chainmask yields no beacons on the air at all. +++ */ +++#define WMI_BCN_TX_REF_DEF_ANTENNA 0 +++ ++ struct wmi_bcn_tx_ref_cmd { ++ __le32 vdev_id; ++ __le32 data_len; ++@@ -3481,6 +3943,8 @@ struct wmi_bcn_tx_ref_cmd { ++ __le32 frame_control; ++ /* to control CABQ traffic: WMI_BCN_TX_REF_FLAG_ */ ++ __le32 flags; +++ /* introduced in 10.2 */ +++ __le32 antenna_mask; ++ } __packed; ++ ++ /* Beacon filter */ ++@@ -3633,6 +4097,13 @@ enum wmi_sta_ps_param_pspoll_count { ++ * Values greater than 0 indicate the maximum numer of PS-Poll frames ++ * FW will send before waking up. ++ */ +++ +++ /* When u-APSD is enabled the firmware will be very reluctant to exit +++ * STA PS. This could result in very poor Rx performance with STA doing +++ * PS-Poll for each and every buffered frame. This value is a bit +++ * arbitrary. +++ */ +++ WMI_STA_PS_PSPOLL_COUNT_UAPSD = 3, ++ }; ++ ++ /* ++@@ -3658,6 +4129,30 @@ enum wmi_sta_ps_param_uapsd { ++ WMI_STA_PS_UAPSD_AC3_TRIGGER_EN = (1 << 7), ++ }; ++ +++#define WMI_STA_UAPSD_MAX_INTERVAL_MSEC UINT_MAX +++ +++struct wmi_sta_uapsd_auto_trig_param { +++ __le32 wmm_ac; +++ __le32 user_priority; +++ __le32 service_interval; +++ __le32 suspend_interval; +++ __le32 delay_interval; +++}; +++ +++struct wmi_sta_uapsd_auto_trig_cmd_fixed_param { +++ __le32 vdev_id; +++ struct wmi_mac_addr peer_macaddr; +++ __le32 num_ac; +++}; +++ +++struct wmi_sta_uapsd_auto_trig_arg { +++ u32 wmm_ac; +++ u32 user_priority; +++ u32 service_interval; +++ u32 suspend_interval; +++ u32 delay_interval; +++}; +++ ++ enum wmi_sta_powersave_param { ++ /* ++ * Controls how frames are retrievd from AP while STA is sleeping ++@@ -3823,7 +4318,7 @@ struct wmi_bcn_info { ++ ++ struct wmi_host_swba_event { ++ __le32 vdev_map; ++- struct wmi_bcn_info bcn_info[1]; +++ struct wmi_bcn_info bcn_info[0]; ++ } __packed; ++ ++ #define WMI_MAX_AP_VDEV 16 ++@@ -3833,7 +4328,6 @@ struct wmi_tbtt_offset_event { ++ __le32 tbttoffset_list[WMI_MAX_AP_VDEV]; ++ } __packed; ++ ++- ++ struct wmi_peer_create_cmd { ++ __le32 vdev_id; ++ struct wmi_mac_addr peer_macaddr; ++@@ -3951,7 +4445,8 @@ enum wmi_peer_param { ++ WMI_PEER_AUTHORIZE = 0x3, ++ WMI_PEER_CHAN_WIDTH = 0x4, ++ WMI_PEER_NSS = 0x5, ++- WMI_PEER_USE_4ADDR = 0x6 +++ WMI_PEER_USE_4ADDR = 0x6, +++ WMI_PEER_DUMMY_VAR = 0xff, /* dummy parameter for STA PS workaround */ ++ }; ++ ++ struct wmi_peer_set_param_cmd { ++@@ -4029,7 +4524,7 @@ struct wmi_peer_set_q_empty_callback_cmd ++ #define WMI_PEER_SPATIAL_MUX 0x00200000 ++ #define WMI_PEER_VHT 0x02000000 ++ #define WMI_PEER_80MHZ 0x04000000 ++-#define WMI_PEER_PMF 0x08000000 +++#define WMI_PEER_VHT_2G 0x08000000 ++ ++ /* ++ * Peer rate capabilities. ++@@ -4053,7 +4548,7 @@ struct wmi_peer_set_q_empty_callback_cmd ++ /* Maximum listen interval supported by hw in units of beacon interval */ ++ #define ATH10K_MAX_HW_LISTEN_INTERVAL 5 ++ ++-struct wmi_peer_assoc_complete_cmd { +++struct wmi_common_peer_assoc_complete_cmd { ++ struct wmi_mac_addr peer_macaddr; ++ __le32 vdev_id; ++ __le32 peer_new_assoc; /* 1=assoc, 0=reassoc */ ++@@ -4071,11 +4566,30 @@ struct wmi_peer_assoc_complete_cmd { ++ __le32 peer_vht_caps; ++ __le32 peer_phymode; ++ struct wmi_vht_rate_set peer_vht_rates; +++}; +++ +++struct wmi_main_peer_assoc_complete_cmd { +++ struct wmi_common_peer_assoc_complete_cmd cmd; +++ ++ /* HT Operation Element of the peer. Five bytes packed in 2 ++ * INT32 array and filled from lsb to msb. */ ++ __le32 peer_ht_info[2]; ++ } __packed; ++ +++struct wmi_10_1_peer_assoc_complete_cmd { +++ struct wmi_common_peer_assoc_complete_cmd cmd; +++} __packed; +++ +++#define WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX_LSB 0 +++#define WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX_MASK 0x0f +++#define WMI_PEER_ASSOC_INFO0_MAX_NSS_LSB 4 +++#define WMI_PEER_ASSOC_INFO0_MAX_NSS_MASK 0xf0 +++ +++struct wmi_10_2_peer_assoc_complete_cmd { +++ struct wmi_common_peer_assoc_complete_cmd cmd; +++ __le32 info0; /* WMI_PEER_ASSOC_INFO0_ */ +++} __packed; +++ ++ struct wmi_peer_assoc_complete_arg { ++ u8 addr[ETH_ALEN]; ++ u32 vdev_id; ++@@ -4161,6 +4675,11 @@ enum wmi_sta_keepalive_method { ++ WMI_STA_KEEPALIVE_METHOD_UNSOLICITATED_ARP_RESPONSE = 2, ++ }; ++ +++#define WMI_STA_KEEPALIVE_INTERVAL_DISABLE 0 +++ +++/* Firmware crashes if keepalive interval exceeds this limit */ +++#define WMI_STA_KEEPALIVE_INTERVAL_MAX_SECONDS 0xffff +++ ++ /* note: ip4 addresses are in network byte order, i.e. big endian */ ++ struct wmi_sta_keepalive_arp_resp { ++ __be32 src_ip4_addr; ++@@ -4176,6 +4695,16 @@ struct wmi_sta_keepalive_cmd { ++ struct wmi_sta_keepalive_arp_resp arp_resp; ++ } __packed; ++ +++struct wmi_sta_keepalive_arg { +++ u32 vdev_id; +++ u32 enabled; +++ u32 method; +++ u32 interval; +++ __be32 src_ip4_addr; +++ __be32 dest_ip4_addr; +++ const u8 dest_mac_addr[ETH_ALEN]; +++}; +++ ++ enum wmi_force_fw_hang_type { ++ WMI_FORCE_FW_HANG_ASSERT = 1, ++ WMI_FORCE_FW_HANG_NO_DETECT, ++@@ -4240,7 +4769,6 @@ struct wmi_dbglog_cfg_cmd { ++ __le32 config_valid; ++ } __packed; ++ ++-#define ATH10K_RTS_MAX 2347 ++ #define ATH10K_FRAGMT_THRESHOLD_MIN 540 ++ #define ATH10K_FRAGMT_THRESHOLD_MAX 2346 ++ ++@@ -4251,72 +4779,170 @@ struct wmi_dbglog_cfg_cmd { ++ /* By default disable power save for IBSS */ ++ #define ATH10K_DEFAULT_ATIM 0 ++ +++#define WMI_MAX_MEM_REQS 16 +++ +++struct wmi_scan_ev_arg { +++ __le32 event_type; /* %WMI_SCAN_EVENT_ */ +++ __le32 reason; /* %WMI_SCAN_REASON_ */ +++ __le32 channel_freq; /* only valid for WMI_SCAN_EVENT_FOREIGN_CHANNEL */ +++ __le32 scan_req_id; +++ __le32 scan_id; +++ __le32 vdev_id; +++}; +++ +++struct wmi_mgmt_rx_ev_arg { +++ __le32 channel; +++ __le32 snr; +++ __le32 rate; +++ __le32 phy_mode; +++ __le32 buf_len; +++ __le32 status; /* %WMI_RX_STATUS_ */ +++}; +++ +++struct wmi_ch_info_ev_arg { +++ __le32 err_code; +++ __le32 freq; +++ __le32 cmd_flags; +++ __le32 noise_floor; +++ __le32 rx_clear_count; +++ __le32 cycle_count; +++}; +++ +++struct wmi_vdev_start_ev_arg { +++ __le32 vdev_id; +++ __le32 req_id; +++ __le32 resp_type; /* %WMI_VDEV_RESP_ */ +++ __le32 status; +++}; +++ +++struct wmi_peer_kick_ev_arg { +++ const u8 *mac_addr; +++}; +++ +++struct wmi_swba_ev_arg { +++ __le32 vdev_map; +++ const struct wmi_tim_info *tim_info[WMI_MAX_AP_VDEV]; +++ const struct wmi_p2p_noa_info *noa_info[WMI_MAX_AP_VDEV]; +++}; +++ +++struct wmi_phyerr_ev_arg { +++ __le32 num_phyerrs; +++ __le32 tsf_l32; +++ __le32 tsf_u32; +++ __le32 buf_len; +++ const struct wmi_phyerr *phyerrs; +++}; +++ +++struct wmi_svc_rdy_ev_arg { +++ __le32 min_tx_power; +++ __le32 max_tx_power; +++ __le32 ht_cap; +++ __le32 vht_cap; +++ __le32 sw_ver0; +++ __le32 sw_ver1; +++ __le32 fw_build; +++ __le32 phy_capab; +++ __le32 num_rf_chains; +++ __le32 eeprom_rd; +++ __le32 num_mem_reqs; +++ const __le32 *service_map; +++ size_t service_map_len; +++ const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS]; +++}; +++ +++struct wmi_rdy_ev_arg { +++ __le32 sw_version; +++ __le32 abi_version; +++ __le32 status; +++ const u8 *mac_addr; +++}; +++ +++struct wmi_pdev_temperature_event { +++ /* temperature value in Celcius degree */ +++ __le32 temperature; +++} __packed; +++ ++ struct ath10k; ++ struct ath10k_vif; +++struct ath10k_fw_stats_pdev; +++struct ath10k_fw_stats_peer; ++ ++ int ath10k_wmi_attach(struct ath10k *ar); ++ void ath10k_wmi_detach(struct ath10k *ar); ++ int ath10k_wmi_wait_for_service_ready(struct ath10k *ar); ++ int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar); ++ ++-int ath10k_wmi_connect_htc_service(struct ath10k *ar); ++-int ath10k_wmi_pdev_set_channel(struct ath10k *ar, ++- const struct wmi_channel_arg *); ++-int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt); ++-int ath10k_wmi_pdev_resume_target(struct ath10k *ar); ++-int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, ++- u16 rd5g, u16 ctl2g, u16 ctl5g, ++- enum wmi_dfs_region dfs_reg); ++-int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value); ++-int ath10k_wmi_cmd_init(struct ath10k *ar); ++-int ath10k_wmi_start_scan(struct ath10k *ar, const struct wmi_start_scan_arg *); +++struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len); +++int ath10k_wmi_connect(struct ath10k *ar); +++ +++struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len); +++int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); +++int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb, +++ u32 cmd_id); ++ void ath10k_wmi_start_scan_init(struct ath10k *ar, struct wmi_start_scan_arg *); ++-int ath10k_wmi_stop_scan(struct ath10k *ar, ++- const struct wmi_stop_scan_arg *arg); ++-int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id, ++- enum wmi_vdev_type type, ++- enum wmi_vdev_subtype subtype, ++- const u8 macaddr[ETH_ALEN]); ++-int ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id); ++-int ath10k_wmi_vdev_start(struct ath10k *ar, ++- const struct wmi_vdev_start_request_arg *); ++-int ath10k_wmi_vdev_restart(struct ath10k *ar, ++- const struct wmi_vdev_start_request_arg *); ++-int ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id); ++-int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, ++- const u8 *bssid); ++-int ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id); ++-int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id, ++- u32 param_id, u32 param_value); ++-int ath10k_wmi_vdev_install_key(struct ath10k *ar, ++- const struct wmi_vdev_install_key_arg *arg); ++-int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id, ++- const u8 peer_addr[ETH_ALEN]); ++-int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id, ++- const u8 peer_addr[ETH_ALEN]); ++-int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id, ++- const u8 peer_addr[ETH_ALEN], u32 tid_bitmap); ++-int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id, ++- const u8 *peer_addr, ++- enum wmi_peer_param param_id, u32 param_value); ++-int ath10k_wmi_peer_assoc(struct ath10k *ar, ++- const struct wmi_peer_assoc_complete_arg *arg); ++-int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id, ++- enum wmi_sta_ps_mode psmode); ++-int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id, ++- enum wmi_sta_powersave_param param_id, ++- u32 value); ++-int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac, ++- enum wmi_ap_ps_peer_param param_id, u32 value); ++-int ath10k_wmi_scan_chan_list(struct ath10k *ar, ++- const struct wmi_scan_chan_list_arg *arg); ++-int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif); ++-int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, ++- const struct wmi_pdev_set_wmm_params_arg *arg); ++-int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id); ++-int ath10k_wmi_force_fw_hang(struct ath10k *ar, ++- enum wmi_force_fw_hang_type type, u32 delay_ms); ++-int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb); ++-int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable); +++ +++void ath10k_wmi_pull_pdev_stats_base(const struct wmi_pdev_stats_base *src, +++ struct ath10k_fw_stats_pdev *dst); +++void ath10k_wmi_pull_pdev_stats_tx(const struct wmi_pdev_stats_tx *src, +++ struct ath10k_fw_stats_pdev *dst); +++void ath10k_wmi_pull_pdev_stats_rx(const struct wmi_pdev_stats_rx *src, +++ struct ath10k_fw_stats_pdev *dst); +++void ath10k_wmi_pull_pdev_stats_extra(const struct wmi_pdev_stats_extra *src, +++ struct ath10k_fw_stats_pdev *dst); +++void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src, +++ struct ath10k_fw_stats_peer *dst); +++void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar, +++ struct wmi_host_mem_chunks *chunks); +++void ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn, +++ const struct wmi_start_scan_arg *arg); +++void ath10k_wmi_set_wmm_param(struct wmi_wmm_params *params, +++ const struct wmi_wmm_params_arg *arg); +++void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, +++ const struct wmi_channel_arg *arg); +++int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg); +++ +++int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb); +++int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb); +++int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_update_stats(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_dfs(struct ath10k *ar, +++ const struct wmi_phyerr *phyerr, u64 tsf); +++void ath10k_wmi_event_spectral_scan(struct ath10k *ar, +++ const struct wmi_phyerr *phyerr, +++ u64 tsf); +++void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_profile_match(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_debug_print(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar, +++ struct sk_buff *skb); +++void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar, +++ struct sk_buff *skb); +++void ath10k_wmi_event_rtt_error_report(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_dcs_interference(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar, +++ struct sk_buff *skb); +++void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_delba_complete(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_addba_complete(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar, +++ struct sk_buff *skb); +++void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb); +++void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb); +++int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb); ++ ++ #endif /* _WMI_H_ */ ++--- /dev/null +++++ b/drivers/net/wireless/ath/ath10k/spectral.c ++@@ -0,0 +1,552 @@ +++/* +++ * Copyright (c) 2013 Qualcomm Atheros, Inc. +++ * +++ * Permission to use, copy, modify, and/or distribute this software for any +++ * purpose with or without fee is hereby granted, provided that the above +++ * copyright notice and this permission notice appear in all copies. +++ * +++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +++ */ +++ +++#include +++#include "core.h" +++#include "debug.h" +++#include "wmi-ops.h" +++ +++static void send_fft_sample(struct ath10k *ar, +++ const struct fft_sample_tlv *fft_sample_tlv) +++{ +++ int length; +++ +++ if (!ar->spectral.rfs_chan_spec_scan) +++ return; +++ +++ length = __be16_to_cpu(fft_sample_tlv->length) + +++ sizeof(*fft_sample_tlv); +++ relay_write(ar->spectral.rfs_chan_spec_scan, fft_sample_tlv, length); +++} +++ +++static uint8_t get_max_exp(s8 max_index, u16 max_magnitude, size_t bin_len, +++ u8 *data) +++{ +++ int dc_pos; +++ u8 max_exp; +++ +++ dc_pos = bin_len / 2; +++ +++ /* peak index outside of bins */ +++ if (dc_pos < max_index || -dc_pos >= max_index) +++ return 0; +++ +++ for (max_exp = 0; max_exp < 8; max_exp++) { +++ if (data[dc_pos + max_index] == (max_magnitude >> max_exp)) +++ break; +++ } +++ +++ /* max_exp not found */ +++ if (data[dc_pos + max_index] != (max_magnitude >> max_exp)) +++ return 0; +++ +++ return max_exp; +++} +++ +++int ath10k_spectral_process_fft(struct ath10k *ar, +++ const struct wmi_phyerr *phyerr, +++ const struct phyerr_fft_report *fftr, +++ size_t bin_len, u64 tsf) +++{ +++ struct fft_sample_ath10k *fft_sample; +++ u8 buf[sizeof(*fft_sample) + SPECTRAL_ATH10K_MAX_NUM_BINS]; +++ u16 freq1, freq2, total_gain_db, base_pwr_db, length, peak_mag; +++ u32 reg0, reg1; +++ u8 chain_idx, *bins; +++ int dc_pos; +++ +++ fft_sample = (struct fft_sample_ath10k *)&buf; +++ +++ if (bin_len < 64 || bin_len > SPECTRAL_ATH10K_MAX_NUM_BINS) +++ return -EINVAL; +++ +++ reg0 = __le32_to_cpu(fftr->reg0); +++ reg1 = __le32_to_cpu(fftr->reg1); +++ +++ length = sizeof(*fft_sample) - sizeof(struct fft_sample_tlv) + bin_len; +++ fft_sample->tlv.type = ATH_FFT_SAMPLE_ATH10K; +++ fft_sample->tlv.length = __cpu_to_be16(length); +++ +++ /* TODO: there might be a reason why the hardware reports 20/40/80 MHz, +++ * but the results/plots suggest that its actually 22/44/88 MHz. +++ */ +++ switch (phyerr->chan_width_mhz) { +++ case 20: +++ fft_sample->chan_width_mhz = 22; +++ break; +++ case 40: +++ fft_sample->chan_width_mhz = 44; +++ break; +++ case 80: +++ /* TODO: As experiments with an analogue sender and various +++ * configuaritions (fft-sizes of 64/128/256 and 20/40/80 Mhz) +++ * show, the particular configuration of 80 MHz/64 bins does +++ * not match with the other smaples at all. Until the reason +++ * for that is found, don't report these samples. +++ */ +++ if (bin_len == 64) +++ return -EINVAL; +++ fft_sample->chan_width_mhz = 88; +++ break; +++ default: +++ fft_sample->chan_width_mhz = phyerr->chan_width_mhz; +++ } +++ +++ fft_sample->relpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB); +++ fft_sample->avgpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB); +++ +++ peak_mag = MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG); +++ fft_sample->max_magnitude = __cpu_to_be16(peak_mag); +++ fft_sample->max_index = MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX); +++ fft_sample->rssi = phyerr->rssi_combined; +++ +++ total_gain_db = MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB); +++ base_pwr_db = MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB); +++ fft_sample->total_gain_db = __cpu_to_be16(total_gain_db); +++ fft_sample->base_pwr_db = __cpu_to_be16(base_pwr_db); +++ +++ freq1 = __le16_to_cpu(phyerr->freq1); +++ freq2 = __le16_to_cpu(phyerr->freq2); +++ fft_sample->freq1 = __cpu_to_be16(freq1); +++ fft_sample->freq2 = __cpu_to_be16(freq2); +++ +++ chain_idx = MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX); +++ +++ fft_sample->noise = __cpu_to_be16( +++ __le16_to_cpu(phyerr->nf_chains[chain_idx])); +++ +++ bins = (u8 *)fftr; +++ bins += sizeof(*fftr); +++ +++ fft_sample->tsf = __cpu_to_be64(tsf); +++ +++ /* max_exp has been directly reported by previous hardware (ath9k), +++ * maybe its possible to get it by other means? +++ */ +++ fft_sample->max_exp = get_max_exp(fft_sample->max_index, peak_mag, +++ bin_len, bins); +++ +++ memcpy(fft_sample->data, bins, bin_len); +++ +++ /* DC value (value in the middle) is the blind spot of the spectral +++ * sample and invalid, interpolate it. +++ */ +++ dc_pos = bin_len / 2; +++ fft_sample->data[dc_pos] = (fft_sample->data[dc_pos + 1] + +++ fft_sample->data[dc_pos - 1]) / 2; +++ +++ send_fft_sample(ar, &fft_sample->tlv); +++ +++ return 0; +++} +++ +++static struct ath10k_vif *ath10k_get_spectral_vdev(struct ath10k *ar) +++{ +++ struct ath10k_vif *arvif; +++ +++ lockdep_assert_held(&ar->conf_mutex); +++ +++ if (list_empty(&ar->arvifs)) +++ return NULL; +++ +++ /* if there already is a vif doing spectral, return that. */ +++ list_for_each_entry(arvif, &ar->arvifs, list) +++ if (arvif->spectral_enabled) +++ return arvif; +++ +++ /* otherwise, return the first vif. */ +++ return list_first_entry(&ar->arvifs, typeof(*arvif), list); +++} +++ +++static int ath10k_spectral_scan_trigger(struct ath10k *ar) +++{ +++ struct ath10k_vif *arvif; +++ int res; +++ int vdev_id; +++ +++ lockdep_assert_held(&ar->conf_mutex); +++ +++ arvif = ath10k_get_spectral_vdev(ar); +++ if (!arvif) +++ return -ENODEV; +++ vdev_id = arvif->vdev_id; +++ +++ if (ar->spectral.mode == SPECTRAL_DISABLED) +++ return 0; +++ +++ res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id, +++ WMI_SPECTRAL_TRIGGER_CMD_CLEAR, +++ WMI_SPECTRAL_ENABLE_CMD_ENABLE); +++ if (res < 0) +++ return res; +++ +++ res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id, +++ WMI_SPECTRAL_TRIGGER_CMD_TRIGGER, +++ WMI_SPECTRAL_ENABLE_CMD_ENABLE); +++ if (res < 0) +++ return res; +++ +++ return 0; +++} +++ +++static int ath10k_spectral_scan_config(struct ath10k *ar, +++ enum ath10k_spectral_mode mode) +++{ +++ struct wmi_vdev_spectral_conf_arg arg; +++ struct ath10k_vif *arvif; +++ int vdev_id, count, res = 0; +++ +++ lockdep_assert_held(&ar->conf_mutex); +++ +++ arvif = ath10k_get_spectral_vdev(ar); +++ if (!arvif) +++ return -ENODEV; +++ +++ vdev_id = arvif->vdev_id; +++ +++ arvif->spectral_enabled = (mode != SPECTRAL_DISABLED); +++ ar->spectral.mode = mode; +++ +++ res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id, +++ WMI_SPECTRAL_TRIGGER_CMD_CLEAR, +++ WMI_SPECTRAL_ENABLE_CMD_DISABLE); +++ if (res < 0) { +++ ath10k_warn(ar, "failed to enable spectral scan: %d\n", res); +++ return res; +++ } +++ +++ if (mode == SPECTRAL_DISABLED) +++ return 0; +++ +++ if (mode == SPECTRAL_BACKGROUND) +++ count = WMI_SPECTRAL_COUNT_DEFAULT; +++ else +++ count = max_t(u8, 1, ar->spectral.config.count); +++ +++ arg.vdev_id = vdev_id; +++ arg.scan_count = count; +++ arg.scan_period = WMI_SPECTRAL_PERIOD_DEFAULT; +++ arg.scan_priority = WMI_SPECTRAL_PRIORITY_DEFAULT; +++ arg.scan_fft_size = ar->spectral.config.fft_size; +++ arg.scan_gc_ena = WMI_SPECTRAL_GC_ENA_DEFAULT; +++ arg.scan_restart_ena = WMI_SPECTRAL_RESTART_ENA_DEFAULT; +++ arg.scan_noise_floor_ref = WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT; +++ arg.scan_init_delay = WMI_SPECTRAL_INIT_DELAY_DEFAULT; +++ arg.scan_nb_tone_thr = WMI_SPECTRAL_NB_TONE_THR_DEFAULT; +++ arg.scan_str_bin_thr = WMI_SPECTRAL_STR_BIN_THR_DEFAULT; +++ arg.scan_wb_rpt_mode = WMI_SPECTRAL_WB_RPT_MODE_DEFAULT; +++ arg.scan_rssi_rpt_mode = WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT; +++ arg.scan_rssi_thr = WMI_SPECTRAL_RSSI_THR_DEFAULT; +++ arg.scan_pwr_format = WMI_SPECTRAL_PWR_FORMAT_DEFAULT; +++ arg.scan_rpt_mode = WMI_SPECTRAL_RPT_MODE_DEFAULT; +++ arg.scan_bin_scale = WMI_SPECTRAL_BIN_SCALE_DEFAULT; +++ arg.scan_dbm_adj = WMI_SPECTRAL_DBM_ADJ_DEFAULT; +++ arg.scan_chn_mask = WMI_SPECTRAL_CHN_MASK_DEFAULT; +++ +++ res = ath10k_wmi_vdev_spectral_conf(ar, &arg); +++ if (res < 0) { +++ ath10k_warn(ar, "failed to configure spectral scan: %d\n", res); +++ return res; +++ } +++ +++ return 0; +++} +++ +++static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ath10k *ar = file->private_data; +++ char *mode = ""; +++ unsigned int len; +++ enum ath10k_spectral_mode spectral_mode; +++ +++ mutex_lock(&ar->conf_mutex); +++ spectral_mode = ar->spectral.mode; +++ mutex_unlock(&ar->conf_mutex); +++ +++ switch (spectral_mode) { +++ case SPECTRAL_DISABLED: +++ mode = "disable"; +++ break; +++ case SPECTRAL_BACKGROUND: +++ mode = "background"; +++ break; +++ case SPECTRAL_MANUAL: +++ mode = "manual"; +++ break; +++ } +++ +++ len = strlen(mode); +++ return simple_read_from_buffer(user_buf, count, ppos, mode, len); +++} +++ +++static ssize_t write_file_spec_scan_ctl(struct file *file, +++ const char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ath10k *ar = file->private_data; +++ char buf[32]; +++ ssize_t len; +++ int res; +++ +++ len = min(count, sizeof(buf) - 1); +++ if (copy_from_user(buf, user_buf, len)) +++ return -EFAULT; +++ +++ buf[len] = '\0'; +++ +++ mutex_lock(&ar->conf_mutex); +++ +++ if (strncmp("trigger", buf, 7) == 0) { +++ if (ar->spectral.mode == SPECTRAL_MANUAL || +++ ar->spectral.mode == SPECTRAL_BACKGROUND) { +++ /* reset the configuration to adopt possibly changed +++ * debugfs parameters +++ */ +++ res = ath10k_spectral_scan_config(ar, +++ ar->spectral.mode); +++ if (res < 0) { +++ ath10k_warn(ar, "failed to reconfigure spectral scan: %d\n", +++ res); +++ } +++ res = ath10k_spectral_scan_trigger(ar); +++ if (res < 0) { +++ ath10k_warn(ar, "failed to trigger spectral scan: %d\n", +++ res); +++ } +++ } else { +++ res = -EINVAL; +++ } +++ } else if (strncmp("background", buf, 9) == 0) { +++ res = ath10k_spectral_scan_config(ar, SPECTRAL_BACKGROUND); +++ } else if (strncmp("manual", buf, 6) == 0) { +++ res = ath10k_spectral_scan_config(ar, SPECTRAL_MANUAL); +++ } else if (strncmp("disable", buf, 7) == 0) { +++ res = ath10k_spectral_scan_config(ar, SPECTRAL_DISABLED); +++ } else { +++ res = -EINVAL; +++ } +++ +++ mutex_unlock(&ar->conf_mutex); +++ +++ if (res < 0) +++ return res; +++ +++ return count; +++} +++ +++static const struct file_operations fops_spec_scan_ctl = { +++ .read = read_file_spec_scan_ctl, +++ .write = write_file_spec_scan_ctl, +++ .open = simple_open, +++ .owner = THIS_MODULE, +++ .llseek = default_llseek, +++}; +++ +++static ssize_t read_file_spectral_count(struct file *file, +++ char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ath10k *ar = file->private_data; +++ char buf[32]; +++ unsigned int len; +++ u8 spectral_count; +++ +++ mutex_lock(&ar->conf_mutex); +++ spectral_count = ar->spectral.config.count; +++ mutex_unlock(&ar->conf_mutex); +++ +++ len = sprintf(buf, "%d\n", spectral_count); +++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); +++} +++ +++static ssize_t write_file_spectral_count(struct file *file, +++ const char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ath10k *ar = file->private_data; +++ unsigned long val; +++ char buf[32]; +++ ssize_t len; +++ +++ len = min(count, sizeof(buf) - 1); +++ if (copy_from_user(buf, user_buf, len)) +++ return -EFAULT; +++ +++ buf[len] = '\0'; +++ if (kstrtoul(buf, 0, &val)) +++ return -EINVAL; +++ +++ if (val < 0 || val > 255) +++ return -EINVAL; +++ +++ mutex_lock(&ar->conf_mutex); +++ ar->spectral.config.count = val; +++ mutex_unlock(&ar->conf_mutex); +++ +++ return count; +++} +++ +++static const struct file_operations fops_spectral_count = { +++ .read = read_file_spectral_count, +++ .write = write_file_spectral_count, +++ .open = simple_open, +++ .owner = THIS_MODULE, +++ .llseek = default_llseek, +++}; +++ +++static ssize_t read_file_spectral_bins(struct file *file, +++ char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ath10k *ar = file->private_data; +++ char buf[32]; +++ unsigned int len, bins, fft_size, bin_scale; +++ +++ mutex_lock(&ar->conf_mutex); +++ +++ fft_size = ar->spectral.config.fft_size; +++ bin_scale = WMI_SPECTRAL_BIN_SCALE_DEFAULT; +++ bins = 1 << (fft_size - bin_scale); +++ +++ mutex_unlock(&ar->conf_mutex); +++ +++ len = sprintf(buf, "%d\n", bins); +++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); +++} +++ +++static ssize_t write_file_spectral_bins(struct file *file, +++ const char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ath10k *ar = file->private_data; +++ unsigned long val; +++ char buf[32]; +++ ssize_t len; +++ +++ len = min(count, sizeof(buf) - 1); +++ if (copy_from_user(buf, user_buf, len)) +++ return -EFAULT; +++ +++ buf[len] = '\0'; +++ if (kstrtoul(buf, 0, &val)) +++ return -EINVAL; +++ +++ if (val < 64 || val > SPECTRAL_ATH10K_MAX_NUM_BINS) +++ return -EINVAL; +++ +++ if (!is_power_of_2(val)) +++ return -EINVAL; +++ +++ mutex_lock(&ar->conf_mutex); +++ ar->spectral.config.fft_size = ilog2(val); +++ ar->spectral.config.fft_size += WMI_SPECTRAL_BIN_SCALE_DEFAULT; +++ mutex_unlock(&ar->conf_mutex); +++ +++ return count; +++} +++ +++static const struct file_operations fops_spectral_bins = { +++ .read = read_file_spectral_bins, +++ .write = write_file_spectral_bins, +++ .open = simple_open, +++ .owner = THIS_MODULE, +++ .llseek = default_llseek, +++}; +++ +++static struct dentry *create_buf_file_handler(const char *filename, +++ struct dentry *parent, +++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0)) +++ umode_t mode, +++#else +++ int mode, +++#endif +++ struct rchan_buf *buf, +++ int *is_global) +++{ +++ struct dentry *buf_file; +++ +++ buf_file = debugfs_create_file(filename, mode, parent, buf, +++ &relay_file_operations); +++ *is_global = 1; +++ return buf_file; +++} +++ +++static int remove_buf_file_handler(struct dentry *dentry) +++{ +++ debugfs_remove(dentry); +++ +++ return 0; +++} +++ +++static struct rchan_callbacks rfs_spec_scan_cb = { +++ .create_buf_file = create_buf_file_handler, +++ .remove_buf_file = remove_buf_file_handler, +++}; +++ +++int ath10k_spectral_start(struct ath10k *ar) +++{ +++ struct ath10k_vif *arvif; +++ +++ lockdep_assert_held(&ar->conf_mutex); +++ +++ list_for_each_entry(arvif, &ar->arvifs, list) +++ arvif->spectral_enabled = 0; +++ +++ ar->spectral.mode = SPECTRAL_DISABLED; +++ ar->spectral.config.count = WMI_SPECTRAL_COUNT_DEFAULT; +++ ar->spectral.config.fft_size = WMI_SPECTRAL_FFT_SIZE_DEFAULT; +++ +++ return 0; +++} +++ +++int ath10k_spectral_vif_stop(struct ath10k_vif *arvif) +++{ +++ if (!arvif->spectral_enabled) +++ return 0; +++ +++ return ath10k_spectral_scan_config(arvif->ar, SPECTRAL_DISABLED); +++} +++ +++int ath10k_spectral_create(struct ath10k *ar) +++{ +++ ar->spectral.rfs_chan_spec_scan = relay_open("spectral_scan", +++ ar->debug.debugfs_phy, +++ 1024, 256, +++ &rfs_spec_scan_cb, NULL); +++ debugfs_create_file("spectral_scan_ctl", +++ S_IRUSR | S_IWUSR, +++ ar->debug.debugfs_phy, ar, +++ &fops_spec_scan_ctl); +++ debugfs_create_file("spectral_count", +++ S_IRUSR | S_IWUSR, +++ ar->debug.debugfs_phy, ar, +++ &fops_spectral_count); +++ debugfs_create_file("spectral_bins", +++ S_IRUSR | S_IWUSR, +++ ar->debug.debugfs_phy, ar, +++ &fops_spectral_bins); +++ +++ return 0; +++} +++ +++void ath10k_spectral_destroy(struct ath10k *ar) +++{ +++ if (ar->spectral.rfs_chan_spec_scan) { +++ relay_close(ar->spectral.rfs_chan_spec_scan); +++ ar->spectral.rfs_chan_spec_scan = NULL; +++ } +++} ++--- /dev/null +++++ b/drivers/net/wireless/ath/ath10k/spectral.h ++@@ -0,0 +1,90 @@ +++/* +++ * Copyright (c) 2013 Qualcomm Atheros, Inc. +++ * +++ * Permission to use, copy, modify, and/or distribute this software for any +++ * purpose with or without fee is hereby granted, provided that the above +++ * copyright notice and this permission notice appear in all copies. +++ * +++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +++ */ +++ +++#ifndef SPECTRAL_H +++#define SPECTRAL_H +++ +++#include "../spectral_common.h" +++ +++/** +++ * struct ath10k_spec_scan - parameters for Atheros spectral scan +++ * +++ * @count: number of scan results requested for manual mode +++ * @fft_size: number of bins to be requested = 2^(fft_size - bin_scale) +++ */ +++struct ath10k_spec_scan { +++ u8 count; +++ u8 fft_size; +++}; +++ +++/* enum ath10k_spectral_mode: +++ * +++ * @SPECTRAL_DISABLED: spectral mode is disabled +++ * @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with +++ * something else. +++ * @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples +++ * is performed manually. +++ */ +++enum ath10k_spectral_mode { +++ SPECTRAL_DISABLED = 0, +++ SPECTRAL_BACKGROUND, +++ SPECTRAL_MANUAL, +++}; +++ +++#ifdef CPTCFG_ATH10K_DEBUGFS +++ +++int ath10k_spectral_process_fft(struct ath10k *ar, +++ const struct wmi_phyerr *phyerr, +++ const struct phyerr_fft_report *fftr, +++ size_t bin_len, u64 tsf); +++int ath10k_spectral_start(struct ath10k *ar); +++int ath10k_spectral_vif_stop(struct ath10k_vif *arvif); +++int ath10k_spectral_create(struct ath10k *ar); +++void ath10k_spectral_destroy(struct ath10k *ar); +++ +++#else +++ +++static inline int +++ath10k_spectral_process_fft(struct ath10k *ar, +++ const struct wmi_phyerr *phyerr, +++ const struct phyerr_fft_report *fftr, +++ size_t bin_len, u64 tsf) +++{ +++ return 0; +++} +++ +++static inline int ath10k_spectral_start(struct ath10k *ar) +++{ +++ return 0; +++} +++ +++static inline int ath10k_spectral_vif_stop(struct ath10k_vif *arvif) +++{ +++ return 0; +++} +++ +++static inline int ath10k_spectral_create(struct ath10k *ar) +++{ +++ return 0; +++} +++ +++static inline void ath10k_spectral_destroy(struct ath10k *ar) +++{ +++} +++ +++#endif /* CPTCFG_ATH10K_DEBUGFS */ +++ +++#endif /* SPECTRAL_H */ ++--- /dev/null +++++ b/drivers/net/wireless/ath/ath10k/testmode.c ++@@ -0,0 +1,385 @@ +++/* +++ * Copyright (c) 2014 Qualcomm Atheros, Inc. +++ * +++ * Permission to use, copy, modify, and/or distribute this software for any +++ * purpose with or without fee is hereby granted, provided that the above +++ * copyright notice and this permission notice appear in all copies. +++ * +++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +++ */ +++ +++#include "testmode.h" +++ +++#include +++#include +++ +++#include "debug.h" +++#include "wmi.h" +++#include "hif.h" +++#include "hw.h" +++ +++#include "testmode_i.h" +++ +++static const struct nla_policy ath10k_tm_policy[ATH10K_TM_ATTR_MAX + 1] = { +++ [ATH10K_TM_ATTR_CMD] = { .type = NLA_U32 }, +++ [ATH10K_TM_ATTR_DATA] = { .type = NLA_BINARY, +++ .len = ATH10K_TM_DATA_MAX_LEN }, +++ [ATH10K_TM_ATTR_WMI_CMDID] = { .type = NLA_U32 }, +++ [ATH10K_TM_ATTR_VERSION_MAJOR] = { .type = NLA_U32 }, +++ [ATH10K_TM_ATTR_VERSION_MINOR] = { .type = NLA_U32 }, +++}; +++ +++/* Returns true if callee consumes the skb and the skb should be discarded. +++ * Returns false if skb is not used. Does not sleep. +++ */ +++bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb) +++{ +++ struct sk_buff *nl_skb; +++ bool consumed; +++ int ret; +++ +++ ath10k_dbg(ar, ATH10K_DBG_TESTMODE, +++ "testmode event wmi cmd_id %d skb %p skb->len %d\n", +++ cmd_id, skb, skb->len); +++ +++ ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", skb->data, skb->len); +++ +++ spin_lock_bh(&ar->data_lock); +++ +++ if (!ar->testmode.utf_monitor) { +++ consumed = false; +++ goto out; +++ } +++ +++ /* Only testmode.c should be handling events from utf firmware, +++ * otherwise all sort of problems will arise as mac80211 operations +++ * are not initialised. +++ */ +++ consumed = true; +++ +++ nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy, +++ 2 * sizeof(u32) + skb->len, +++ GFP_ATOMIC); +++ if (!nl_skb) { +++ ath10k_warn(ar, +++ "failed to allocate skb for testmode wmi event\n"); +++ goto out; +++ } +++ +++ ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_CMD, ATH10K_TM_CMD_WMI); +++ if (ret) { +++ ath10k_warn(ar, +++ "failed to to put testmode wmi event cmd attribute: %d\n", +++ ret); +++ kfree_skb(nl_skb); +++ goto out; +++ } +++ +++ ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_WMI_CMDID, cmd_id); +++ if (ret) { +++ ath10k_warn(ar, +++ "failed to to put testmode wmi even cmd_id: %d\n", +++ ret); +++ kfree_skb(nl_skb); +++ goto out; +++ } +++ +++ ret = nla_put(nl_skb, ATH10K_TM_ATTR_DATA, skb->len, skb->data); +++ if (ret) { +++ ath10k_warn(ar, +++ "failed to copy skb to testmode wmi event: %d\n", +++ ret); +++ kfree_skb(nl_skb); +++ goto out; +++ } +++ +++ cfg80211_testmode_event(nl_skb, GFP_ATOMIC); +++ +++out: +++ spin_unlock_bh(&ar->data_lock); +++ +++ return consumed; +++} +++ +++static int ath10k_tm_cmd_get_version(struct ath10k *ar, struct nlattr *tb[]) +++{ +++ struct sk_buff *skb; +++ int ret; +++ +++ ath10k_dbg(ar, ATH10K_DBG_TESTMODE, +++ "testmode cmd get version_major %d version_minor %d\n", +++ ATH10K_TESTMODE_VERSION_MAJOR, +++ ATH10K_TESTMODE_VERSION_MINOR); +++ +++ skb = cfg80211_testmode_alloc_reply_skb(ar->hw->wiphy, +++ nla_total_size(sizeof(u32))); +++ if (!skb) +++ return -ENOMEM; +++ +++ ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MAJOR, +++ ATH10K_TESTMODE_VERSION_MAJOR); +++ if (ret) { +++ kfree_skb(skb); +++ return ret; +++ } +++ +++ ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MINOR, +++ ATH10K_TESTMODE_VERSION_MINOR); +++ if (ret) { +++ kfree_skb(skb); +++ return ret; +++ } +++ +++ return cfg80211_testmode_reply(skb); +++} +++ +++static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[]) +++{ +++ char filename[100]; +++ int ret; +++ +++ ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf start\n"); +++ +++ mutex_lock(&ar->conf_mutex); +++ +++ if (ar->state == ATH10K_STATE_UTF) { +++ ret = -EALREADY; +++ goto err; +++ } +++ +++ /* start utf only when the driver is not in use */ +++ if (ar->state != ATH10K_STATE_OFF) { +++ ret = -EBUSY; +++ goto err; +++ } +++ +++ if (WARN_ON(ar->testmode.utf != NULL)) { +++ /* utf image is already downloaded, it shouldn't be */ +++ ret = -EEXIST; +++ goto err; +++ } +++ +++ snprintf(filename, sizeof(filename), "%s/%s", +++ ar->hw_params.fw.dir, ATH10K_FW_UTF_FILE); +++ +++ /* load utf firmware image */ +++ ret = request_firmware(&ar->testmode.utf, filename, ar->dev); +++ if (ret) { +++ ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n", +++ filename, ret); +++ goto err; +++ } +++ +++ spin_lock_bh(&ar->data_lock); +++ +++ ar->testmode.utf_monitor = true; +++ +++ spin_unlock_bh(&ar->data_lock); +++ +++ BUILD_BUG_ON(sizeof(ar->fw_features) != +++ sizeof(ar->testmode.orig_fw_features)); +++ +++ memcpy(ar->testmode.orig_fw_features, ar->fw_features, +++ sizeof(ar->fw_features)); +++ ar->testmode.orig_wmi_op_version = ar->wmi.op_version; +++ +++ /* utf.bin firmware image does not advertise firmware features. Do +++ * an ugly hack where we force the firmware features so that wmi.c +++ * will use the correct WMI interface. +++ */ +++ memset(ar->fw_features, 0, sizeof(ar->fw_features)); +++ ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_1; +++ +++ ret = ath10k_hif_power_up(ar); +++ if (ret) { +++ ath10k_err(ar, "failed to power up hif (testmode): %d\n", ret); +++ ar->state = ATH10K_STATE_OFF; +++ goto err_fw_features; +++ } +++ +++ ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_UTF); +++ if (ret) { +++ ath10k_err(ar, "failed to start core (testmode): %d\n", ret); +++ ar->state = ATH10K_STATE_OFF; +++ goto err_power_down; +++ } +++ +++ ar->state = ATH10K_STATE_UTF; +++ +++ ath10k_info(ar, "UTF firmware started\n"); +++ +++ mutex_unlock(&ar->conf_mutex); +++ +++ return 0; +++ +++err_power_down: +++ ath10k_hif_power_down(ar); +++ +++err_fw_features: +++ /* return the original firmware features */ +++ memcpy(ar->fw_features, ar->testmode.orig_fw_features, +++ sizeof(ar->fw_features)); +++ ar->wmi.op_version = ar->testmode.orig_wmi_op_version; +++ +++ release_firmware(ar->testmode.utf); +++ ar->testmode.utf = NULL; +++ +++err: +++ mutex_unlock(&ar->conf_mutex); +++ +++ return ret; +++} +++ +++static void __ath10k_tm_cmd_utf_stop(struct ath10k *ar) +++{ +++ lockdep_assert_held(&ar->conf_mutex); +++ +++ ath10k_core_stop(ar); +++ ath10k_hif_power_down(ar); +++ +++ spin_lock_bh(&ar->data_lock); +++ +++ ar->testmode.utf_monitor = false; +++ +++ spin_unlock_bh(&ar->data_lock); +++ +++ /* return the original firmware features */ +++ memcpy(ar->fw_features, ar->testmode.orig_fw_features, +++ sizeof(ar->fw_features)); +++ ar->wmi.op_version = ar->testmode.orig_wmi_op_version; +++ +++ release_firmware(ar->testmode.utf); +++ ar->testmode.utf = NULL; +++ +++ ar->state = ATH10K_STATE_OFF; +++} +++ +++static int ath10k_tm_cmd_utf_stop(struct ath10k *ar, struct nlattr *tb[]) +++{ +++ int ret; +++ +++ ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf stop\n"); +++ +++ mutex_lock(&ar->conf_mutex); +++ +++ if (ar->state != ATH10K_STATE_UTF) { +++ ret = -ENETDOWN; +++ goto out; +++ } +++ +++ __ath10k_tm_cmd_utf_stop(ar); +++ +++ ret = 0; +++ +++ ath10k_info(ar, "UTF firmware stopped\n"); +++ +++out: +++ mutex_unlock(&ar->conf_mutex); +++ return ret; +++} +++ +++static int ath10k_tm_cmd_wmi(struct ath10k *ar, struct nlattr *tb[]) +++{ +++ struct sk_buff *skb; +++ int ret, buf_len; +++ u32 cmd_id; +++ void *buf; +++ +++ mutex_lock(&ar->conf_mutex); +++ +++ if (ar->state != ATH10K_STATE_UTF) { +++ ret = -ENETDOWN; +++ goto out; +++ } +++ +++ if (!tb[ATH10K_TM_ATTR_DATA]) { +++ ret = -EINVAL; +++ goto out; +++ } +++ +++ if (!tb[ATH10K_TM_ATTR_WMI_CMDID]) { +++ ret = -EINVAL; +++ goto out; +++ } +++ +++ buf = nla_data(tb[ATH10K_TM_ATTR_DATA]); +++ buf_len = nla_len(tb[ATH10K_TM_ATTR_DATA]); +++ cmd_id = nla_get_u32(tb[ATH10K_TM_ATTR_WMI_CMDID]); +++ +++ ath10k_dbg(ar, ATH10K_DBG_TESTMODE, +++ "testmode cmd wmi cmd_id %d buf %p buf_len %d\n", +++ cmd_id, buf, buf_len); +++ +++ ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", buf, buf_len); +++ +++ skb = ath10k_wmi_alloc_skb(ar, buf_len); +++ if (!skb) { +++ ret = -ENOMEM; +++ goto out; +++ } +++ +++ memcpy(skb->data, buf, buf_len); +++ +++ ret = ath10k_wmi_cmd_send(ar, skb, cmd_id); +++ if (ret) { +++ ath10k_warn(ar, "failed to transmit wmi command (testmode): %d\n", +++ ret); +++ goto out; +++ } +++ +++ ret = 0; +++ +++out: +++ mutex_unlock(&ar->conf_mutex); +++ return ret; +++} +++ +++int ath10k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +++ void *data, int len) +++{ +++ struct ath10k *ar = hw->priv; +++ struct nlattr *tb[ATH10K_TM_ATTR_MAX + 1]; +++ int ret; +++ +++ ret = nla_parse(tb, ATH10K_TM_ATTR_MAX, data, len, +++ ath10k_tm_policy); +++ if (ret) +++ return ret; +++ +++ if (!tb[ATH10K_TM_ATTR_CMD]) +++ return -EINVAL; +++ +++ switch (nla_get_u32(tb[ATH10K_TM_ATTR_CMD])) { +++ case ATH10K_TM_CMD_GET_VERSION: +++ return ath10k_tm_cmd_get_version(ar, tb); +++ case ATH10K_TM_CMD_UTF_START: +++ return ath10k_tm_cmd_utf_start(ar, tb); +++ case ATH10K_TM_CMD_UTF_STOP: +++ return ath10k_tm_cmd_utf_stop(ar, tb); +++ case ATH10K_TM_CMD_WMI: +++ return ath10k_tm_cmd_wmi(ar, tb); +++ default: +++ return -EOPNOTSUPP; +++ } +++} +++ +++void ath10k_testmode_destroy(struct ath10k *ar) +++{ +++ mutex_lock(&ar->conf_mutex); +++ +++ if (ar->state != ATH10K_STATE_UTF) { +++ /* utf firmware is not running, nothing to do */ +++ goto out; +++ } +++ +++ __ath10k_tm_cmd_utf_stop(ar); +++ +++out: +++ mutex_unlock(&ar->conf_mutex); +++} ++--- /dev/null +++++ b/drivers/net/wireless/ath/ath10k/testmode.h ++@@ -0,0 +1,46 @@ +++/* +++ * Copyright (c) 2014 Qualcomm Atheros, Inc. +++ * +++ * Permission to use, copy, modify, and/or distribute this software for any +++ * purpose with or without fee is hereby granted, provided that the above +++ * copyright notice and this permission notice appear in all copies. +++ * +++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +++ */ +++ +++#include "core.h" +++ +++#ifdef CPTCFG_NL80211_TESTMODE +++ +++void ath10k_testmode_destroy(struct ath10k *ar); +++ +++bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb); +++int ath10k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +++ void *data, int len); +++ +++#else +++ +++static inline void ath10k_testmode_destroy(struct ath10k *ar) +++{ +++} +++ +++static inline bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, +++ struct sk_buff *skb) +++{ +++ return false; +++} +++ +++static inline int ath10k_tm_cmd(struct ieee80211_hw *hw, +++ struct ieee80211_vif *vif, +++ void *data, int len) +++{ +++ return 0; +++} +++ +++#endif ++--- /dev/null +++++ b/drivers/net/wireless/ath/ath10k/testmode_i.h ++@@ -0,0 +1,70 @@ +++/* +++ * Copyright (c) 2014 Qualcomm Atheros, Inc. +++ * +++ * Permission to use, copy, modify, and/or distribute this software for any +++ * purpose with or without fee is hereby granted, provided that the above +++ * copyright notice and this permission notice appear in all copies. +++ * +++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +++ */ +++ +++/* "API" level of the ath10k testmode interface. Bump it after every +++ * incompatible interface change. +++ */ +++#define ATH10K_TESTMODE_VERSION_MAJOR 1 +++ +++/* Bump this after every _compatible_ interface change, for example +++ * addition of a new command or an attribute. +++ */ +++#define ATH10K_TESTMODE_VERSION_MINOR 0 +++ +++#define ATH10K_TM_DATA_MAX_LEN 5000 +++ +++enum ath10k_tm_attr { +++ __ATH10K_TM_ATTR_INVALID = 0, +++ ATH10K_TM_ATTR_CMD = 1, +++ ATH10K_TM_ATTR_DATA = 2, +++ ATH10K_TM_ATTR_WMI_CMDID = 3, +++ ATH10K_TM_ATTR_VERSION_MAJOR = 4, +++ ATH10K_TM_ATTR_VERSION_MINOR = 5, +++ +++ /* keep last */ +++ __ATH10K_TM_ATTR_AFTER_LAST, +++ ATH10K_TM_ATTR_MAX = __ATH10K_TM_ATTR_AFTER_LAST - 1, +++}; +++ +++/* All ath10k testmode interface commands specified in +++ * ATH10K_TM_ATTR_CMD +++ */ +++enum ath10k_tm_cmd { +++ /* Returns the supported ath10k testmode interface version in +++ * ATH10K_TM_ATTR_VERSION. Always guaranteed to work. User space +++ * uses this to verify it's using the correct version of the +++ * testmode interface +++ */ +++ ATH10K_TM_CMD_GET_VERSION = 0, +++ +++ /* Boots the UTF firmware, the netdev interface must be down at the +++ * time. +++ */ +++ ATH10K_TM_CMD_UTF_START = 1, +++ +++ /* Shuts down the UTF firmware and puts the driver back into OFF +++ * state. +++ */ +++ ATH10K_TM_CMD_UTF_STOP = 2, +++ +++ /* The command used to transmit a WMI command to the firmware and +++ * the event to receive WMI events from the firmware. Without +++ * struct wmi_cmd_hdr header, only the WMI payload. Command id is +++ * provided with ATH10K_TM_ATTR_WMI_CMDID and payload in +++ * ATH10K_TM_ATTR_DATA. +++ */ +++ ATH10K_TM_CMD_WMI = 3, +++}; ++--- /dev/null +++++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c ++@@ -0,0 +1,243 @@ +++/* +++ * Copyright (c) 2014 Qualcomm Atheros, Inc. +++ * +++ * Permission to use, copy, modify, and/or distribute this software for any +++ * purpose with or without fee is hereby granted, provided that the above +++ * copyright notice and this permission notice appear in all copies. +++ * +++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +++ */ +++ +++#include "core.h" +++#include "wmi-ops.h" +++#include "debug.h" +++ +++static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file, +++ char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ieee80211_sta *sta = file->private_data; +++ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; +++ struct ath10k *ar = arsta->arvif->ar; +++ char buf[32]; +++ int len = 0; +++ +++ mutex_lock(&ar->conf_mutex); +++ len = scnprintf(buf, sizeof(buf) - len, "aggregation mode: %s\n", +++ (arsta->aggr_mode == ATH10K_DBG_AGGR_MODE_AUTO) ? +++ "auto" : "manual"); +++ mutex_unlock(&ar->conf_mutex); +++ +++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); +++} +++ +++static ssize_t ath10k_dbg_sta_write_aggr_mode(struct file *file, +++ const char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ieee80211_sta *sta = file->private_data; +++ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; +++ struct ath10k *ar = arsta->arvif->ar; +++ u32 aggr_mode; +++ int ret; +++ +++ if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode)) +++ return -EINVAL; +++ +++ if (aggr_mode >= ATH10K_DBG_AGGR_MODE_MAX) +++ return -EINVAL; +++ +++ mutex_lock(&ar->conf_mutex); +++ if ((ar->state != ATH10K_STATE_ON) || +++ (aggr_mode == arsta->aggr_mode)) { +++ ret = count; +++ goto out; +++ } +++ +++ ret = ath10k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr); +++ if (ret) { +++ ath10k_warn(ar, "failed to clear addba session ret: %d\n", ret); +++ goto out; +++ } +++ +++ arsta->aggr_mode = aggr_mode; +++out: +++ mutex_unlock(&ar->conf_mutex); +++ return ret; +++} +++ +++static const struct file_operations fops_aggr_mode = { +++ .read = ath10k_dbg_sta_read_aggr_mode, +++ .write = ath10k_dbg_sta_write_aggr_mode, +++ .open = simple_open, +++ .owner = THIS_MODULE, +++ .llseek = default_llseek, +++}; +++ +++static ssize_t ath10k_dbg_sta_write_addba(struct file *file, +++ const char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ieee80211_sta *sta = file->private_data; +++ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; +++ struct ath10k *ar = arsta->arvif->ar; +++ u32 tid, buf_size; +++ int ret; +++ char buf[64]; +++ +++ simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); +++ +++ /* make sure that buf is null terminated */ +++ buf[sizeof(buf) - 1] = '\0'; +++ +++ ret = sscanf(buf, "%u %u", &tid, &buf_size); +++ if (ret != 2) +++ return -EINVAL; +++ +++ /* Valid TID values are 0 through 15 */ +++ if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2) +++ return -EINVAL; +++ +++ mutex_lock(&ar->conf_mutex); +++ if ((ar->state != ATH10K_STATE_ON) || +++ (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) { +++ ret = count; +++ goto out; +++ } +++ +++ ret = ath10k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr, +++ tid, buf_size); +++ if (ret) { +++ ath10k_warn(ar, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n", +++ arsta->arvif->vdev_id, sta->addr, tid, buf_size); +++ } +++ +++ ret = count; +++out: +++ mutex_unlock(&ar->conf_mutex); +++ return ret; +++} +++ +++static const struct file_operations fops_addba = { +++ .write = ath10k_dbg_sta_write_addba, +++ .open = simple_open, +++ .owner = THIS_MODULE, +++ .llseek = default_llseek, +++}; +++ +++static ssize_t ath10k_dbg_sta_write_addba_resp(struct file *file, +++ const char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ieee80211_sta *sta = file->private_data; +++ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; +++ struct ath10k *ar = arsta->arvif->ar; +++ u32 tid, status; +++ int ret; +++ char buf[64]; +++ +++ simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); +++ +++ /* make sure that buf is null terminated */ +++ buf[sizeof(buf) - 1] = '\0'; +++ +++ ret = sscanf(buf, "%u %u", &tid, &status); +++ if (ret != 2) +++ return -EINVAL; +++ +++ /* Valid TID values are 0 through 15 */ +++ if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2) +++ return -EINVAL; +++ +++ mutex_lock(&ar->conf_mutex); +++ if ((ar->state != ATH10K_STATE_ON) || +++ (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) { +++ ret = count; +++ goto out; +++ } +++ +++ ret = ath10k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr, +++ tid, status); +++ if (ret) { +++ ath10k_warn(ar, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n", +++ arsta->arvif->vdev_id, sta->addr, tid, status); +++ } +++ ret = count; +++out: +++ mutex_unlock(&ar->conf_mutex); +++ return ret; +++} +++ +++static const struct file_operations fops_addba_resp = { +++ .write = ath10k_dbg_sta_write_addba_resp, +++ .open = simple_open, +++ .owner = THIS_MODULE, +++ .llseek = default_llseek, +++}; +++ +++static ssize_t ath10k_dbg_sta_write_delba(struct file *file, +++ const char __user *user_buf, +++ size_t count, loff_t *ppos) +++{ +++ struct ieee80211_sta *sta = file->private_data; +++ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; +++ struct ath10k *ar = arsta->arvif->ar; +++ u32 tid, initiator, reason; +++ int ret; +++ char buf[64]; +++ +++ simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); +++ +++ /* make sure that buf is null terminated */ +++ buf[sizeof(buf) - 1] = '\0'; +++ +++ ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason); +++ if (ret != 3) +++ return -EINVAL; +++ +++ /* Valid TID values are 0 through 15 */ +++ if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2) +++ return -EINVAL; +++ +++ mutex_lock(&ar->conf_mutex); +++ if ((ar->state != ATH10K_STATE_ON) || +++ (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) { +++ ret = count; +++ goto out; +++ } +++ +++ ret = ath10k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr, +++ tid, initiator, reason); +++ if (ret) { +++ ath10k_warn(ar, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n", +++ arsta->arvif->vdev_id, sta->addr, tid, initiator, +++ reason); +++ } +++ ret = count; +++out: +++ mutex_unlock(&ar->conf_mutex); +++ return ret; +++} +++ +++static const struct file_operations fops_delba = { +++ .write = ath10k_dbg_sta_write_delba, +++ .open = simple_open, +++ .owner = THIS_MODULE, +++ .llseek = default_llseek, +++}; +++ +++void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +++ struct ieee80211_sta *sta, struct dentry *dir) +++{ +++ debugfs_create_file("aggr_mode", S_IRUGO | S_IWUSR, dir, sta, +++ &fops_aggr_mode); +++ debugfs_create_file("addba", S_IWUSR, dir, sta, &fops_addba); +++ debugfs_create_file("addba_resp", S_IWUSR, dir, sta, &fops_addba_resp); +++ debugfs_create_file("delba", S_IWUSR, dir, sta, &fops_delba); +++} ++--- /dev/null +++++ b/drivers/net/wireless/ath/ath10k/hw.c ++@@ -0,0 +1,58 @@ +++/* +++ * Copyright (c) 2014-2015 Qualcomm Atheros, Inc. +++ * +++ * Permission to use, copy, modify, and/or distribute this software for any +++ * purpose with or without fee is hereby granted, provided that the above +++ * copyright notice and this permission notice appear in all copies. +++ * +++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +++ */ +++ +++#include +++#include "hw.h" +++ +++const struct ath10k_hw_regs qca988x_regs = { +++ .rtc_state_cold_reset_mask = 0x00000400, +++ .rtc_soc_base_address = 0x00004000, +++ .rtc_wmac_base_address = 0x00005000, +++ .soc_core_base_address = 0x00009000, +++ .ce_wrapper_base_address = 0x00057000, +++ .ce0_base_address = 0x00057400, +++ .ce1_base_address = 0x00057800, +++ .ce2_base_address = 0x00057c00, +++ .ce3_base_address = 0x00058000, +++ .ce4_base_address = 0x00058400, +++ .ce5_base_address = 0x00058800, +++ .ce6_base_address = 0x00058c00, +++ .ce7_base_address = 0x00059000, +++ .soc_reset_control_si0_rst_mask = 0x00000001, +++ .soc_reset_control_ce_rst_mask = 0x00040000, +++ .soc_chip_id_address = 0x00ec, +++ .scratch_3_address = 0x0030, +++}; +++ +++const struct ath10k_hw_regs qca6174_regs = { +++ .rtc_state_cold_reset_mask = 0x00002000, +++ .rtc_soc_base_address = 0x00000800, +++ .rtc_wmac_base_address = 0x00001000, +++ .soc_core_base_address = 0x0003a000, +++ .ce_wrapper_base_address = 0x00034000, +++ .ce0_base_address = 0x00034400, +++ .ce1_base_address = 0x00034800, +++ .ce2_base_address = 0x00034c00, +++ .ce3_base_address = 0x00035000, +++ .ce4_base_address = 0x00035400, +++ .ce5_base_address = 0x00035800, +++ .ce6_base_address = 0x00035c00, +++ .ce7_base_address = 0x00036000, +++ .soc_reset_control_si0_rst_mask = 0x00000000, +++ .soc_reset_control_ce_rst_mask = 0x00000001, +++ .soc_chip_id_address = 0x000f0, +++ .scratch_3_address = 0x0028, +++}; ++--- /dev/null +++++ b/drivers/net/wireless/ath/ath10k/thermal.c ++@@ -0,0 +1,244 @@ +++/* +++ * Copyright (c) 2014 Qualcomm Atheros, Inc. +++ * +++ * Permission to use, copy, modify, and/or distribute this software for any +++ * purpose with or without fee is hereby granted, provided that the above +++ * copyright notice and this permission notice appear in all copies. +++ * +++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +++ */ +++ +++#include +++#include +++#include +++#include +++#include +++#include "core.h" +++#include "debug.h" +++#include "wmi-ops.h" +++ +++static int ath10k_thermal_get_active_vifs(struct ath10k *ar, +++ enum wmi_vdev_type type) +++{ +++ struct ath10k_vif *arvif; +++ int count = 0; +++ +++ lockdep_assert_held(&ar->conf_mutex); +++ +++ list_for_each_entry(arvif, &ar->arvifs, list) { +++ if (!arvif->is_started) +++ continue; +++ +++ if (!arvif->is_up) +++ continue; +++ +++ if (arvif->vdev_type != type) +++ continue; +++ +++ count++; +++ } +++ return count; +++} +++ +++static int ath10k_thermal_get_max_dutycycle(struct thermal_cooling_device *cdev, +++ unsigned long *state) +++{ +++ *state = ATH10K_QUIET_DUTY_CYCLE_MAX; +++ +++ return 0; +++} +++ +++static int ath10k_thermal_get_cur_dutycycle(struct thermal_cooling_device *cdev, +++ unsigned long *state) +++{ +++ struct ath10k *ar = cdev->devdata; +++ +++ mutex_lock(&ar->conf_mutex); +++ *state = ar->thermal.duty_cycle; +++ mutex_unlock(&ar->conf_mutex); +++ +++ return 0; +++} +++ +++static int ath10k_thermal_set_cur_dutycycle(struct thermal_cooling_device *cdev, +++ unsigned long duty_cycle) +++{ +++ struct ath10k *ar = cdev->devdata; +++ u32 period, duration, enabled; +++ int num_bss, ret = 0; +++ +++ mutex_lock(&ar->conf_mutex); +++ if (ar->state != ATH10K_STATE_ON) { +++ ret = -ENETDOWN; +++ goto out; +++ } +++ +++ if (duty_cycle > ATH10K_QUIET_DUTY_CYCLE_MAX) { +++ ath10k_warn(ar, "duty cycle %ld is exceeding the limit %d\n", +++ duty_cycle, ATH10K_QUIET_DUTY_CYCLE_MAX); +++ ret = -EINVAL; +++ goto out; +++ } +++ /* TODO: Right now, thermal mitigation is handled only for single/multi +++ * vif AP mode. Since quiet param is not validated in STA mode, it needs +++ * to be investigated further to handle multi STA and multi-vif (AP+STA) +++ * mode properly. +++ */ +++ num_bss = ath10k_thermal_get_active_vifs(ar, WMI_VDEV_TYPE_AP); +++ if (!num_bss) { +++ ath10k_warn(ar, "no active AP interfaces\n"); +++ ret = -ENETDOWN; +++ goto out; +++ } +++ period = max(ATH10K_QUIET_PERIOD_MIN, +++ (ATH10K_QUIET_PERIOD_DEFAULT / num_bss)); +++ duration = (period * duty_cycle) / 100; +++ enabled = duration ? 1 : 0; +++ +++ ret = ath10k_wmi_pdev_set_quiet_mode(ar, period, duration, +++ ATH10K_QUIET_START_OFFSET, +++ enabled); +++ if (ret) { +++ ath10k_warn(ar, "failed to set quiet mode period %u duarion %u enabled %u ret %d\n", +++ period, duration, enabled, ret); +++ goto out; +++ } +++ ar->thermal.duty_cycle = duty_cycle; +++out: +++ mutex_unlock(&ar->conf_mutex); +++ return ret; +++} +++ +++static struct thermal_cooling_device_ops ath10k_thermal_ops = { +++ .get_max_state = ath10k_thermal_get_max_dutycycle, +++ .get_cur_state = ath10k_thermal_get_cur_dutycycle, +++ .set_cur_state = ath10k_thermal_set_cur_dutycycle, +++}; +++ +++static ssize_t ath10k_thermal_show_temp(struct device *dev, +++ struct device_attribute *attr, +++ char *buf) +++{ +++ struct ath10k *ar = dev_get_drvdata(dev); +++ int ret, temperature; +++ +++ mutex_lock(&ar->conf_mutex); +++ +++ /* Can't get temperature when the card is off */ +++ if (ar->state != ATH10K_STATE_ON) { +++ ret = -ENETDOWN; +++ goto out; +++ } +++ +++ reinit_completion(&ar->thermal.wmi_sync); +++ ret = ath10k_wmi_pdev_get_temperature(ar); +++ if (ret) { +++ ath10k_warn(ar, "failed to read temperature %d\n", ret); +++ goto out; +++ } +++ +++ if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) { +++ ret = -ESHUTDOWN; +++ goto out; +++ } +++ +++ ret = wait_for_completion_timeout(&ar->thermal.wmi_sync, +++ ATH10K_THERMAL_SYNC_TIMEOUT_HZ); +++ if (ret == 0) { +++ ath10k_warn(ar, "failed to synchronize thermal read\n"); +++ ret = -ETIMEDOUT; +++ goto out; +++ } +++ +++ spin_lock_bh(&ar->data_lock); +++ temperature = ar->thermal.temperature; +++ spin_unlock_bh(&ar->data_lock); +++ +++ /* display in millidegree celcius */ +++ ret = snprintf(buf, PAGE_SIZE, "%d\n", temperature * 1000); +++out: +++ mutex_unlock(&ar->conf_mutex); +++ return ret; +++} +++ +++void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature) +++{ +++ spin_lock_bh(&ar->data_lock); +++ ar->thermal.temperature = temperature; +++ spin_unlock_bh(&ar->data_lock); +++ complete(&ar->thermal.wmi_sync); +++} +++ +++static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ath10k_thermal_show_temp, +++ NULL, 0); +++ +++static struct attribute *ath10k_hwmon_attrs[] = { +++ &sensor_dev_attr_temp1_input.dev_attr.attr, +++ NULL, +++}; +++ATTRIBUTE_GROUPS(ath10k_hwmon); +++ +++int ath10k_thermal_register(struct ath10k *ar) +++{ +++ struct thermal_cooling_device *cdev; +++ struct device *hwmon_dev; +++ int ret; +++ +++ cdev = thermal_cooling_device_register("ath10k_thermal", ar, +++ &ath10k_thermal_ops); +++ +++ if (IS_ERR(cdev)) { +++ ath10k_err(ar, "failed to setup thermal device result: %ld\n", +++ PTR_ERR(cdev)); +++ return -EINVAL; +++ } +++ +++ ret = sysfs_create_link(&ar->dev->kobj, &cdev->device.kobj, +++ "cooling_device"); +++ if (ret) { +++ ath10k_err(ar, "failed to create thermal symlink\n"); +++ goto err_cooling_destroy; +++ } +++ +++ ar->thermal.cdev = cdev; +++ +++ /* Do not register hwmon device when temperature reading is not +++ * supported by firmware +++ */ +++ if (ar->wmi.op_version != ATH10K_FW_WMI_OP_VERSION_10_2_4) +++ return 0; +++ +++ /* Avoid linking error on devm_hwmon_device_register_with_groups, I +++ * guess linux/hwmon.h is missing proper stubs. */ +++ if (!config_enabled(CONFIG_HWMON)) +++ return 0; +++ +++ hwmon_dev = devm_hwmon_device_register_with_groups(ar->dev, +++ "ath10k_hwmon", ar, +++ ath10k_hwmon_groups); +++ if (IS_ERR(hwmon_dev)) { +++ ath10k_err(ar, "failed to register hwmon device: %ld\n", +++ PTR_ERR(hwmon_dev)); +++ ret = -EINVAL; +++ goto err_remove_link; +++ } +++ return 0; +++ +++err_remove_link: +++ sysfs_remove_link(&ar->dev->kobj, "thermal_sensor"); +++err_cooling_destroy: +++ thermal_cooling_device_unregister(cdev); +++ return ret; +++} +++ +++void ath10k_thermal_unregister(struct ath10k *ar) +++{ +++ thermal_cooling_device_unregister(ar->thermal.cdev); +++ sysfs_remove_link(&ar->dev->kobj, "cooling_device"); +++} ++--- /dev/null +++++ b/drivers/net/wireless/ath/ath10k/thermal.h ++@@ -0,0 +1,58 @@ +++/* +++ * Copyright (c) 2014 Qualcomm Atheros, Inc. +++ * +++ * Permission to use, copy, modify, and/or distribute this software for any +++ * purpose with or without fee is hereby granted, provided that the above +++ * copyright notice and this permission notice appear in all copies. +++ * +++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +++ */ +++#ifndef _THERMAL_ +++#define _THERMAL_ +++ +++#define ATH10K_QUIET_PERIOD_DEFAULT 100 +++#define ATH10K_QUIET_PERIOD_MIN 25 +++#define ATH10K_QUIET_START_OFFSET 10 +++#define ATH10K_QUIET_DUTY_CYCLE_MAX 70 +++#define ATH10K_HWMON_NAME_LEN 15 +++#define ATH10K_THERMAL_SYNC_TIMEOUT_HZ (5*HZ) +++ +++struct ath10k_thermal { +++ struct thermal_cooling_device *cdev; +++ struct completion wmi_sync; +++ +++ /* protected by conf_mutex */ +++ u32 duty_cycle; +++ /* temperature value in Celcius degree +++ * protected by data_lock +++ */ +++ int temperature; +++}; +++ +++#ifdef CONFIG_THERMAL +++int ath10k_thermal_register(struct ath10k *ar); +++void ath10k_thermal_unregister(struct ath10k *ar); +++void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature); +++#else +++static inline int ath10k_thermal_register(struct ath10k *ar) +++{ +++ return 0; +++} +++ +++static inline void ath10k_thermal_unregister(struct ath10k *ar) +++{ +++} +++ +++static inline void ath10k_thermal_event_temperature(struct ath10k *ar, +++ int temperature) +++{ +++} +++ +++#endif +++#endif /* _THERMAL_ */ ++--- /dev/null +++++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h ++@@ -0,0 +1,1063 @@ +++/* +++ * Copyright (c) 2005-2011 Atheros Communications Inc. +++ * Copyright (c) 2011-2014 Qualcomm Atheros, Inc. +++ * +++ * Permission to use, copy, modify, and/or distribute this software for any +++ * purpose with or without fee is hereby granted, provided that the above +++ * copyright notice and this permission notice appear in all copies. +++ * +++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +++ */ +++ +++#ifndef _WMI_OPS_H_ +++#define _WMI_OPS_H_ +++ +++struct ath10k; +++struct sk_buff; +++ +++struct wmi_ops { +++ void (*rx)(struct ath10k *ar, struct sk_buff *skb); +++ void (*map_svc)(const __le32 *in, unsigned long *out, size_t len); +++ +++ int (*pull_scan)(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_scan_ev_arg *arg); +++ int (*pull_mgmt_rx)(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_mgmt_rx_ev_arg *arg); +++ int (*pull_ch_info)(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_ch_info_ev_arg *arg); +++ int (*pull_vdev_start)(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_vdev_start_ev_arg *arg); +++ int (*pull_peer_kick)(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_peer_kick_ev_arg *arg); +++ int (*pull_swba)(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_swba_ev_arg *arg); +++ int (*pull_phyerr)(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_phyerr_ev_arg *arg); +++ int (*pull_svc_rdy)(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_svc_rdy_ev_arg *arg); +++ int (*pull_rdy)(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_rdy_ev_arg *arg); +++ int (*pull_fw_stats)(struct ath10k *ar, struct sk_buff *skb, +++ struct ath10k_fw_stats *stats); +++ +++ struct sk_buff *(*gen_pdev_suspend)(struct ath10k *ar, u32 suspend_opt); +++ struct sk_buff *(*gen_pdev_resume)(struct ath10k *ar); +++ struct sk_buff *(*gen_pdev_set_rd)(struct ath10k *ar, u16 rd, u16 rd2g, +++ u16 rd5g, u16 ctl2g, u16 ctl5g, +++ enum wmi_dfs_region dfs_reg); +++ struct sk_buff *(*gen_pdev_set_param)(struct ath10k *ar, u32 id, +++ u32 value); +++ struct sk_buff *(*gen_init)(struct ath10k *ar); +++ struct sk_buff *(*gen_start_scan)(struct ath10k *ar, +++ const struct wmi_start_scan_arg *arg); +++ struct sk_buff *(*gen_stop_scan)(struct ath10k *ar, +++ const struct wmi_stop_scan_arg *arg); +++ struct sk_buff *(*gen_vdev_create)(struct ath10k *ar, u32 vdev_id, +++ enum wmi_vdev_type type, +++ enum wmi_vdev_subtype subtype, +++ const u8 macaddr[ETH_ALEN]); +++ struct sk_buff *(*gen_vdev_delete)(struct ath10k *ar, u32 vdev_id); +++ struct sk_buff *(*gen_vdev_start)(struct ath10k *ar, +++ const struct wmi_vdev_start_request_arg *arg, +++ bool restart); +++ struct sk_buff *(*gen_vdev_stop)(struct ath10k *ar, u32 vdev_id); +++ struct sk_buff *(*gen_vdev_up)(struct ath10k *ar, u32 vdev_id, u32 aid, +++ const u8 *bssid); +++ struct sk_buff *(*gen_vdev_down)(struct ath10k *ar, u32 vdev_id); +++ struct sk_buff *(*gen_vdev_set_param)(struct ath10k *ar, u32 vdev_id, +++ u32 param_id, u32 param_value); +++ struct sk_buff *(*gen_vdev_install_key)(struct ath10k *ar, +++ const struct wmi_vdev_install_key_arg *arg); +++ struct sk_buff *(*gen_vdev_spectral_conf)(struct ath10k *ar, +++ const struct wmi_vdev_spectral_conf_arg *arg); +++ struct sk_buff *(*gen_vdev_spectral_enable)(struct ath10k *ar, u32 vdev_id, +++ u32 trigger, u32 enable); +++ struct sk_buff *(*gen_vdev_wmm_conf)(struct ath10k *ar, u32 vdev_id, +++ const struct wmi_wmm_params_all_arg *arg); +++ struct sk_buff *(*gen_peer_create)(struct ath10k *ar, u32 vdev_id, +++ const u8 peer_addr[ETH_ALEN]); +++ struct sk_buff *(*gen_peer_delete)(struct ath10k *ar, u32 vdev_id, +++ const u8 peer_addr[ETH_ALEN]); +++ struct sk_buff *(*gen_peer_flush)(struct ath10k *ar, u32 vdev_id, +++ const u8 peer_addr[ETH_ALEN], +++ u32 tid_bitmap); +++ struct sk_buff *(*gen_peer_set_param)(struct ath10k *ar, u32 vdev_id, +++ const u8 *peer_addr, +++ enum wmi_peer_param param_id, +++ u32 param_value); +++ struct sk_buff *(*gen_peer_assoc)(struct ath10k *ar, +++ const struct wmi_peer_assoc_complete_arg *arg); +++ struct sk_buff *(*gen_set_psmode)(struct ath10k *ar, u32 vdev_id, +++ enum wmi_sta_ps_mode psmode); +++ struct sk_buff *(*gen_set_sta_ps)(struct ath10k *ar, u32 vdev_id, +++ enum wmi_sta_powersave_param param_id, +++ u32 value); +++ struct sk_buff *(*gen_set_ap_ps)(struct ath10k *ar, u32 vdev_id, +++ const u8 *mac, +++ enum wmi_ap_ps_peer_param param_id, +++ u32 value); +++ struct sk_buff *(*gen_scan_chan_list)(struct ath10k *ar, +++ const struct wmi_scan_chan_list_arg *arg); +++ struct sk_buff *(*gen_beacon_dma)(struct ath10k *ar, u32 vdev_id, +++ const void *bcn, size_t bcn_len, +++ u32 bcn_paddr, bool dtim_zero, +++ bool deliver_cab); +++ struct sk_buff *(*gen_pdev_set_wmm)(struct ath10k *ar, +++ const struct wmi_wmm_params_all_arg *arg); +++ struct sk_buff *(*gen_request_stats)(struct ath10k *ar, u32 stats_mask); +++ struct sk_buff *(*gen_force_fw_hang)(struct ath10k *ar, +++ enum wmi_force_fw_hang_type type, +++ u32 delay_ms); +++ struct sk_buff *(*gen_mgmt_tx)(struct ath10k *ar, struct sk_buff *skb); +++ struct sk_buff *(*gen_dbglog_cfg)(struct ath10k *ar, u32 module_enable, +++ u32 log_level); +++ struct sk_buff *(*gen_pktlog_enable)(struct ath10k *ar, u32 filter); +++ struct sk_buff *(*gen_pktlog_disable)(struct ath10k *ar); +++ struct sk_buff *(*gen_pdev_set_quiet_mode)(struct ath10k *ar, +++ u32 period, u32 duration, +++ u32 next_offset, +++ u32 enabled); +++ struct sk_buff *(*gen_pdev_get_temperature)(struct ath10k *ar); +++ struct sk_buff *(*gen_addba_clear_resp)(struct ath10k *ar, u32 vdev_id, +++ const u8 *mac); +++ struct sk_buff *(*gen_addba_send)(struct ath10k *ar, u32 vdev_id, +++ const u8 *mac, u32 tid, u32 buf_size); +++ struct sk_buff *(*gen_addba_set_resp)(struct ath10k *ar, u32 vdev_id, +++ const u8 *mac, u32 tid, +++ u32 status); +++ struct sk_buff *(*gen_delba_send)(struct ath10k *ar, u32 vdev_id, +++ const u8 *mac, u32 tid, u32 initiator, +++ u32 reason); +++ struct sk_buff *(*gen_bcn_tmpl)(struct ath10k *ar, u32 vdev_id, +++ u32 tim_ie_offset, struct sk_buff *bcn, +++ u32 prb_caps, u32 prb_erp, +++ void *prb_ies, size_t prb_ies_len); +++ struct sk_buff *(*gen_prb_tmpl)(struct ath10k *ar, u32 vdev_id, +++ struct sk_buff *bcn); +++ struct sk_buff *(*gen_p2p_go_bcn_ie)(struct ath10k *ar, u32 vdev_id, +++ const u8 *p2p_ie); +++ struct sk_buff *(*gen_vdev_sta_uapsd)(struct ath10k *ar, u32 vdev_id, +++ const u8 peer_addr[ETH_ALEN], +++ const struct wmi_sta_uapsd_auto_trig_arg *args, +++ u32 num_ac); +++ struct sk_buff *(*gen_sta_keepalive)(struct ath10k *ar, +++ const struct wmi_sta_keepalive_arg *arg); +++}; +++ +++int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); +++ +++static inline int +++ath10k_wmi_rx(struct ath10k *ar, struct sk_buff *skb) +++{ +++ if (WARN_ON_ONCE(!ar->wmi.ops->rx)) +++ return -EOPNOTSUPP; +++ +++ ar->wmi.ops->rx(ar, skb); +++ return 0; +++} +++ +++static inline int +++ath10k_wmi_map_svc(struct ath10k *ar, const __le32 *in, unsigned long *out, +++ size_t len) +++{ +++ if (!ar->wmi.ops->map_svc) +++ return -EOPNOTSUPP; +++ +++ ar->wmi.ops->map_svc(in, out, len); +++ return 0; +++} +++ +++static inline int +++ath10k_wmi_pull_scan(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_scan_ev_arg *arg) +++{ +++ if (!ar->wmi.ops->pull_scan) +++ return -EOPNOTSUPP; +++ +++ return ar->wmi.ops->pull_scan(ar, skb, arg); +++} +++ +++static inline int +++ath10k_wmi_pull_mgmt_rx(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_mgmt_rx_ev_arg *arg) +++{ +++ if (!ar->wmi.ops->pull_mgmt_rx) +++ return -EOPNOTSUPP; +++ +++ return ar->wmi.ops->pull_mgmt_rx(ar, skb, arg); +++} +++ +++static inline int +++ath10k_wmi_pull_ch_info(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_ch_info_ev_arg *arg) +++{ +++ if (!ar->wmi.ops->pull_ch_info) +++ return -EOPNOTSUPP; +++ +++ return ar->wmi.ops->pull_ch_info(ar, skb, arg); +++} +++ +++static inline int +++ath10k_wmi_pull_vdev_start(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_vdev_start_ev_arg *arg) +++{ +++ if (!ar->wmi.ops->pull_vdev_start) +++ return -EOPNOTSUPP; +++ +++ return ar->wmi.ops->pull_vdev_start(ar, skb, arg); +++} +++ +++static inline int +++ath10k_wmi_pull_peer_kick(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_peer_kick_ev_arg *arg) +++{ +++ if (!ar->wmi.ops->pull_peer_kick) +++ return -EOPNOTSUPP; +++ +++ return ar->wmi.ops->pull_peer_kick(ar, skb, arg); +++} +++ +++static inline int +++ath10k_wmi_pull_swba(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_swba_ev_arg *arg) +++{ +++ if (!ar->wmi.ops->pull_swba) +++ return -EOPNOTSUPP; +++ +++ return ar->wmi.ops->pull_swba(ar, skb, arg); +++} +++ +++static inline int +++ath10k_wmi_pull_phyerr(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_phyerr_ev_arg *arg) +++{ +++ if (!ar->wmi.ops->pull_phyerr) +++ return -EOPNOTSUPP; +++ +++ return ar->wmi.ops->pull_phyerr(ar, skb, arg); +++} +++ +++static inline int +++ath10k_wmi_pull_svc_rdy(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_svc_rdy_ev_arg *arg) +++{ +++ if (!ar->wmi.ops->pull_svc_rdy) +++ return -EOPNOTSUPP; +++ +++ return ar->wmi.ops->pull_svc_rdy(ar, skb, arg); +++} +++ +++static inline int +++ath10k_wmi_pull_rdy(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_rdy_ev_arg *arg) +++{ +++ if (!ar->wmi.ops->pull_rdy) +++ return -EOPNOTSUPP; +++ +++ return ar->wmi.ops->pull_rdy(ar, skb, arg); +++} +++ +++static inline int +++ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb, +++ struct ath10k_fw_stats *stats) +++{ +++ if (!ar->wmi.ops->pull_fw_stats) +++ return -EOPNOTSUPP; +++ +++ return ar->wmi.ops->pull_fw_stats(ar, skb, stats); +++} +++ +++static inline int +++ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) +++{ +++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu); +++ struct sk_buff *skb; +++ int ret; +++ +++ if (!ar->wmi.ops->gen_mgmt_tx) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_mgmt_tx(ar, msdu); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ ret = ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->mgmt_tx_cmdid); +++ if (ret) +++ return ret; +++ +++ /* FIXME There's no ACK event for Management Tx. This probably +++ * shouldn't be called here either. */ +++ info->flags |= IEEE80211_TX_STAT_ACK; +++ ieee80211_tx_status_irqsafe(ar->hw, msdu); +++ +++ return 0; +++} +++ +++static inline int +++ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, u16 rd5g, +++ u16 ctl2g, u16 ctl5g, +++ enum wmi_dfs_region dfs_reg) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_pdev_set_rd) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_pdev_set_rd(ar, rd, rd2g, rd5g, ctl2g, ctl5g, +++ dfs_reg); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, +++ ar->wmi.cmd->pdev_set_regdomain_cmdid); +++} +++ +++static inline int +++ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_pdev_suspend) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_pdev_suspend(ar, suspend_opt); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_suspend_cmdid); +++} +++ +++static inline int +++ath10k_wmi_pdev_resume_target(struct ath10k *ar) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_pdev_resume) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_pdev_resume(ar); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_resume_cmdid); +++} +++ +++static inline int +++ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_pdev_set_param) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_pdev_set_param(ar, id, value); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_param_cmdid); +++} +++ +++static inline int +++ath10k_wmi_cmd_init(struct ath10k *ar) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_init) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_init(ar); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->init_cmdid); +++} +++ +++static inline int +++ath10k_wmi_start_scan(struct ath10k *ar, +++ const struct wmi_start_scan_arg *arg) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_start_scan) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_start_scan(ar, arg); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->start_scan_cmdid); +++} +++ +++static inline int +++ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_stop_scan) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_stop_scan(ar, arg); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->stop_scan_cmdid); +++} +++ +++static inline int +++ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id, +++ enum wmi_vdev_type type, +++ enum wmi_vdev_subtype subtype, +++ const u8 macaddr[ETH_ALEN]) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_vdev_create) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_vdev_create(ar, vdev_id, type, subtype, macaddr); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_create_cmdid); +++} +++ +++static inline int +++ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_vdev_delete) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_vdev_delete(ar, vdev_id); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_delete_cmdid); +++} +++ +++static inline int +++ath10k_wmi_vdev_start(struct ath10k *ar, +++ const struct wmi_vdev_start_request_arg *arg) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_vdev_start) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_vdev_start(ar, arg, false); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, +++ ar->wmi.cmd->vdev_start_request_cmdid); +++} +++ +++static inline int +++ath10k_wmi_vdev_restart(struct ath10k *ar, +++ const struct wmi_vdev_start_request_arg *arg) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_vdev_start) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_vdev_start(ar, arg, true); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, +++ ar->wmi.cmd->vdev_restart_request_cmdid); +++} +++ +++static inline int +++ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_vdev_stop) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_vdev_stop(ar, vdev_id); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_stop_cmdid); +++} +++ +++static inline int +++ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_vdev_up) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_vdev_up(ar, vdev_id, aid, bssid); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_up_cmdid); +++} +++ +++static inline int +++ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_vdev_down) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_vdev_down(ar, vdev_id); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_down_cmdid); +++} +++ +++static inline int +++ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id, u32 param_id, +++ u32 param_value) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_vdev_set_param) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_vdev_set_param(ar, vdev_id, param_id, +++ param_value); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_set_param_cmdid); +++} +++ +++static inline int +++ath10k_wmi_vdev_install_key(struct ath10k *ar, +++ const struct wmi_vdev_install_key_arg *arg) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_vdev_install_key) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_vdev_install_key(ar, arg); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, +++ ar->wmi.cmd->vdev_install_key_cmdid); +++} +++ +++static inline int +++ath10k_wmi_vdev_spectral_conf(struct ath10k *ar, +++ const struct wmi_vdev_spectral_conf_arg *arg) +++{ +++ struct sk_buff *skb; +++ u32 cmd_id; +++ +++ skb = ar->wmi.ops->gen_vdev_spectral_conf(ar, arg); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ cmd_id = ar->wmi.cmd->vdev_spectral_scan_configure_cmdid; +++ return ath10k_wmi_cmd_send(ar, skb, cmd_id); +++} +++ +++static inline int +++ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger, +++ u32 enable) +++{ +++ struct sk_buff *skb; +++ u32 cmd_id; +++ +++ skb = ar->wmi.ops->gen_vdev_spectral_enable(ar, vdev_id, trigger, +++ enable); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ cmd_id = ar->wmi.cmd->vdev_spectral_scan_enable_cmdid; +++ return ath10k_wmi_cmd_send(ar, skb, cmd_id); +++} +++ +++static inline int +++ath10k_wmi_vdev_sta_uapsd(struct ath10k *ar, u32 vdev_id, +++ const u8 peer_addr[ETH_ALEN], +++ const struct wmi_sta_uapsd_auto_trig_arg *args, +++ u32 num_ac) +++{ +++ struct sk_buff *skb; +++ u32 cmd_id; +++ +++ if (!ar->wmi.ops->gen_vdev_sta_uapsd) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_vdev_sta_uapsd(ar, vdev_id, peer_addr, args, +++ num_ac); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ cmd_id = ar->wmi.cmd->sta_uapsd_auto_trig_cmdid; +++ return ath10k_wmi_cmd_send(ar, skb, cmd_id); +++} +++ +++static inline int +++ath10k_wmi_vdev_wmm_conf(struct ath10k *ar, u32 vdev_id, +++ const struct wmi_wmm_params_all_arg *arg) +++{ +++ struct sk_buff *skb; +++ u32 cmd_id; +++ +++ skb = ar->wmi.ops->gen_vdev_wmm_conf(ar, vdev_id, arg); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ cmd_id = ar->wmi.cmd->vdev_set_wmm_params_cmdid; +++ return ath10k_wmi_cmd_send(ar, skb, cmd_id); +++} +++ +++static inline int +++ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id, +++ const u8 peer_addr[ETH_ALEN]) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_peer_create) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_peer_create(ar, vdev_id, peer_addr); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_create_cmdid); +++} +++ +++static inline int +++ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id, +++ const u8 peer_addr[ETH_ALEN]) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_peer_delete) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_peer_delete(ar, vdev_id, peer_addr); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_delete_cmdid); +++} +++ +++static inline int +++ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id, +++ const u8 peer_addr[ETH_ALEN], u32 tid_bitmap) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_peer_flush) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_peer_flush(ar, vdev_id, peer_addr, tid_bitmap); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_flush_tids_cmdid); +++} +++ +++static inline int +++ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id, const u8 *peer_addr, +++ enum wmi_peer_param param_id, u32 param_value) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_peer_set_param) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_peer_set_param(ar, vdev_id, peer_addr, param_id, +++ param_value); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_set_param_cmdid); +++} +++ +++static inline int +++ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id, +++ enum wmi_sta_ps_mode psmode) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_set_psmode) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_set_psmode(ar, vdev_id, psmode); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, +++ ar->wmi.cmd->sta_powersave_mode_cmdid); +++} +++ +++static inline int +++ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id, +++ enum wmi_sta_powersave_param param_id, u32 value) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_set_sta_ps) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_set_sta_ps(ar, vdev_id, param_id, value); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, +++ ar->wmi.cmd->sta_powersave_param_cmdid); +++} +++ +++static inline int +++ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac, +++ enum wmi_ap_ps_peer_param param_id, u32 value) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_set_ap_ps) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_set_ap_ps(ar, vdev_id, mac, param_id, value); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, +++ ar->wmi.cmd->ap_ps_peer_param_cmdid); +++} +++ +++static inline int +++ath10k_wmi_scan_chan_list(struct ath10k *ar, +++ const struct wmi_scan_chan_list_arg *arg) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_scan_chan_list) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_scan_chan_list(ar, arg); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid); +++} +++ +++static inline int +++ath10k_wmi_peer_assoc(struct ath10k *ar, +++ const struct wmi_peer_assoc_complete_arg *arg) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_peer_assoc) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_peer_assoc(ar, arg); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid); +++} +++ +++static inline int +++ath10k_wmi_beacon_send_ref_nowait(struct ath10k *ar, u32 vdev_id, +++ const void *bcn, size_t bcn_len, +++ u32 bcn_paddr, bool dtim_zero, +++ bool deliver_cab) +++{ +++ struct sk_buff *skb; +++ int ret; +++ +++ if (!ar->wmi.ops->gen_beacon_dma) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_beacon_dma(ar, vdev_id, bcn, bcn_len, bcn_paddr, +++ dtim_zero, deliver_cab); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ ret = ath10k_wmi_cmd_send_nowait(ar, skb, +++ ar->wmi.cmd->pdev_send_bcn_cmdid); +++ if (ret) { +++ dev_kfree_skb(skb); +++ return ret; +++ } +++ +++ return 0; +++} +++ +++static inline int +++ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, +++ const struct wmi_wmm_params_all_arg *arg) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_pdev_set_wmm) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_pdev_set_wmm(ar, arg); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, +++ ar->wmi.cmd->pdev_set_wmm_params_cmdid); +++} +++ +++static inline int +++ath10k_wmi_request_stats(struct ath10k *ar, u32 stats_mask) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_request_stats) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_request_stats(ar, stats_mask); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_stats_cmdid); +++} +++ +++static inline int +++ath10k_wmi_force_fw_hang(struct ath10k *ar, +++ enum wmi_force_fw_hang_type type, u32 delay_ms) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_force_fw_hang) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_force_fw_hang(ar, type, delay_ms); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid); +++} +++ +++static inline int +++ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable, u32 log_level) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_dbglog_cfg) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_dbglog_cfg(ar, module_enable, log_level); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->dbglog_cfg_cmdid); +++} +++ +++static inline int +++ath10k_wmi_pdev_pktlog_enable(struct ath10k *ar, u32 filter) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_pktlog_enable) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_pktlog_enable(ar, filter); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_pktlog_enable_cmdid); +++} +++ +++static inline int +++ath10k_wmi_pdev_pktlog_disable(struct ath10k *ar) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_pktlog_disable) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_pktlog_disable(ar); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, +++ ar->wmi.cmd->pdev_pktlog_disable_cmdid); +++} +++ +++static inline int +++ath10k_wmi_pdev_set_quiet_mode(struct ath10k *ar, u32 period, u32 duration, +++ u32 next_offset, u32 enabled) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_pdev_set_quiet_mode) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_pdev_set_quiet_mode(ar, period, duration, +++ next_offset, enabled); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, +++ ar->wmi.cmd->pdev_set_quiet_mode_cmdid); +++} +++ +++static inline int +++ath10k_wmi_pdev_get_temperature(struct ath10k *ar) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_pdev_get_temperature) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_pdev_get_temperature(ar); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, +++ ar->wmi.cmd->pdev_get_temperature_cmdid); +++} +++ +++static inline int +++ath10k_wmi_addba_clear_resp(struct ath10k *ar, u32 vdev_id, const u8 *mac) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_addba_clear_resp) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_addba_clear_resp(ar, vdev_id, mac); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, +++ ar->wmi.cmd->addba_clear_resp_cmdid); +++} +++ +++static inline int +++ath10k_wmi_addba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac, +++ u32 tid, u32 buf_size) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_addba_send) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_addba_send(ar, vdev_id, mac, tid, buf_size); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, +++ ar->wmi.cmd->addba_send_cmdid); +++} +++ +++static inline int +++ath10k_wmi_addba_set_resp(struct ath10k *ar, u32 vdev_id, const u8 *mac, +++ u32 tid, u32 status) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_addba_set_resp) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_addba_set_resp(ar, vdev_id, mac, tid, status); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, +++ ar->wmi.cmd->addba_set_resp_cmdid); +++} +++ +++static inline int +++ath10k_wmi_delba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac, +++ u32 tid, u32 initiator, u32 reason) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_delba_send) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_delba_send(ar, vdev_id, mac, tid, initiator, +++ reason); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, +++ ar->wmi.cmd->delba_send_cmdid); +++} +++ +++static inline int +++ath10k_wmi_bcn_tmpl(struct ath10k *ar, u32 vdev_id, u32 tim_ie_offset, +++ struct sk_buff *bcn, u32 prb_caps, u32 prb_erp, +++ void *prb_ies, size_t prb_ies_len) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_bcn_tmpl) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_bcn_tmpl(ar, vdev_id, tim_ie_offset, bcn, +++ prb_caps, prb_erp, prb_ies, +++ prb_ies_len); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->bcn_tmpl_cmdid); +++} +++ +++static inline int +++ath10k_wmi_prb_tmpl(struct ath10k *ar, u32 vdev_id, struct sk_buff *prb) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_prb_tmpl) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_prb_tmpl(ar, vdev_id, prb); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->prb_tmpl_cmdid); +++} +++ +++static inline int +++ath10k_wmi_p2p_go_bcn_ie(struct ath10k *ar, u32 vdev_id, const u8 *p2p_ie) +++{ +++ struct sk_buff *skb; +++ +++ if (!ar->wmi.ops->gen_p2p_go_bcn_ie) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_p2p_go_bcn_ie(ar, vdev_id, p2p_ie); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->p2p_go_set_beacon_ie); +++} +++ +++static inline int +++ath10k_wmi_sta_keepalive(struct ath10k *ar, +++ const struct wmi_sta_keepalive_arg *arg) +++{ +++ struct sk_buff *skb; +++ u32 cmd_id; +++ +++ if (!ar->wmi.ops->gen_sta_keepalive) +++ return -EOPNOTSUPP; +++ +++ skb = ar->wmi.ops->gen_sta_keepalive(ar, arg); +++ if (IS_ERR(skb)) +++ return PTR_ERR(skb); +++ +++ cmd_id = ar->wmi.cmd->sta_keepalive_cmd; +++ return ath10k_wmi_cmd_send(ar, skb, cmd_id); +++} +++ +++#endif ++--- /dev/null +++++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c ++@@ -0,0 +1,2796 @@ +++/* +++ * Copyright (c) 2005-2011 Atheros Communications Inc. +++ * Copyright (c) 2011-2014 Qualcomm Atheros, Inc. +++ * +++ * Permission to use, copy, modify, and/or distribute this software for any +++ * purpose with or without fee is hereby granted, provided that the above +++ * copyright notice and this permission notice appear in all copies. +++ * +++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +++ */ +++#include "core.h" +++#include "debug.h" +++#include "hw.h" +++#include "wmi.h" +++#include "wmi-ops.h" +++#include "wmi-tlv.h" +++ +++/***************/ +++/* TLV helpers */ +++/**************/ +++ +++struct wmi_tlv_policy { +++ size_t min_len; +++}; +++ +++static const struct wmi_tlv_policy wmi_tlv_policies[] = { +++ [WMI_TLV_TAG_ARRAY_BYTE] +++ = { .min_len = sizeof(u8) }, +++ [WMI_TLV_TAG_ARRAY_UINT32] +++ = { .min_len = sizeof(u32) }, +++ [WMI_TLV_TAG_STRUCT_SCAN_EVENT] +++ = { .min_len = sizeof(struct wmi_scan_event) }, +++ [WMI_TLV_TAG_STRUCT_MGMT_RX_HDR] +++ = { .min_len = sizeof(struct wmi_tlv_mgmt_rx_ev) }, +++ [WMI_TLV_TAG_STRUCT_CHAN_INFO_EVENT] +++ = { .min_len = sizeof(struct wmi_chan_info_event) }, +++ [WMI_TLV_TAG_STRUCT_VDEV_START_RESPONSE_EVENT] +++ = { .min_len = sizeof(struct wmi_vdev_start_response_event) }, +++ [WMI_TLV_TAG_STRUCT_PEER_STA_KICKOUT_EVENT] +++ = { .min_len = sizeof(struct wmi_peer_sta_kickout_event) }, +++ [WMI_TLV_TAG_STRUCT_HOST_SWBA_EVENT] +++ = { .min_len = sizeof(struct wmi_host_swba_event) }, +++ [WMI_TLV_TAG_STRUCT_TIM_INFO] +++ = { .min_len = sizeof(struct wmi_tim_info) }, +++ [WMI_TLV_TAG_STRUCT_P2P_NOA_INFO] +++ = { .min_len = sizeof(struct wmi_p2p_noa_info) }, +++ [WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT] +++ = { .min_len = sizeof(struct wmi_tlv_svc_rdy_ev) }, +++ [WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES] +++ = { .min_len = sizeof(struct hal_reg_capabilities) }, +++ [WMI_TLV_TAG_STRUCT_WLAN_HOST_MEM_REQ] +++ = { .min_len = sizeof(struct wlan_host_mem_req) }, +++ [WMI_TLV_TAG_STRUCT_READY_EVENT] +++ = { .min_len = sizeof(struct wmi_tlv_rdy_ev) }, +++ [WMI_TLV_TAG_STRUCT_OFFLOAD_BCN_TX_STATUS_EVENT] +++ = { .min_len = sizeof(struct wmi_tlv_bcn_tx_status_ev) }, +++ [WMI_TLV_TAG_STRUCT_DIAG_DATA_CONTAINER_EVENT] +++ = { .min_len = sizeof(struct wmi_tlv_diag_data_ev) }, +++}; +++ +++static int +++ath10k_wmi_tlv_iter(struct ath10k *ar, const void *ptr, size_t len, +++ int (*iter)(struct ath10k *ar, u16 tag, u16 len, +++ const void *ptr, void *data), +++ void *data) +++{ +++ const void *begin = ptr; +++ const struct wmi_tlv *tlv; +++ u16 tlv_tag, tlv_len; +++ int ret; +++ +++ while (len > 0) { +++ if (len < sizeof(*tlv)) { +++ ath10k_dbg(ar, ATH10K_DBG_WMI, +++ "wmi tlv parse failure at byte %zd (%zu bytes left, %zu expected)\n", +++ ptr - begin, len, sizeof(*tlv)); +++ return -EINVAL; +++ } +++ +++ tlv = ptr; +++ tlv_tag = __le16_to_cpu(tlv->tag); +++ tlv_len = __le16_to_cpu(tlv->len); +++ ptr += sizeof(*tlv); +++ len -= sizeof(*tlv); +++ +++ if (tlv_len > len) { +++ ath10k_dbg(ar, ATH10K_DBG_WMI, +++ "wmi tlv parse failure of tag %hhu at byte %zd (%zu bytes left, %hhu expected)\n", +++ tlv_tag, ptr - begin, len, tlv_len); +++ return -EINVAL; +++ } +++ +++ if (tlv_tag < ARRAY_SIZE(wmi_tlv_policies) && +++ wmi_tlv_policies[tlv_tag].min_len && +++ wmi_tlv_policies[tlv_tag].min_len > tlv_len) { +++ ath10k_dbg(ar, ATH10K_DBG_WMI, +++ "wmi tlv parse failure of tag %hhu at byte %zd (%hhu bytes is less than min length %zu)\n", +++ tlv_tag, ptr - begin, tlv_len, +++ wmi_tlv_policies[tlv_tag].min_len); +++ return -EINVAL; +++ } +++ +++ ret = iter(ar, tlv_tag, tlv_len, ptr, data); +++ if (ret) +++ return ret; +++ +++ ptr += tlv_len; +++ len -= tlv_len; +++ } +++ +++ return 0; +++} +++ +++static int ath10k_wmi_tlv_iter_parse(struct ath10k *ar, u16 tag, u16 len, +++ const void *ptr, void *data) +++{ +++ const void **tb = data; +++ +++ if (tag < WMI_TLV_TAG_MAX) +++ tb[tag] = ptr; +++ +++ return 0; +++} +++ +++static int ath10k_wmi_tlv_parse(struct ath10k *ar, const void **tb, +++ const void *ptr, size_t len) +++{ +++ return ath10k_wmi_tlv_iter(ar, ptr, len, ath10k_wmi_tlv_iter_parse, +++ (void *)tb); +++} +++ +++static const void ** +++ath10k_wmi_tlv_parse_alloc(struct ath10k *ar, const void *ptr, +++ size_t len, gfp_t gfp) +++{ +++ const void **tb; +++ int ret; +++ +++ tb = kzalloc(sizeof(*tb) * WMI_TLV_TAG_MAX, gfp); +++ if (!tb) +++ return ERR_PTR(-ENOMEM); +++ +++ ret = ath10k_wmi_tlv_parse(ar, tb, ptr, len); +++ if (ret) { +++ kfree(tb); +++ return ERR_PTR(ret); +++ } +++ +++ return tb; +++} +++ +++static u16 ath10k_wmi_tlv_len(const void *ptr) +++{ +++ return __le16_to_cpu((((const struct wmi_tlv *)ptr) - 1)->len); +++} +++ +++/**************/ +++/* TLV events */ +++/**************/ +++static int ath10k_wmi_tlv_event_bcn_tx_status(struct ath10k *ar, +++ struct sk_buff *skb) +++{ +++ const void **tb; +++ const struct wmi_tlv_bcn_tx_status_ev *ev; +++ u32 vdev_id, tx_status; +++ int ret; +++ +++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); +++ if (IS_ERR(tb)) { +++ ret = PTR_ERR(tb); +++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret); +++ return ret; +++ } +++ +++ ev = tb[WMI_TLV_TAG_STRUCT_OFFLOAD_BCN_TX_STATUS_EVENT]; +++ if (!ev) { +++ kfree(tb); +++ return -EPROTO; +++ } +++ +++ tx_status = __le32_to_cpu(ev->tx_status); +++ vdev_id = __le32_to_cpu(ev->vdev_id); +++ +++ switch (tx_status) { +++ case WMI_TLV_BCN_TX_STATUS_OK: +++ break; +++ case WMI_TLV_BCN_TX_STATUS_XRETRY: +++ case WMI_TLV_BCN_TX_STATUS_DROP: +++ case WMI_TLV_BCN_TX_STATUS_FILTERED: +++ /* FIXME: It's probably worth telling mac80211 to stop the +++ * interface as it is crippled. +++ */ +++ ath10k_warn(ar, "received bcn tmpl tx status on vdev %i: %d", +++ vdev_id, tx_status); +++ break; +++ } +++ +++ kfree(tb); +++ return 0; +++} +++ +++static int ath10k_wmi_tlv_event_diag_data(struct ath10k *ar, +++ struct sk_buff *skb) +++{ +++ const void **tb; +++ const struct wmi_tlv_diag_data_ev *ev; +++ const struct wmi_tlv_diag_item *item; +++ const void *data; +++ int ret, num_items, len; +++ +++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); +++ if (IS_ERR(tb)) { +++ ret = PTR_ERR(tb); +++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret); +++ return ret; +++ } +++ +++ ev = tb[WMI_TLV_TAG_STRUCT_DIAG_DATA_CONTAINER_EVENT]; +++ data = tb[WMI_TLV_TAG_ARRAY_BYTE]; +++ if (!ev || !data) { +++ kfree(tb); +++ return -EPROTO; +++ } +++ +++ num_items = __le32_to_cpu(ev->num_items); +++ len = ath10k_wmi_tlv_len(data); +++ +++ while (num_items--) { +++ if (len == 0) +++ break; +++ if (len < sizeof(*item)) { +++ ath10k_warn(ar, "failed to parse diag data: can't fit item header\n"); +++ break; +++ } +++ +++ item = data; +++ +++ if (len < sizeof(*item) + __le16_to_cpu(item->len)) { +++ ath10k_warn(ar, "failed to parse diag data: item is too long\n"); +++ break; +++ } +++ +++ trace_ath10k_wmi_diag_container(ar, +++ item->type, +++ __le32_to_cpu(item->timestamp), +++ __le32_to_cpu(item->code), +++ __le16_to_cpu(item->len), +++ item->payload); +++ +++ len -= sizeof(*item); +++ len -= roundup(__le16_to_cpu(item->len), 4); +++ +++ data += sizeof(*item); +++ data += roundup(__le16_to_cpu(item->len), 4); +++ } +++ +++ if (num_items != -1 || len != 0) +++ ath10k_warn(ar, "failed to parse diag data event: num_items %d len %d\n", +++ num_items, len); +++ +++ kfree(tb); +++ return 0; +++} +++ +++static int ath10k_wmi_tlv_event_diag(struct ath10k *ar, +++ struct sk_buff *skb) +++{ +++ const void **tb; +++ const void *data; +++ int ret, len; +++ +++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); +++ if (IS_ERR(tb)) { +++ ret = PTR_ERR(tb); +++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret); +++ return ret; +++ } +++ +++ data = tb[WMI_TLV_TAG_ARRAY_BYTE]; +++ if (!data) { +++ kfree(tb); +++ return -EPROTO; +++ } +++ len = ath10k_wmi_tlv_len(data); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv diag event len %d\n", len); +++ trace_ath10k_wmi_diag(ar, data, len); +++ +++ kfree(tb); +++ return 0; +++} +++ +++/***********/ +++/* TLV ops */ +++/***********/ +++ +++static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) +++{ +++ struct wmi_cmd_hdr *cmd_hdr; +++ enum wmi_tlv_event_id id; +++ +++ cmd_hdr = (struct wmi_cmd_hdr *)skb->data; +++ id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); +++ +++ if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) +++ return; +++ +++ trace_ath10k_wmi_event(ar, id, skb->data, skb->len); +++ +++ switch (id) { +++ case WMI_TLV_MGMT_RX_EVENTID: +++ ath10k_wmi_event_mgmt_rx(ar, skb); +++ /* mgmt_rx() owns the skb now! */ +++ return; +++ case WMI_TLV_SCAN_EVENTID: +++ ath10k_wmi_event_scan(ar, skb); +++ break; +++ case WMI_TLV_CHAN_INFO_EVENTID: +++ ath10k_wmi_event_chan_info(ar, skb); +++ break; +++ case WMI_TLV_ECHO_EVENTID: +++ ath10k_wmi_event_echo(ar, skb); +++ break; +++ case WMI_TLV_DEBUG_MESG_EVENTID: +++ ath10k_wmi_event_debug_mesg(ar, skb); +++ break; +++ case WMI_TLV_UPDATE_STATS_EVENTID: +++ ath10k_wmi_event_update_stats(ar, skb); +++ break; +++ case WMI_TLV_VDEV_START_RESP_EVENTID: +++ ath10k_wmi_event_vdev_start_resp(ar, skb); +++ break; +++ case WMI_TLV_VDEV_STOPPED_EVENTID: +++ ath10k_wmi_event_vdev_stopped(ar, skb); +++ break; +++ case WMI_TLV_PEER_STA_KICKOUT_EVENTID: +++ ath10k_wmi_event_peer_sta_kickout(ar, skb); +++ break; +++ case WMI_TLV_HOST_SWBA_EVENTID: +++ ath10k_wmi_event_host_swba(ar, skb); +++ break; +++ case WMI_TLV_TBTTOFFSET_UPDATE_EVENTID: +++ ath10k_wmi_event_tbttoffset_update(ar, skb); +++ break; +++ case WMI_TLV_PHYERR_EVENTID: +++ ath10k_wmi_event_phyerr(ar, skb); +++ break; +++ case WMI_TLV_ROAM_EVENTID: +++ ath10k_wmi_event_roam(ar, skb); +++ break; +++ case WMI_TLV_PROFILE_MATCH: +++ ath10k_wmi_event_profile_match(ar, skb); +++ break; +++ case WMI_TLV_DEBUG_PRINT_EVENTID: +++ ath10k_wmi_event_debug_print(ar, skb); +++ break; +++ case WMI_TLV_PDEV_QVIT_EVENTID: +++ ath10k_wmi_event_pdev_qvit(ar, skb); +++ break; +++ case WMI_TLV_WLAN_PROFILE_DATA_EVENTID: +++ ath10k_wmi_event_wlan_profile_data(ar, skb); +++ break; +++ case WMI_TLV_RTT_MEASUREMENT_REPORT_EVENTID: +++ ath10k_wmi_event_rtt_measurement_report(ar, skb); +++ break; +++ case WMI_TLV_TSF_MEASUREMENT_REPORT_EVENTID: +++ ath10k_wmi_event_tsf_measurement_report(ar, skb); +++ break; +++ case WMI_TLV_RTT_ERROR_REPORT_EVENTID: +++ ath10k_wmi_event_rtt_error_report(ar, skb); +++ break; +++ case WMI_TLV_WOW_WAKEUP_HOST_EVENTID: +++ ath10k_wmi_event_wow_wakeup_host(ar, skb); +++ break; +++ case WMI_TLV_DCS_INTERFERENCE_EVENTID: +++ ath10k_wmi_event_dcs_interference(ar, skb); +++ break; +++ case WMI_TLV_PDEV_TPC_CONFIG_EVENTID: +++ ath10k_wmi_event_pdev_tpc_config(ar, skb); +++ break; +++ case WMI_TLV_PDEV_FTM_INTG_EVENTID: +++ ath10k_wmi_event_pdev_ftm_intg(ar, skb); +++ break; +++ case WMI_TLV_GTK_OFFLOAD_STATUS_EVENTID: +++ ath10k_wmi_event_gtk_offload_status(ar, skb); +++ break; +++ case WMI_TLV_GTK_REKEY_FAIL_EVENTID: +++ ath10k_wmi_event_gtk_rekey_fail(ar, skb); +++ break; +++ case WMI_TLV_TX_DELBA_COMPLETE_EVENTID: +++ ath10k_wmi_event_delba_complete(ar, skb); +++ break; +++ case WMI_TLV_TX_ADDBA_COMPLETE_EVENTID: +++ ath10k_wmi_event_addba_complete(ar, skb); +++ break; +++ case WMI_TLV_VDEV_INSTALL_KEY_COMPLETE_EVENTID: +++ ath10k_wmi_event_vdev_install_key_complete(ar, skb); +++ break; +++ case WMI_TLV_SERVICE_READY_EVENTID: +++ ath10k_wmi_event_service_ready(ar, skb); +++ break; +++ case WMI_TLV_READY_EVENTID: +++ ath10k_wmi_event_ready(ar, skb); +++ break; +++ case WMI_TLV_OFFLOAD_BCN_TX_STATUS_EVENTID: +++ ath10k_wmi_tlv_event_bcn_tx_status(ar, skb); +++ break; +++ case WMI_TLV_DIAG_DATA_CONTAINER_EVENTID: +++ ath10k_wmi_tlv_event_diag_data(ar, skb); +++ break; +++ case WMI_TLV_DIAG_EVENTID: +++ ath10k_wmi_tlv_event_diag(ar, skb); +++ break; +++ default: +++ ath10k_warn(ar, "Unknown eventid: %d\n", id); +++ break; +++ } +++ +++ dev_kfree_skb(skb); +++} +++ +++static int ath10k_wmi_tlv_op_pull_scan_ev(struct ath10k *ar, +++ struct sk_buff *skb, +++ struct wmi_scan_ev_arg *arg) +++{ +++ const void **tb; +++ const struct wmi_scan_event *ev; +++ int ret; +++ +++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); +++ if (IS_ERR(tb)) { +++ ret = PTR_ERR(tb); +++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret); +++ return ret; +++ } +++ +++ ev = tb[WMI_TLV_TAG_STRUCT_SCAN_EVENT]; +++ if (!ev) { +++ kfree(tb); +++ return -EPROTO; +++ } +++ +++ arg->event_type = ev->event_type; +++ arg->reason = ev->reason; +++ arg->channel_freq = ev->channel_freq; +++ arg->scan_req_id = ev->scan_req_id; +++ arg->scan_id = ev->scan_id; +++ arg->vdev_id = ev->vdev_id; +++ +++ kfree(tb); +++ return 0; +++} +++ +++static int ath10k_wmi_tlv_op_pull_mgmt_rx_ev(struct ath10k *ar, +++ struct sk_buff *skb, +++ struct wmi_mgmt_rx_ev_arg *arg) +++{ +++ const void **tb; +++ const struct wmi_tlv_mgmt_rx_ev *ev; +++ const u8 *frame; +++ u32 msdu_len; +++ int ret; +++ +++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); +++ if (IS_ERR(tb)) { +++ ret = PTR_ERR(tb); +++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret); +++ return ret; +++ } +++ +++ ev = tb[WMI_TLV_TAG_STRUCT_MGMT_RX_HDR]; +++ frame = tb[WMI_TLV_TAG_ARRAY_BYTE]; +++ +++ if (!ev || !frame) { +++ kfree(tb); +++ return -EPROTO; +++ } +++ +++ arg->channel = ev->channel; +++ arg->buf_len = ev->buf_len; +++ arg->status = ev->status; +++ arg->snr = ev->snr; +++ arg->phy_mode = ev->phy_mode; +++ arg->rate = ev->rate; +++ +++ msdu_len = __le32_to_cpu(arg->buf_len); +++ +++ if (skb->len < (frame - skb->data) + msdu_len) { +++ kfree(tb); +++ return -EPROTO; +++ } +++ +++ /* shift the sk_buff to point to `frame` */ +++ skb_trim(skb, 0); +++ skb_put(skb, frame - skb->data); +++ skb_pull(skb, frame - skb->data); +++ skb_put(skb, msdu_len); +++ +++ kfree(tb); +++ return 0; +++} +++ +++static int ath10k_wmi_tlv_op_pull_ch_info_ev(struct ath10k *ar, +++ struct sk_buff *skb, +++ struct wmi_ch_info_ev_arg *arg) +++{ +++ const void **tb; +++ const struct wmi_chan_info_event *ev; +++ int ret; +++ +++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); +++ if (IS_ERR(tb)) { +++ ret = PTR_ERR(tb); +++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret); +++ return ret; +++ } +++ +++ ev = tb[WMI_TLV_TAG_STRUCT_CHAN_INFO_EVENT]; +++ if (!ev) { +++ kfree(tb); +++ return -EPROTO; +++ } +++ +++ arg->err_code = ev->err_code; +++ arg->freq = ev->freq; +++ arg->cmd_flags = ev->cmd_flags; +++ arg->noise_floor = ev->noise_floor; +++ arg->rx_clear_count = ev->rx_clear_count; +++ arg->cycle_count = ev->cycle_count; +++ +++ kfree(tb); +++ return 0; +++} +++ +++static int +++ath10k_wmi_tlv_op_pull_vdev_start_ev(struct ath10k *ar, struct sk_buff *skb, +++ struct wmi_vdev_start_ev_arg *arg) +++{ +++ const void **tb; +++ const struct wmi_vdev_start_response_event *ev; +++ int ret; +++ +++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); +++ if (IS_ERR(tb)) { +++ ret = PTR_ERR(tb); +++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret); +++ return ret; +++ } +++ +++ ev = tb[WMI_TLV_TAG_STRUCT_VDEV_START_RESPONSE_EVENT]; +++ if (!ev) { +++ kfree(tb); +++ return -EPROTO; +++ } +++ +++ skb_pull(skb, sizeof(*ev)); +++ arg->vdev_id = ev->vdev_id; +++ arg->req_id = ev->req_id; +++ arg->resp_type = ev->resp_type; +++ arg->status = ev->status; +++ +++ kfree(tb); +++ return 0; +++} +++ +++static int ath10k_wmi_tlv_op_pull_peer_kick_ev(struct ath10k *ar, +++ struct sk_buff *skb, +++ struct wmi_peer_kick_ev_arg *arg) +++{ +++ const void **tb; +++ const struct wmi_peer_sta_kickout_event *ev; +++ int ret; +++ +++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); +++ if (IS_ERR(tb)) { +++ ret = PTR_ERR(tb); +++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret); +++ return ret; +++ } +++ +++ ev = tb[WMI_TLV_TAG_STRUCT_PEER_STA_KICKOUT_EVENT]; +++ if (!ev) { +++ kfree(tb); +++ return -EPROTO; +++ } +++ +++ arg->mac_addr = ev->peer_macaddr.addr; +++ +++ kfree(tb); +++ return 0; +++} +++ +++struct wmi_tlv_swba_parse { +++ const struct wmi_host_swba_event *ev; +++ bool tim_done; +++ bool noa_done; +++ size_t n_tim; +++ size_t n_noa; +++ struct wmi_swba_ev_arg *arg; +++}; +++ +++static int ath10k_wmi_tlv_swba_tim_parse(struct ath10k *ar, u16 tag, u16 len, +++ const void *ptr, void *data) +++{ +++ struct wmi_tlv_swba_parse *swba = data; +++ +++ if (tag != WMI_TLV_TAG_STRUCT_TIM_INFO) +++ return -EPROTO; +++ +++ if (swba->n_tim >= ARRAY_SIZE(swba->arg->tim_info)) +++ return -ENOBUFS; +++ +++ swba->arg->tim_info[swba->n_tim++] = ptr; +++ return 0; +++} +++ +++static int ath10k_wmi_tlv_swba_noa_parse(struct ath10k *ar, u16 tag, u16 len, +++ const void *ptr, void *data) +++{ +++ struct wmi_tlv_swba_parse *swba = data; +++ +++ if (tag != WMI_TLV_TAG_STRUCT_P2P_NOA_INFO) +++ return -EPROTO; +++ +++ if (swba->n_noa >= ARRAY_SIZE(swba->arg->noa_info)) +++ return -ENOBUFS; +++ +++ swba->arg->noa_info[swba->n_noa++] = ptr; +++ return 0; +++} +++ +++static int ath10k_wmi_tlv_swba_parse(struct ath10k *ar, u16 tag, u16 len, +++ const void *ptr, void *data) +++{ +++ struct wmi_tlv_swba_parse *swba = data; +++ int ret; +++ +++ switch (tag) { +++ case WMI_TLV_TAG_STRUCT_HOST_SWBA_EVENT: +++ swba->ev = ptr; +++ break; +++ case WMI_TLV_TAG_ARRAY_STRUCT: +++ if (!swba->tim_done) { +++ swba->tim_done = true; +++ ret = ath10k_wmi_tlv_iter(ar, ptr, len, +++ ath10k_wmi_tlv_swba_tim_parse, +++ swba); +++ if (ret) +++ return ret; +++ } else if (!swba->noa_done) { +++ swba->noa_done = true; +++ ret = ath10k_wmi_tlv_iter(ar, ptr, len, +++ ath10k_wmi_tlv_swba_noa_parse, +++ swba); +++ if (ret) +++ return ret; +++ } +++ break; +++ default: +++ break; +++ } +++ return 0; +++} +++ +++static int ath10k_wmi_tlv_op_pull_swba_ev(struct ath10k *ar, +++ struct sk_buff *skb, +++ struct wmi_swba_ev_arg *arg) +++{ +++ struct wmi_tlv_swba_parse swba = { .arg = arg }; +++ u32 map; +++ size_t n_vdevs; +++ int ret; +++ +++ ret = ath10k_wmi_tlv_iter(ar, skb->data, skb->len, +++ ath10k_wmi_tlv_swba_parse, &swba); +++ if (ret) { +++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret); +++ return ret; +++ } +++ +++ if (!swba.ev) +++ return -EPROTO; +++ +++ arg->vdev_map = swba.ev->vdev_map; +++ +++ for (map = __le32_to_cpu(arg->vdev_map), n_vdevs = 0; map; map >>= 1) +++ if (map & BIT(0)) +++ n_vdevs++; +++ +++ if (n_vdevs != swba.n_tim || +++ n_vdevs != swba.n_noa) +++ return -EPROTO; +++ +++ return 0; +++} +++ +++static int ath10k_wmi_tlv_op_pull_phyerr_ev(struct ath10k *ar, +++ struct sk_buff *skb, +++ struct wmi_phyerr_ev_arg *arg) +++{ +++ const void **tb; +++ const struct wmi_tlv_phyerr_ev *ev; +++ const void *phyerrs; +++ int ret; +++ +++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); +++ if (IS_ERR(tb)) { +++ ret = PTR_ERR(tb); +++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret); +++ return ret; +++ } +++ +++ ev = tb[WMI_TLV_TAG_STRUCT_COMB_PHYERR_RX_HDR]; +++ phyerrs = tb[WMI_TLV_TAG_ARRAY_BYTE]; +++ +++ if (!ev || !phyerrs) { +++ kfree(tb); +++ return -EPROTO; +++ } +++ +++ arg->num_phyerrs = ev->num_phyerrs; +++ arg->tsf_l32 = ev->tsf_l32; +++ arg->tsf_u32 = ev->tsf_u32; +++ arg->buf_len = ev->buf_len; +++ arg->phyerrs = phyerrs; +++ +++ kfree(tb); +++ return 0; +++} +++ +++#define WMI_TLV_ABI_VER_NS0 0x5F414351 +++#define WMI_TLV_ABI_VER_NS1 0x00004C4D +++#define WMI_TLV_ABI_VER_NS2 0x00000000 +++#define WMI_TLV_ABI_VER_NS3 0x00000000 +++ +++#define WMI_TLV_ABI_VER0_MAJOR 1 +++#define WMI_TLV_ABI_VER0_MINOR 0 +++#define WMI_TLV_ABI_VER0 ((((WMI_TLV_ABI_VER0_MAJOR) << 24) & 0xFF000000) | \ +++ (((WMI_TLV_ABI_VER0_MINOR) << 0) & 0x00FFFFFF)) +++#define WMI_TLV_ABI_VER1 53 +++ +++static int +++ath10k_wmi_tlv_parse_mem_reqs(struct ath10k *ar, u16 tag, u16 len, +++ const void *ptr, void *data) +++{ +++ struct wmi_svc_rdy_ev_arg *arg = data; +++ int i; +++ +++ if (tag != WMI_TLV_TAG_STRUCT_WLAN_HOST_MEM_REQ) +++ return -EPROTO; +++ +++ for (i = 0; i < ARRAY_SIZE(arg->mem_reqs); i++) { +++ if (!arg->mem_reqs[i]) { +++ arg->mem_reqs[i] = ptr; +++ return 0; +++ } +++ } +++ +++ return -ENOMEM; +++} +++ +++static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar, +++ struct sk_buff *skb, +++ struct wmi_svc_rdy_ev_arg *arg) +++{ +++ const void **tb; +++ const struct hal_reg_capabilities *reg; +++ const struct wmi_tlv_svc_rdy_ev *ev; +++ const __le32 *svc_bmap; +++ const struct wlan_host_mem_req *mem_reqs; +++ int ret; +++ +++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); +++ if (IS_ERR(tb)) { +++ ret = PTR_ERR(tb); +++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret); +++ return ret; +++ } +++ +++ ev = tb[WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT]; +++ reg = tb[WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES]; +++ svc_bmap = tb[WMI_TLV_TAG_ARRAY_UINT32]; +++ mem_reqs = tb[WMI_TLV_TAG_ARRAY_STRUCT]; +++ +++ if (!ev || !reg || !svc_bmap || !mem_reqs) { +++ kfree(tb); +++ return -EPROTO; +++ } +++ +++ /* This is an internal ABI compatibility check for WMI TLV so check it +++ * here instead of the generic WMI code. +++ */ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, +++ "wmi tlv abi 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x\n", +++ __le32_to_cpu(ev->abi.abi_ver0), WMI_TLV_ABI_VER0, +++ __le32_to_cpu(ev->abi.abi_ver_ns0), WMI_TLV_ABI_VER_NS0, +++ __le32_to_cpu(ev->abi.abi_ver_ns1), WMI_TLV_ABI_VER_NS1, +++ __le32_to_cpu(ev->abi.abi_ver_ns2), WMI_TLV_ABI_VER_NS2, +++ __le32_to_cpu(ev->abi.abi_ver_ns3), WMI_TLV_ABI_VER_NS3); +++ +++ if (__le32_to_cpu(ev->abi.abi_ver0) != WMI_TLV_ABI_VER0 || +++ __le32_to_cpu(ev->abi.abi_ver_ns0) != WMI_TLV_ABI_VER_NS0 || +++ __le32_to_cpu(ev->abi.abi_ver_ns1) != WMI_TLV_ABI_VER_NS1 || +++ __le32_to_cpu(ev->abi.abi_ver_ns2) != WMI_TLV_ABI_VER_NS2 || +++ __le32_to_cpu(ev->abi.abi_ver_ns3) != WMI_TLV_ABI_VER_NS3) { +++ kfree(tb); +++ return -ENOTSUPP; +++ } +++ +++ arg->min_tx_power = ev->hw_min_tx_power; +++ arg->max_tx_power = ev->hw_max_tx_power; +++ arg->ht_cap = ev->ht_cap_info; +++ arg->vht_cap = ev->vht_cap_info; +++ arg->sw_ver0 = ev->abi.abi_ver0; +++ arg->sw_ver1 = ev->abi.abi_ver1; +++ arg->fw_build = ev->fw_build_vers; +++ arg->phy_capab = ev->phy_capability; +++ arg->num_rf_chains = ev->num_rf_chains; +++ arg->eeprom_rd = reg->eeprom_rd; +++ arg->num_mem_reqs = ev->num_mem_reqs; +++ arg->service_map = svc_bmap; +++ arg->service_map_len = ath10k_wmi_tlv_len(svc_bmap); +++ +++ ret = ath10k_wmi_tlv_iter(ar, mem_reqs, ath10k_wmi_tlv_len(mem_reqs), +++ ath10k_wmi_tlv_parse_mem_reqs, arg); +++ if (ret) { +++ kfree(tb); +++ ath10k_warn(ar, "failed to parse mem_reqs tlv: %d\n", ret); +++ return ret; +++ } +++ +++ kfree(tb); +++ return 0; +++} +++ +++static int ath10k_wmi_tlv_op_pull_rdy_ev(struct ath10k *ar, +++ struct sk_buff *skb, +++ struct wmi_rdy_ev_arg *arg) +++{ +++ const void **tb; +++ const struct wmi_tlv_rdy_ev *ev; +++ int ret; +++ +++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); +++ if (IS_ERR(tb)) { +++ ret = PTR_ERR(tb); +++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret); +++ return ret; +++ } +++ +++ ev = tb[WMI_TLV_TAG_STRUCT_READY_EVENT]; +++ if (!ev) { +++ kfree(tb); +++ return -EPROTO; +++ } +++ +++ arg->sw_version = ev->abi.abi_ver0; +++ arg->abi_version = ev->abi.abi_ver1; +++ arg->status = ev->status; +++ arg->mac_addr = ev->mac_addr.addr; +++ +++ kfree(tb); +++ return 0; +++} +++ +++static void ath10k_wmi_tlv_pull_vdev_stats(const struct wmi_tlv_vdev_stats *src, +++ struct ath10k_fw_stats_vdev *dst) +++{ +++ int i; +++ +++ dst->vdev_id = __le32_to_cpu(src->vdev_id); +++ dst->beacon_snr = __le32_to_cpu(src->beacon_snr); +++ dst->data_snr = __le32_to_cpu(src->data_snr); +++ dst->num_rx_frames = __le32_to_cpu(src->num_rx_frames); +++ dst->num_rts_fail = __le32_to_cpu(src->num_rts_fail); +++ dst->num_rts_success = __le32_to_cpu(src->num_rts_success); +++ dst->num_rx_err = __le32_to_cpu(src->num_rx_err); +++ dst->num_rx_discard = __le32_to_cpu(src->num_rx_discard); +++ dst->num_tx_not_acked = __le32_to_cpu(src->num_tx_not_acked); +++ +++ for (i = 0; i < ARRAY_SIZE(src->num_tx_frames); i++) +++ dst->num_tx_frames[i] = +++ __le32_to_cpu(src->num_tx_frames[i]); +++ +++ for (i = 0; i < ARRAY_SIZE(src->num_tx_frames_retries); i++) +++ dst->num_tx_frames_retries[i] = +++ __le32_to_cpu(src->num_tx_frames_retries[i]); +++ +++ for (i = 0; i < ARRAY_SIZE(src->num_tx_frames_failures); i++) +++ dst->num_tx_frames_failures[i] = +++ __le32_to_cpu(src->num_tx_frames_failures[i]); +++ +++ for (i = 0; i < ARRAY_SIZE(src->tx_rate_history); i++) +++ dst->tx_rate_history[i] = +++ __le32_to_cpu(src->tx_rate_history[i]); +++ +++ for (i = 0; i < ARRAY_SIZE(src->beacon_rssi_history); i++) +++ dst->beacon_rssi_history[i] = +++ __le32_to_cpu(src->beacon_rssi_history[i]); +++} +++ +++static int ath10k_wmi_tlv_op_pull_fw_stats(struct ath10k *ar, +++ struct sk_buff *skb, +++ struct ath10k_fw_stats *stats) +++{ +++ const void **tb; +++ const struct wmi_tlv_stats_ev *ev; +++ const void *data; +++ u32 num_pdev_stats; +++ u32 num_vdev_stats; +++ u32 num_peer_stats; +++ u32 num_bcnflt_stats; +++ u32 num_chan_stats; +++ size_t data_len; +++ int ret; +++ int i; +++ +++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); +++ if (IS_ERR(tb)) { +++ ret = PTR_ERR(tb); +++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret); +++ return ret; +++ } +++ +++ ev = tb[WMI_TLV_TAG_STRUCT_STATS_EVENT]; +++ data = tb[WMI_TLV_TAG_ARRAY_BYTE]; +++ +++ if (!ev || !data) { +++ kfree(tb); +++ return -EPROTO; +++ } +++ +++ data_len = ath10k_wmi_tlv_len(data); +++ num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); +++ num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); +++ num_peer_stats = __le32_to_cpu(ev->num_peer_stats); +++ num_bcnflt_stats = __le32_to_cpu(ev->num_bcnflt_stats); +++ num_chan_stats = __le32_to_cpu(ev->num_chan_stats); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, +++ "wmi tlv stats update pdev %i vdev %i peer %i bcnflt %i chan %i\n", +++ num_pdev_stats, num_vdev_stats, num_peer_stats, +++ num_bcnflt_stats, num_chan_stats); +++ +++ for (i = 0; i < num_pdev_stats; i++) { +++ const struct wmi_pdev_stats *src; +++ struct ath10k_fw_stats_pdev *dst; +++ +++ src = data; +++ if (data_len < sizeof(*src)) +++ return -EPROTO; +++ +++ data += sizeof(*src); +++ data_len -= sizeof(*src); +++ +++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC); +++ if (!dst) +++ continue; +++ +++ ath10k_wmi_pull_pdev_stats_base(&src->base, dst); +++ ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst); +++ ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst); +++ list_add_tail(&dst->list, &stats->pdevs); +++ } +++ +++ for (i = 0; i < num_vdev_stats; i++) { +++ const struct wmi_tlv_vdev_stats *src; +++ struct ath10k_fw_stats_vdev *dst; +++ +++ src = data; +++ if (data_len < sizeof(*src)) +++ return -EPROTO; +++ +++ data += sizeof(*src); +++ data_len -= sizeof(*src); +++ +++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC); +++ if (!dst) +++ continue; +++ +++ ath10k_wmi_tlv_pull_vdev_stats(src, dst); +++ list_add_tail(&dst->list, &stats->vdevs); +++ } +++ +++ for (i = 0; i < num_peer_stats; i++) { +++ const struct wmi_10x_peer_stats *src; +++ struct ath10k_fw_stats_peer *dst; +++ +++ src = data; +++ if (data_len < sizeof(*src)) +++ return -EPROTO; +++ +++ data += sizeof(*src); +++ data_len -= sizeof(*src); +++ +++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC); +++ if (!dst) +++ continue; +++ +++ ath10k_wmi_pull_peer_stats(&src->old, dst); +++ dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate); +++ list_add_tail(&dst->list, &stats->peers); +++ } +++ +++ kfree(tb); +++ return 0; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_pdev_suspend(struct ath10k *ar, u32 opt) +++{ +++ struct wmi_tlv_pdev_suspend *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ tlv = (void *)skb->data; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SUSPEND_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->opt = __cpu_to_le32(opt); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev suspend\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_pdev_resume(struct ath10k *ar) +++{ +++ struct wmi_tlv_resume_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ tlv = (void *)skb->data; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_RESUME_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->reserved = __cpu_to_le32(0); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev resume\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_pdev_set_rd(struct ath10k *ar, +++ u16 rd, u16 rd2g, u16 rd5g, +++ u16 ctl2g, u16 ctl5g, +++ enum wmi_dfs_region dfs_reg) +++{ +++ struct wmi_tlv_pdev_set_rd_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ tlv = (void *)skb->data; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SET_REGDOMAIN_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->regd = __cpu_to_le32(rd); +++ cmd->regd_2ghz = __cpu_to_le32(rd2g); +++ cmd->regd_5ghz = __cpu_to_le32(rd5g); +++ cmd->conform_limit_2ghz = __cpu_to_le32(rd2g); +++ cmd->conform_limit_5ghz = __cpu_to_le32(rd5g); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev set rd\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_pdev_set_param(struct ath10k *ar, u32 param_id, +++ u32 param_value) +++{ +++ struct wmi_tlv_pdev_set_param_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ tlv = (void *)skb->data; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SET_PARAM_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->param_id = __cpu_to_le32(param_id); +++ cmd->param_value = __cpu_to_le32(param_value); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev set param\n"); +++ return skb; +++} +++ +++static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar) +++{ +++ struct sk_buff *skb; +++ struct wmi_tlv *tlv; +++ struct wmi_tlv_init_cmd *cmd; +++ struct wmi_tlv_resource_config *cfg; +++ struct wmi_host_mem_chunks *chunks; +++ size_t len, chunks_len; +++ void *ptr; +++ +++ chunks_len = ar->wmi.num_mem_chunks * sizeof(struct host_memory_chunk); +++ len = (sizeof(*tlv) + sizeof(*cmd)) + +++ (sizeof(*tlv) + sizeof(*cfg)) + +++ (sizeof(*tlv) + chunks_len); +++ +++ skb = ath10k_wmi_alloc_skb(ar, len); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ ptr = skb->data; +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_INIT_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ ptr += sizeof(*tlv); +++ ptr += sizeof(*cmd); +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_RESOURCE_CONFIG); +++ tlv->len = __cpu_to_le16(sizeof(*cfg)); +++ cfg = (void *)tlv->value; +++ ptr += sizeof(*tlv); +++ ptr += sizeof(*cfg); +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT); +++ tlv->len = __cpu_to_le16(chunks_len); +++ chunks = (void *)tlv->value; +++ +++ ptr += sizeof(*tlv); +++ ptr += chunks_len; +++ +++ cmd->abi.abi_ver0 = __cpu_to_le32(WMI_TLV_ABI_VER0); +++ cmd->abi.abi_ver1 = __cpu_to_le32(WMI_TLV_ABI_VER1); +++ cmd->abi.abi_ver_ns0 = __cpu_to_le32(WMI_TLV_ABI_VER_NS0); +++ cmd->abi.abi_ver_ns1 = __cpu_to_le32(WMI_TLV_ABI_VER_NS1); +++ cmd->abi.abi_ver_ns2 = __cpu_to_le32(WMI_TLV_ABI_VER_NS2); +++ cmd->abi.abi_ver_ns3 = __cpu_to_le32(WMI_TLV_ABI_VER_NS3); +++ cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks); +++ +++ cfg->num_vdevs = __cpu_to_le32(TARGET_TLV_NUM_VDEVS); +++ cfg->num_peers = __cpu_to_le32(TARGET_TLV_NUM_PEERS); +++ +++ if (test_bit(WMI_SERVICE_RX_FULL_REORDER, ar->wmi.svc_map)) { +++ cfg->num_offload_peers = __cpu_to_le32(3); +++ cfg->num_offload_reorder_bufs = __cpu_to_le32(3); +++ } else { +++ cfg->num_offload_peers = __cpu_to_le32(0); +++ cfg->num_offload_reorder_bufs = __cpu_to_le32(0); +++ } +++ +++ cfg->num_peer_keys = __cpu_to_le32(2); +++ cfg->num_tids = __cpu_to_le32(TARGET_TLV_NUM_TIDS); +++ cfg->ast_skid_limit = __cpu_to_le32(0x10); +++ cfg->tx_chain_mask = __cpu_to_le32(0x7); +++ cfg->rx_chain_mask = __cpu_to_le32(0x7); +++ cfg->rx_timeout_pri[0] = __cpu_to_le32(0x64); +++ cfg->rx_timeout_pri[1] = __cpu_to_le32(0x64); +++ cfg->rx_timeout_pri[2] = __cpu_to_le32(0x64); +++ cfg->rx_timeout_pri[3] = __cpu_to_le32(0x28); +++ cfg->rx_decap_mode = __cpu_to_le32(1); +++ cfg->scan_max_pending_reqs = __cpu_to_le32(4); +++ cfg->bmiss_offload_max_vdev = __cpu_to_le32(3); +++ cfg->roam_offload_max_vdev = __cpu_to_le32(3); +++ cfg->roam_offload_max_ap_profiles = __cpu_to_le32(8); +++ cfg->num_mcast_groups = __cpu_to_le32(0); +++ cfg->num_mcast_table_elems = __cpu_to_le32(0); +++ cfg->mcast2ucast_mode = __cpu_to_le32(0); +++ cfg->tx_dbg_log_size = __cpu_to_le32(0x400); +++ cfg->num_wds_entries = __cpu_to_le32(0x20); +++ cfg->dma_burst_size = __cpu_to_le32(0); +++ cfg->mac_aggr_delim = __cpu_to_le32(0); +++ cfg->rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(0); +++ cfg->vow_config = __cpu_to_le32(0); +++ cfg->gtk_offload_max_vdev = __cpu_to_le32(2); +++ cfg->num_msdu_desc = __cpu_to_le32(TARGET_TLV_NUM_MSDU_DESC); +++ cfg->max_frag_entries = __cpu_to_le32(2); +++ cfg->num_tdls_vdevs = __cpu_to_le32(1); +++ cfg->num_tdls_conn_table_entries = __cpu_to_le32(0x20); +++ cfg->beacon_tx_offload_max_vdev = __cpu_to_le32(2); +++ cfg->num_multicast_filter_entries = __cpu_to_le32(5); +++ cfg->num_wow_filters = __cpu_to_le32(0x16); +++ cfg->num_keep_alive_pattern = __cpu_to_le32(6); +++ cfg->keep_alive_pattern_size = __cpu_to_le32(0); +++ cfg->max_tdls_concurrent_sleep_sta = __cpu_to_le32(1); +++ cfg->max_tdls_concurrent_buffer_sta = __cpu_to_le32(1); +++ +++ ath10k_wmi_put_host_mem_chunks(ar, chunks); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv init\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_start_scan(struct ath10k *ar, +++ const struct wmi_start_scan_arg *arg) +++{ +++ struct wmi_tlv_start_scan_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ size_t len, chan_len, ssid_len, bssid_len, ie_len; +++ __le32 *chans; +++ struct wmi_ssid *ssids; +++ struct wmi_mac_addr *addrs; +++ void *ptr; +++ int i, ret; +++ +++ ret = ath10k_wmi_start_scan_verify(arg); +++ if (ret) +++ return ERR_PTR(ret); +++ +++ chan_len = arg->n_channels * sizeof(__le32); +++ ssid_len = arg->n_ssids * sizeof(struct wmi_ssid); +++ bssid_len = arg->n_bssids * sizeof(struct wmi_mac_addr); +++ ie_len = roundup(arg->ie_len, 4); +++ len = (sizeof(*tlv) + sizeof(*cmd)) + +++ (arg->n_channels ? sizeof(*tlv) + chan_len : 0) + +++ (arg->n_ssids ? sizeof(*tlv) + ssid_len : 0) + +++ (arg->n_bssids ? sizeof(*tlv) + bssid_len : 0) + +++ (arg->ie_len ? sizeof(*tlv) + ie_len : 0); +++ +++ skb = ath10k_wmi_alloc_skb(ar, len); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ ptr = (void *)skb->data; +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_START_SCAN_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ +++ ath10k_wmi_put_start_scan_common(&cmd->common, arg); +++ cmd->burst_duration_ms = __cpu_to_le32(0); +++ cmd->num_channels = __cpu_to_le32(arg->n_channels); +++ cmd->num_ssids = __cpu_to_le32(arg->n_ssids); +++ cmd->num_bssids = __cpu_to_le32(arg->n_bssids); +++ cmd->ie_len = __cpu_to_le32(arg->ie_len); +++ cmd->num_probes = __cpu_to_le32(3); +++ +++ /* FIXME: There are some scan flag inconsistencies across firmwares, +++ * e.g. WMI-TLV inverts the logic behind the following flag. +++ */ +++ cmd->common.scan_ctrl_flags ^= __cpu_to_le32(WMI_SCAN_FILTER_PROBE_REQ); +++ +++ ptr += sizeof(*tlv); +++ ptr += sizeof(*cmd); +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_UINT32); +++ tlv->len = __cpu_to_le16(chan_len); +++ chans = (void *)tlv->value; +++ for (i = 0; i < arg->n_channels; i++) +++ chans[i] = __cpu_to_le32(arg->channels[i]); +++ +++ ptr += sizeof(*tlv); +++ ptr += chan_len; +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_FIXED_STRUCT); +++ tlv->len = __cpu_to_le16(ssid_len); +++ ssids = (void *)tlv->value; +++ for (i = 0; i < arg->n_ssids; i++) { +++ ssids[i].ssid_len = __cpu_to_le32(arg->ssids[i].len); +++ memcpy(ssids[i].ssid, arg->ssids[i].ssid, arg->ssids[i].len); +++ } +++ +++ ptr += sizeof(*tlv); +++ ptr += ssid_len; +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_FIXED_STRUCT); +++ tlv->len = __cpu_to_le16(bssid_len); +++ addrs = (void *)tlv->value; +++ for (i = 0; i < arg->n_bssids; i++) +++ ether_addr_copy(addrs[i].addr, arg->bssids[i].bssid); +++ +++ ptr += sizeof(*tlv); +++ ptr += bssid_len; +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE); +++ tlv->len = __cpu_to_le16(ie_len); +++ memcpy(tlv->value, arg->ie, arg->ie_len); +++ +++ ptr += sizeof(*tlv); +++ ptr += ie_len; +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv start scan\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_stop_scan(struct ath10k *ar, +++ const struct wmi_stop_scan_arg *arg) +++{ +++ struct wmi_stop_scan_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ u32 scan_id; +++ u32 req_id; +++ +++ if (arg->req_id > 0xFFF) +++ return ERR_PTR(-EINVAL); +++ if (arg->req_type == WMI_SCAN_STOP_ONE && arg->u.scan_id > 0xFFF) +++ return ERR_PTR(-EINVAL); +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ scan_id = arg->u.scan_id; +++ scan_id |= WMI_HOST_SCAN_REQ_ID_PREFIX; +++ +++ req_id = arg->req_id; +++ req_id |= WMI_HOST_SCAN_REQUESTOR_ID_PREFIX; +++ +++ tlv = (void *)skb->data; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STOP_SCAN_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->req_type = __cpu_to_le32(arg->req_type); +++ cmd->vdev_id = __cpu_to_le32(arg->u.vdev_id); +++ cmd->scan_id = __cpu_to_le32(scan_id); +++ cmd->scan_req_id = __cpu_to_le32(req_id); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv stop scan\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_vdev_create(struct ath10k *ar, +++ u32 vdev_id, +++ enum wmi_vdev_type vdev_type, +++ enum wmi_vdev_subtype vdev_subtype, +++ const u8 mac_addr[ETH_ALEN]) +++{ +++ struct wmi_vdev_create_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ tlv = (void *)skb->data; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_CREATE_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ cmd->vdev_type = __cpu_to_le32(vdev_type); +++ cmd->vdev_subtype = __cpu_to_le32(vdev_subtype); +++ ether_addr_copy(cmd->vdev_macaddr.addr, mac_addr); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev create\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_vdev_delete(struct ath10k *ar, u32 vdev_id) +++{ +++ struct wmi_vdev_delete_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ tlv = (void *)skb->data; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_DELETE_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev delete\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_vdev_start(struct ath10k *ar, +++ const struct wmi_vdev_start_request_arg *arg, +++ bool restart) +++{ +++ struct wmi_tlv_vdev_start_cmd *cmd; +++ struct wmi_channel *ch; +++ struct wmi_p2p_noa_descriptor *noa; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ size_t len; +++ void *ptr; +++ u32 flags = 0; +++ +++ if (WARN_ON(arg->ssid && arg->ssid_len == 0)) +++ return ERR_PTR(-EINVAL); +++ if (WARN_ON(arg->hidden_ssid && !arg->ssid)) +++ return ERR_PTR(-EINVAL); +++ if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid))) +++ return ERR_PTR(-EINVAL); +++ +++ len = (sizeof(*tlv) + sizeof(*cmd)) + +++ (sizeof(*tlv) + sizeof(*ch)) + +++ (sizeof(*tlv) + 0); +++ skb = ath10k_wmi_alloc_skb(ar, len); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ if (arg->hidden_ssid) +++ flags |= WMI_VDEV_START_HIDDEN_SSID; +++ if (arg->pmf_enabled) +++ flags |= WMI_VDEV_START_PMF_ENABLED; +++ +++ ptr = (void *)skb->data; +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_START_REQUEST_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->vdev_id = __cpu_to_le32(arg->vdev_id); +++ cmd->bcn_intval = __cpu_to_le32(arg->bcn_intval); +++ cmd->dtim_period = __cpu_to_le32(arg->dtim_period); +++ cmd->flags = __cpu_to_le32(flags); +++ cmd->bcn_tx_rate = __cpu_to_le32(arg->bcn_tx_rate); +++ cmd->bcn_tx_power = __cpu_to_le32(arg->bcn_tx_power); +++ cmd->disable_hw_ack = __cpu_to_le32(arg->disable_hw_ack); +++ +++ if (arg->ssid) { +++ cmd->ssid.ssid_len = __cpu_to_le32(arg->ssid_len); +++ memcpy(cmd->ssid.ssid, arg->ssid, arg->ssid_len); +++ } +++ +++ ptr += sizeof(*tlv); +++ ptr += sizeof(*cmd); +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_CHANNEL); +++ tlv->len = __cpu_to_le16(sizeof(*ch)); +++ ch = (void *)tlv->value; +++ ath10k_wmi_put_wmi_channel(ch, &arg->channel); +++ +++ ptr += sizeof(*tlv); +++ ptr += sizeof(*ch); +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT); +++ tlv->len = 0; +++ noa = (void *)tlv->value; +++ +++ /* Note: This is a nested TLV containing: +++ * [wmi_tlv][wmi_p2p_noa_descriptor][wmi_tlv].. +++ */ +++ +++ ptr += sizeof(*tlv); +++ ptr += 0; +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev start\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_vdev_stop(struct ath10k *ar, u32 vdev_id) +++{ +++ struct wmi_vdev_stop_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ tlv = (void *)skb->data; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_STOP_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev stop\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, +++ const u8 *bssid) +++ +++{ +++ struct wmi_vdev_up_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ tlv = (void *)skb->data; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_UP_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ cmd->vdev_assoc_id = __cpu_to_le32(aid); +++ ether_addr_copy(cmd->vdev_bssid.addr, bssid); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev up\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_vdev_down(struct ath10k *ar, u32 vdev_id) +++{ +++ struct wmi_vdev_down_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ tlv = (void *)skb->data; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_DOWN_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev down\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_vdev_set_param(struct ath10k *ar, u32 vdev_id, +++ u32 param_id, u32 param_value) +++{ +++ struct wmi_vdev_set_param_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ tlv = (void *)skb->data; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_SET_PARAM_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ cmd->param_id = __cpu_to_le32(param_id); +++ cmd->param_value = __cpu_to_le32(param_value); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev set param\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_vdev_install_key(struct ath10k *ar, +++ const struct wmi_vdev_install_key_arg *arg) +++{ +++ struct wmi_vdev_install_key_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ size_t len; +++ void *ptr; +++ +++ if (arg->key_cipher == WMI_CIPHER_NONE && arg->key_data != NULL) +++ return ERR_PTR(-EINVAL); +++ if (arg->key_cipher != WMI_CIPHER_NONE && arg->key_data == NULL) +++ return ERR_PTR(-EINVAL); +++ +++ len = sizeof(*tlv) + sizeof(*cmd) + +++ sizeof(*tlv) + roundup(arg->key_len, sizeof(__le32)); +++ skb = ath10k_wmi_alloc_skb(ar, len); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ ptr = (void *)skb->data; +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_INSTALL_KEY_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->vdev_id = __cpu_to_le32(arg->vdev_id); +++ cmd->key_idx = __cpu_to_le32(arg->key_idx); +++ cmd->key_flags = __cpu_to_le32(arg->key_flags); +++ cmd->key_cipher = __cpu_to_le32(arg->key_cipher); +++ cmd->key_len = __cpu_to_le32(arg->key_len); +++ cmd->key_txmic_len = __cpu_to_le32(arg->key_txmic_len); +++ cmd->key_rxmic_len = __cpu_to_le32(arg->key_rxmic_len); +++ +++ if (arg->macaddr) +++ ether_addr_copy(cmd->peer_macaddr.addr, arg->macaddr); +++ +++ ptr += sizeof(*tlv); +++ ptr += sizeof(*cmd); +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE); +++ tlv->len = __cpu_to_le16(roundup(arg->key_len, sizeof(__le32))); +++ if (arg->key_data) +++ memcpy(tlv->value, arg->key_data, arg->key_len); +++ +++ ptr += sizeof(*tlv); +++ ptr += roundup(arg->key_len, sizeof(__le32)); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev install key\n"); +++ return skb; +++} +++ +++static void *ath10k_wmi_tlv_put_uapsd_ac(struct ath10k *ar, void *ptr, +++ const struct wmi_sta_uapsd_auto_trig_arg *arg) +++{ +++ struct wmi_sta_uapsd_auto_trig_param *ac; +++ struct wmi_tlv *tlv; +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_UAPSD_AUTO_TRIG_PARAM); +++ tlv->len = __cpu_to_le16(sizeof(*ac)); +++ ac = (void *)tlv->value; +++ +++ ac->wmm_ac = __cpu_to_le32(arg->wmm_ac); +++ ac->user_priority = __cpu_to_le32(arg->user_priority); +++ ac->service_interval = __cpu_to_le32(arg->service_interval); +++ ac->suspend_interval = __cpu_to_le32(arg->suspend_interval); +++ ac->delay_interval = __cpu_to_le32(arg->delay_interval); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, +++ "wmi tlv vdev sta uapsd auto trigger ac %d prio %d svc int %d susp int %d delay int %d\n", +++ ac->wmm_ac, ac->user_priority, ac->service_interval, +++ ac->suspend_interval, ac->delay_interval); +++ +++ return ptr + sizeof(*tlv) + sizeof(*ac); +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_vdev_sta_uapsd(struct ath10k *ar, u32 vdev_id, +++ const u8 peer_addr[ETH_ALEN], +++ const struct wmi_sta_uapsd_auto_trig_arg *args, +++ u32 num_ac) +++{ +++ struct wmi_sta_uapsd_auto_trig_cmd_fixed_param *cmd; +++ struct wmi_sta_uapsd_auto_trig_param *ac; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ size_t len; +++ size_t ac_tlv_len; +++ void *ptr; +++ int i; +++ +++ ac_tlv_len = num_ac * (sizeof(*tlv) + sizeof(*ac)); +++ len = sizeof(*tlv) + sizeof(*cmd) + +++ sizeof(*tlv) + ac_tlv_len; +++ skb = ath10k_wmi_alloc_skb(ar, len); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ ptr = (void *)skb->data; +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_UAPSD_AUTO_TRIG_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ cmd->num_ac = __cpu_to_le32(num_ac); +++ ether_addr_copy(cmd->peer_macaddr.addr, peer_addr); +++ +++ ptr += sizeof(*tlv); +++ ptr += sizeof(*cmd); +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT); +++ tlv->len = __cpu_to_le16(ac_tlv_len); +++ ac = (void *)tlv->value; +++ +++ ptr += sizeof(*tlv); +++ for (i = 0; i < num_ac; i++) +++ ptr = ath10k_wmi_tlv_put_uapsd_ac(ar, ptr, &args[i]); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev sta uapsd auto trigger\n"); +++ return skb; +++} +++ +++static void *ath10k_wmi_tlv_put_wmm(void *ptr, +++ const struct wmi_wmm_params_arg *arg) +++{ +++ struct wmi_wmm_params *wmm; +++ struct wmi_tlv *tlv; +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_WMM_PARAMS); +++ tlv->len = __cpu_to_le16(sizeof(*wmm)); +++ wmm = (void *)tlv->value; +++ ath10k_wmi_set_wmm_param(wmm, arg); +++ +++ return ptr + sizeof(*tlv) + sizeof(*wmm); +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_vdev_wmm_conf(struct ath10k *ar, u32 vdev_id, +++ const struct wmi_wmm_params_all_arg *arg) +++{ +++ struct wmi_tlv_vdev_set_wmm_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ size_t len; +++ void *ptr; +++ +++ len = sizeof(*tlv) + sizeof(*cmd); +++ skb = ath10k_wmi_alloc_skb(ar, len); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ ptr = (void *)skb->data; +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_SET_WMM_PARAMS_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ +++ ath10k_wmi_set_wmm_param(&cmd->vdev_wmm_params[0].params, &arg->ac_be); +++ ath10k_wmi_set_wmm_param(&cmd->vdev_wmm_params[1].params, &arg->ac_bk); +++ ath10k_wmi_set_wmm_param(&cmd->vdev_wmm_params[2].params, &arg->ac_vi); +++ ath10k_wmi_set_wmm_param(&cmd->vdev_wmm_params[3].params, &arg->ac_vo); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev wmm conf\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_sta_keepalive(struct ath10k *ar, +++ const struct wmi_sta_keepalive_arg *arg) +++{ +++ struct wmi_tlv_sta_keepalive_cmd *cmd; +++ struct wmi_sta_keepalive_arp_resp *arp; +++ struct sk_buff *skb; +++ struct wmi_tlv *tlv; +++ void *ptr; +++ size_t len; +++ +++ len = sizeof(*tlv) + sizeof(*cmd) + +++ sizeof(*tlv) + sizeof(*arp); +++ skb = ath10k_wmi_alloc_skb(ar, len); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ ptr = (void *)skb->data; +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_KEEPALIVE_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->vdev_id = __cpu_to_le32(arg->vdev_id); +++ cmd->enabled = __cpu_to_le32(arg->enabled); +++ cmd->method = __cpu_to_le32(arg->method); +++ cmd->interval = __cpu_to_le32(arg->interval); +++ +++ ptr += sizeof(*tlv); +++ ptr += sizeof(*cmd); +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_KEEPALVE_ARP_RESPONSE); +++ tlv->len = __cpu_to_le16(sizeof(*arp)); +++ arp = (void *)tlv->value; +++ +++ arp->src_ip4_addr = arg->src_ip4_addr; +++ arp->dest_ip4_addr = arg->dest_ip4_addr; +++ ether_addr_copy(arp->dest_mac_addr.addr, arg->dest_mac_addr); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv sta keepalive vdev %d enabled %d method %d inverval %d\n", +++ arg->vdev_id, arg->enabled, arg->method, arg->interval); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_peer_create(struct ath10k *ar, u32 vdev_id, +++ const u8 peer_addr[ETH_ALEN]) +++{ +++ struct wmi_tlv_peer_create_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ tlv = (void *)skb->data; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_CREATE_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ cmd->peer_type = __cpu_to_le32(WMI_TLV_PEER_TYPE_DEFAULT); /* FIXME */ +++ ether_addr_copy(cmd->peer_addr.addr, peer_addr); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer create\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_peer_delete(struct ath10k *ar, u32 vdev_id, +++ const u8 peer_addr[ETH_ALEN]) +++{ +++ struct wmi_peer_delete_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ tlv = (void *)skb->data; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_DELETE_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ ether_addr_copy(cmd->peer_macaddr.addr, peer_addr); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer delete\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_peer_flush(struct ath10k *ar, u32 vdev_id, +++ const u8 peer_addr[ETH_ALEN], u32 tid_bitmap) +++{ +++ struct wmi_peer_flush_tids_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ tlv = (void *)skb->data; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_FLUSH_TIDS_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ cmd->peer_tid_bitmap = __cpu_to_le32(tid_bitmap); +++ ether_addr_copy(cmd->peer_macaddr.addr, peer_addr); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer flush\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_peer_set_param(struct ath10k *ar, u32 vdev_id, +++ const u8 *peer_addr, +++ enum wmi_peer_param param_id, +++ u32 param_value) +++{ +++ struct wmi_peer_set_param_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ tlv = (void *)skb->data; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_SET_PARAM_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ cmd->param_id = __cpu_to_le32(param_id); +++ cmd->param_value = __cpu_to_le32(param_value); +++ ether_addr_copy(cmd->peer_macaddr.addr, peer_addr); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer set param\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_peer_assoc(struct ath10k *ar, +++ const struct wmi_peer_assoc_complete_arg *arg) +++{ +++ struct wmi_tlv_peer_assoc_cmd *cmd; +++ struct wmi_vht_rate_set *vht_rate; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ size_t len, legacy_rate_len, ht_rate_len; +++ void *ptr; +++ +++ if (arg->peer_mpdu_density > 16) +++ return ERR_PTR(-EINVAL); +++ if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES) +++ return ERR_PTR(-EINVAL); +++ if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES) +++ return ERR_PTR(-EINVAL); +++ +++ legacy_rate_len = roundup(arg->peer_legacy_rates.num_rates, +++ sizeof(__le32)); +++ ht_rate_len = roundup(arg->peer_ht_rates.num_rates, sizeof(__le32)); +++ len = (sizeof(*tlv) + sizeof(*cmd)) + +++ (sizeof(*tlv) + legacy_rate_len) + +++ (sizeof(*tlv) + ht_rate_len) + +++ (sizeof(*tlv) + sizeof(*vht_rate)); +++ skb = ath10k_wmi_alloc_skb(ar, len); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ ptr = (void *)skb->data; +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_ASSOC_COMPLETE_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ +++ cmd->vdev_id = __cpu_to_le32(arg->vdev_id); +++ cmd->new_assoc = __cpu_to_le32(arg->peer_reassoc ? 0 : 1); +++ cmd->assoc_id = __cpu_to_le32(arg->peer_aid); +++ cmd->flags = __cpu_to_le32(arg->peer_flags); +++ cmd->caps = __cpu_to_le32(arg->peer_caps); +++ cmd->listen_intval = __cpu_to_le32(arg->peer_listen_intval); +++ cmd->ht_caps = __cpu_to_le32(arg->peer_ht_caps); +++ cmd->max_mpdu = __cpu_to_le32(arg->peer_max_mpdu); +++ cmd->mpdu_density = __cpu_to_le32(arg->peer_mpdu_density); +++ cmd->rate_caps = __cpu_to_le32(arg->peer_rate_caps); +++ cmd->nss = __cpu_to_le32(arg->peer_num_spatial_streams); +++ cmd->vht_caps = __cpu_to_le32(arg->peer_vht_caps); +++ cmd->phy_mode = __cpu_to_le32(arg->peer_phymode); +++ cmd->num_legacy_rates = __cpu_to_le32(arg->peer_legacy_rates.num_rates); +++ cmd->num_ht_rates = __cpu_to_le32(arg->peer_ht_rates.num_rates); +++ ether_addr_copy(cmd->mac_addr.addr, arg->addr); +++ +++ ptr += sizeof(*tlv); +++ ptr += sizeof(*cmd); +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE); +++ tlv->len = __cpu_to_le16(legacy_rate_len); +++ memcpy(tlv->value, arg->peer_legacy_rates.rates, +++ arg->peer_legacy_rates.num_rates); +++ +++ ptr += sizeof(*tlv); +++ ptr += legacy_rate_len; +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE); +++ tlv->len = __cpu_to_le16(ht_rate_len); +++ memcpy(tlv->value, arg->peer_ht_rates.rates, +++ arg->peer_ht_rates.num_rates); +++ +++ ptr += sizeof(*tlv); +++ ptr += ht_rate_len; +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VHT_RATE_SET); +++ tlv->len = __cpu_to_le16(sizeof(*vht_rate)); +++ vht_rate = (void *)tlv->value; +++ +++ vht_rate->rx_max_rate = __cpu_to_le32(arg->peer_vht_rates.rx_max_rate); +++ vht_rate->rx_mcs_set = __cpu_to_le32(arg->peer_vht_rates.rx_mcs_set); +++ vht_rate->tx_max_rate = __cpu_to_le32(arg->peer_vht_rates.tx_max_rate); +++ vht_rate->tx_mcs_set = __cpu_to_le32(arg->peer_vht_rates.tx_mcs_set); +++ +++ ptr += sizeof(*tlv); +++ ptr += sizeof(*vht_rate); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer assoc\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_set_psmode(struct ath10k *ar, u32 vdev_id, +++ enum wmi_sta_ps_mode psmode) +++{ +++ struct wmi_sta_powersave_mode_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ tlv = (void *)skb->data; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_POWERSAVE_MODE_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ cmd->sta_ps_mode = __cpu_to_le32(psmode); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv set psmode\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_set_sta_ps(struct ath10k *ar, u32 vdev_id, +++ enum wmi_sta_powersave_param param_id, +++ u32 param_value) +++{ +++ struct wmi_sta_powersave_param_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ tlv = (void *)skb->data; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_POWERSAVE_PARAM_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ cmd->param_id = __cpu_to_le32(param_id); +++ cmd->param_value = __cpu_to_le32(param_value); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv set sta ps\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_set_ap_ps(struct ath10k *ar, u32 vdev_id, const u8 *mac, +++ enum wmi_ap_ps_peer_param param_id, u32 value) +++{ +++ struct wmi_ap_ps_peer_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ +++ if (!mac) +++ return ERR_PTR(-EINVAL); +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ tlv = (void *)skb->data; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_AP_PS_PEER_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ cmd->param_id = __cpu_to_le32(param_id); +++ cmd->param_value = __cpu_to_le32(value); +++ ether_addr_copy(cmd->peer_macaddr.addr, mac); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv ap ps param\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_scan_chan_list(struct ath10k *ar, +++ const struct wmi_scan_chan_list_arg *arg) +++{ +++ struct wmi_tlv_scan_chan_list_cmd *cmd; +++ struct wmi_channel *ci; +++ struct wmi_channel_arg *ch; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ size_t chans_len, len; +++ int i; +++ void *ptr, *chans; +++ +++ chans_len = arg->n_channels * (sizeof(*tlv) + sizeof(*ci)); +++ len = (sizeof(*tlv) + sizeof(*cmd)) + +++ (sizeof(*tlv) + chans_len); +++ +++ skb = ath10k_wmi_alloc_skb(ar, len); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ ptr = (void *)skb->data; +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_SCAN_CHAN_LIST_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->num_scan_chans = __cpu_to_le32(arg->n_channels); +++ +++ ptr += sizeof(*tlv); +++ ptr += sizeof(*cmd); +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT); +++ tlv->len = __cpu_to_le16(chans_len); +++ chans = (void *)tlv->value; +++ +++ for (i = 0; i < arg->n_channels; i++) { +++ ch = &arg->channels[i]; +++ +++ tlv = chans; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_CHANNEL); +++ tlv->len = __cpu_to_le16(sizeof(*ci)); +++ ci = (void *)tlv->value; +++ +++ ath10k_wmi_put_wmi_channel(ci, ch); +++ +++ chans += sizeof(*tlv); +++ chans += sizeof(*ci); +++ } +++ +++ ptr += sizeof(*tlv); +++ ptr += chans_len; +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv scan chan list\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_beacon_dma(struct ath10k *ar, u32 vdev_id, +++ const void *bcn, size_t bcn_len, +++ u32 bcn_paddr, bool dtim_zero, +++ bool deliver_cab) +++ +++{ +++ struct wmi_bcn_tx_ref_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ struct ieee80211_hdr *hdr; +++ u16 fc; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ hdr = (struct ieee80211_hdr *)bcn; +++ fc = le16_to_cpu(hdr->frame_control); +++ +++ tlv = (void *)skb->data; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_BCN_SEND_FROM_HOST_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ cmd->data_len = __cpu_to_le32(bcn_len); +++ cmd->data_ptr = __cpu_to_le32(bcn_paddr); +++ cmd->msdu_id = 0; +++ cmd->frame_control = __cpu_to_le32(fc); +++ cmd->flags = 0; +++ +++ if (dtim_zero) +++ cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO); +++ +++ if (deliver_cab) +++ cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DELIVER_CAB); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv beacon dma\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_pdev_set_wmm(struct ath10k *ar, +++ const struct wmi_wmm_params_all_arg *arg) +++{ +++ struct wmi_tlv_pdev_set_wmm_cmd *cmd; +++ struct wmi_wmm_params *wmm; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ size_t len; +++ void *ptr; +++ +++ len = (sizeof(*tlv) + sizeof(*cmd)) + +++ (4 * (sizeof(*tlv) + sizeof(*wmm))); +++ skb = ath10k_wmi_alloc_skb(ar, len); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ ptr = (void *)skb->data; +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SET_WMM_PARAMS_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ +++ /* nothing to set here */ +++ +++ ptr += sizeof(*tlv); +++ ptr += sizeof(*cmd); +++ +++ ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_be); +++ ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_bk); +++ ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_vi); +++ ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_vo); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev set wmm\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask) +++{ +++ struct wmi_request_stats_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ tlv = (void *)skb->data; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_REQUEST_STATS_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->stats_id = __cpu_to_le32(stats_mask); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv request stats\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_force_fw_hang(struct ath10k *ar, +++ enum wmi_force_fw_hang_type type, +++ u32 delay_ms) +++{ +++ struct wmi_force_fw_hang_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ +++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ tlv = (void *)skb->data; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_FORCE_FW_HANG_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->type = __cpu_to_le32(type); +++ cmd->delay_ms = __cpu_to_le32(delay_ms); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv force fw hang\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_dbglog_cfg(struct ath10k *ar, u32 module_enable, +++ u32 log_level) { +++ struct wmi_tlv_dbglog_cmd *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ size_t len, bmap_len; +++ u32 value; +++ void *ptr; +++ +++ if (module_enable) { +++ value = WMI_TLV_DBGLOG_LOG_LEVEL_VALUE( +++ module_enable, +++ WMI_TLV_DBGLOG_LOG_LEVEL_VERBOSE); +++ } else { +++ value = WMI_TLV_DBGLOG_LOG_LEVEL_VALUE( +++ WMI_TLV_DBGLOG_ALL_MODULES, +++ WMI_TLV_DBGLOG_LOG_LEVEL_WARN); +++ } +++ +++ bmap_len = 0; +++ len = sizeof(*tlv) + sizeof(*cmd) + sizeof(*tlv) + bmap_len; +++ skb = ath10k_wmi_alloc_skb(ar, len); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ ptr = (void *)skb->data; +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_DEBUG_LOG_CONFIG_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->param = __cpu_to_le32(WMI_TLV_DBGLOG_PARAM_LOG_LEVEL); +++ cmd->value = __cpu_to_le32(value); +++ +++ ptr += sizeof(*tlv); +++ ptr += sizeof(*cmd); +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_UINT32); +++ tlv->len = __cpu_to_le16(bmap_len); +++ +++ /* nothing to do here */ +++ +++ ptr += sizeof(*tlv); +++ ptr += sizeof(bmap_len); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv dbglog value 0x%08x\n", value); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_pktlog_enable(struct ath10k *ar, u32 filter) +++{ +++ struct wmi_tlv_pktlog_enable *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ void *ptr; +++ size_t len; +++ +++ len = sizeof(*tlv) + sizeof(*cmd); +++ skb = ath10k_wmi_alloc_skb(ar, len); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ ptr = (void *)skb->data; +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_ENABLE_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->filter = __cpu_to_le32(filter); +++ +++ ptr += sizeof(*tlv); +++ ptr += sizeof(*cmd); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pktlog enable filter 0x%08x\n", +++ filter); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_pktlog_disable(struct ath10k *ar) +++{ +++ struct wmi_tlv_pktlog_disable *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ void *ptr; +++ size_t len; +++ +++ len = sizeof(*tlv) + sizeof(*cmd); +++ skb = ath10k_wmi_alloc_skb(ar, len); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ ptr = (void *)skb->data; +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_DISABLE_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ +++ ptr += sizeof(*tlv); +++ ptr += sizeof(*cmd); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pktlog disable\n"); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_bcn_tmpl(struct ath10k *ar, u32 vdev_id, +++ u32 tim_ie_offset, struct sk_buff *bcn, +++ u32 prb_caps, u32 prb_erp, void *prb_ies, +++ size_t prb_ies_len) +++{ +++ struct wmi_tlv_bcn_tmpl_cmd *cmd; +++ struct wmi_tlv_bcn_prb_info *info; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ void *ptr; +++ size_t len; +++ +++ if (WARN_ON(prb_ies_len > 0 && !prb_ies)) +++ return ERR_PTR(-EINVAL); +++ +++ len = sizeof(*tlv) + sizeof(*cmd) + +++ sizeof(*tlv) + sizeof(*info) + prb_ies_len + +++ sizeof(*tlv) + roundup(bcn->len, 4); +++ skb = ath10k_wmi_alloc_skb(ar, len); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ ptr = (void *)skb->data; +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_BCN_TMPL_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ cmd->tim_ie_offset = __cpu_to_le32(tim_ie_offset); +++ cmd->buf_len = __cpu_to_le32(bcn->len); +++ +++ ptr += sizeof(*tlv); +++ ptr += sizeof(*cmd); +++ +++ /* FIXME: prb_ies_len should be probably aligned to 4byte boundary but +++ * then it is then impossible to pass original ie len. +++ * This chunk is not used yet so if setting probe resp template yields +++ * problems with beaconing or crashes firmware look here. +++ */ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_BCN_PRB_INFO); +++ tlv->len = __cpu_to_le16(sizeof(*info) + prb_ies_len); +++ info = (void *)tlv->value; +++ info->caps = __cpu_to_le32(prb_caps); +++ info->erp = __cpu_to_le32(prb_erp); +++ memcpy(info->ies, prb_ies, prb_ies_len); +++ +++ ptr += sizeof(*tlv); +++ ptr += sizeof(*info); +++ ptr += prb_ies_len; +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE); +++ tlv->len = __cpu_to_le16(roundup(bcn->len, 4)); +++ memcpy(tlv->value, bcn->data, bcn->len); +++ +++ /* FIXME: Adjust TSF? */ +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv bcn tmpl vdev_id %i\n", +++ vdev_id); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_prb_tmpl(struct ath10k *ar, u32 vdev_id, +++ struct sk_buff *prb) +++{ +++ struct wmi_tlv_prb_tmpl_cmd *cmd; +++ struct wmi_tlv_bcn_prb_info *info; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ void *ptr; +++ size_t len; +++ +++ len = sizeof(*tlv) + sizeof(*cmd) + +++ sizeof(*tlv) + sizeof(*info) + +++ sizeof(*tlv) + roundup(prb->len, 4); +++ skb = ath10k_wmi_alloc_skb(ar, len); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ ptr = (void *)skb->data; +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PRB_TMPL_CMD); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ cmd->buf_len = __cpu_to_le32(prb->len); +++ +++ ptr += sizeof(*tlv); +++ ptr += sizeof(*cmd); +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_BCN_PRB_INFO); +++ tlv->len = __cpu_to_le16(sizeof(*info)); +++ info = (void *)tlv->value; +++ info->caps = 0; +++ info->erp = 0; +++ +++ ptr += sizeof(*tlv); +++ ptr += sizeof(*info); +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE); +++ tlv->len = __cpu_to_le16(roundup(prb->len, 4)); +++ memcpy(tlv->value, prb->data, prb->len); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv prb tmpl vdev_id %i\n", +++ vdev_id); +++ return skb; +++} +++ +++static struct sk_buff * +++ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie(struct ath10k *ar, u32 vdev_id, +++ const u8 *p2p_ie) +++{ +++ struct wmi_tlv_p2p_go_bcn_ie *cmd; +++ struct wmi_tlv *tlv; +++ struct sk_buff *skb; +++ void *ptr; +++ size_t len; +++ +++ len = sizeof(*tlv) + sizeof(*cmd) + +++ sizeof(*tlv) + roundup(p2p_ie[1] + 2, 4); +++ skb = ath10k_wmi_alloc_skb(ar, len); +++ if (!skb) +++ return ERR_PTR(-ENOMEM); +++ +++ ptr = (void *)skb->data; +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_P2P_GO_SET_BEACON_IE); +++ tlv->len = __cpu_to_le16(sizeof(*cmd)); +++ cmd = (void *)tlv->value; +++ cmd->vdev_id = __cpu_to_le32(vdev_id); +++ cmd->ie_len = __cpu_to_le32(p2p_ie[1] + 2); +++ +++ ptr += sizeof(*tlv); +++ ptr += sizeof(*cmd); +++ +++ tlv = ptr; +++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE); +++ tlv->len = __cpu_to_le16(roundup(p2p_ie[1] + 2, 4)); +++ memcpy(tlv->value, p2p_ie, p2p_ie[1] + 2); +++ +++ ptr += sizeof(*tlv); +++ ptr += roundup(p2p_ie[1] + 2, 4); +++ +++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv p2p go bcn ie for vdev %i\n", +++ vdev_id); +++ return skb; +++} +++ +++/****************/ +++/* TLV mappings */ +++/****************/ +++ +++static struct wmi_cmd_map wmi_tlv_cmd_map = { +++ .init_cmdid = WMI_TLV_INIT_CMDID, +++ .start_scan_cmdid = WMI_TLV_START_SCAN_CMDID, +++ .stop_scan_cmdid = WMI_TLV_STOP_SCAN_CMDID, +++ .scan_chan_list_cmdid = WMI_TLV_SCAN_CHAN_LIST_CMDID, +++ .scan_sch_prio_tbl_cmdid = WMI_TLV_SCAN_SCH_PRIO_TBL_CMDID, +++ .pdev_set_regdomain_cmdid = WMI_TLV_PDEV_SET_REGDOMAIN_CMDID, +++ .pdev_set_channel_cmdid = WMI_TLV_PDEV_SET_CHANNEL_CMDID, +++ .pdev_set_param_cmdid = WMI_TLV_PDEV_SET_PARAM_CMDID, +++ .pdev_pktlog_enable_cmdid = WMI_TLV_PDEV_PKTLOG_ENABLE_CMDID, +++ .pdev_pktlog_disable_cmdid = WMI_TLV_PDEV_PKTLOG_DISABLE_CMDID, +++ .pdev_set_wmm_params_cmdid = WMI_TLV_PDEV_SET_WMM_PARAMS_CMDID, +++ .pdev_set_ht_cap_ie_cmdid = WMI_TLV_PDEV_SET_HT_CAP_IE_CMDID, +++ .pdev_set_vht_cap_ie_cmdid = WMI_TLV_PDEV_SET_VHT_CAP_IE_CMDID, +++ .pdev_set_dscp_tid_map_cmdid = WMI_TLV_PDEV_SET_DSCP_TID_MAP_CMDID, +++ .pdev_set_quiet_mode_cmdid = WMI_TLV_PDEV_SET_QUIET_MODE_CMDID, +++ .pdev_green_ap_ps_enable_cmdid = WMI_TLV_PDEV_GREEN_AP_PS_ENABLE_CMDID, +++ .pdev_get_tpc_config_cmdid = WMI_TLV_PDEV_GET_TPC_CONFIG_CMDID, +++ .pdev_set_base_macaddr_cmdid = WMI_TLV_PDEV_SET_BASE_MACADDR_CMDID, +++ .vdev_create_cmdid = WMI_TLV_VDEV_CREATE_CMDID, +++ .vdev_delete_cmdid = WMI_TLV_VDEV_DELETE_CMDID, +++ .vdev_start_request_cmdid = WMI_TLV_VDEV_START_REQUEST_CMDID, +++ .vdev_restart_request_cmdid = WMI_TLV_VDEV_RESTART_REQUEST_CMDID, +++ .vdev_up_cmdid = WMI_TLV_VDEV_UP_CMDID, +++ .vdev_stop_cmdid = WMI_TLV_VDEV_STOP_CMDID, +++ .vdev_down_cmdid = WMI_TLV_VDEV_DOWN_CMDID, +++ .vdev_set_param_cmdid = WMI_TLV_VDEV_SET_PARAM_CMDID, +++ .vdev_install_key_cmdid = WMI_TLV_VDEV_INSTALL_KEY_CMDID, +++ .peer_create_cmdid = WMI_TLV_PEER_CREATE_CMDID, +++ .peer_delete_cmdid = WMI_TLV_PEER_DELETE_CMDID, +++ .peer_flush_tids_cmdid = WMI_TLV_PEER_FLUSH_TIDS_CMDID, +++ .peer_set_param_cmdid = WMI_TLV_PEER_SET_PARAM_CMDID, +++ .peer_assoc_cmdid = WMI_TLV_PEER_ASSOC_CMDID, +++ .peer_add_wds_entry_cmdid = WMI_TLV_PEER_ADD_WDS_ENTRY_CMDID, +++ .peer_remove_wds_entry_cmdid = WMI_TLV_PEER_REMOVE_WDS_ENTRY_CMDID, +++ .peer_mcast_group_cmdid = WMI_TLV_PEER_MCAST_GROUP_CMDID, +++ .bcn_tx_cmdid = WMI_TLV_BCN_TX_CMDID, +++ .pdev_send_bcn_cmdid = WMI_TLV_PDEV_SEND_BCN_CMDID, +++ .bcn_tmpl_cmdid = WMI_TLV_BCN_TMPL_CMDID, +++ .bcn_filter_rx_cmdid = WMI_TLV_BCN_FILTER_RX_CMDID, +++ .prb_req_filter_rx_cmdid = WMI_TLV_PRB_REQ_FILTER_RX_CMDID, +++ .mgmt_tx_cmdid = WMI_TLV_MGMT_TX_CMDID, +++ .prb_tmpl_cmdid = WMI_TLV_PRB_TMPL_CMDID, +++ .addba_clear_resp_cmdid = WMI_TLV_ADDBA_CLEAR_RESP_CMDID, +++ .addba_send_cmdid = WMI_TLV_ADDBA_SEND_CMDID, +++ .addba_status_cmdid = WMI_TLV_ADDBA_STATUS_CMDID, +++ .delba_send_cmdid = WMI_TLV_DELBA_SEND_CMDID, +++ .addba_set_resp_cmdid = WMI_TLV_ADDBA_SET_RESP_CMDID, +++ .send_singleamsdu_cmdid = WMI_TLV_SEND_SINGLEAMSDU_CMDID, +++ .sta_powersave_mode_cmdid = WMI_TLV_STA_POWERSAVE_MODE_CMDID, +++ .sta_powersave_param_cmdid = WMI_TLV_STA_POWERSAVE_PARAM_CMDID, +++ .sta_mimo_ps_mode_cmdid = WMI_TLV_STA_MIMO_PS_MODE_CMDID, +++ .pdev_dfs_enable_cmdid = WMI_TLV_PDEV_DFS_ENABLE_CMDID, +++ .pdev_dfs_disable_cmdid = WMI_TLV_PDEV_DFS_DISABLE_CMDID, +++ .roam_scan_mode = WMI_TLV_ROAM_SCAN_MODE, +++ .roam_scan_rssi_threshold = WMI_TLV_ROAM_SCAN_RSSI_THRESHOLD, +++ .roam_scan_period = WMI_TLV_ROAM_SCAN_PERIOD, +++ .roam_scan_rssi_change_threshold = +++ WMI_TLV_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, +++ .roam_ap_profile = WMI_TLV_ROAM_AP_PROFILE, +++ .ofl_scan_add_ap_profile = WMI_TLV_ROAM_AP_PROFILE, +++ .ofl_scan_remove_ap_profile = WMI_TLV_OFL_SCAN_REMOVE_AP_PROFILE, +++ .ofl_scan_period = WMI_TLV_OFL_SCAN_PERIOD, +++ .p2p_dev_set_device_info = WMI_TLV_P2P_DEV_SET_DEVICE_INFO, +++ .p2p_dev_set_discoverability = WMI_TLV_P2P_DEV_SET_DISCOVERABILITY, +++ .p2p_go_set_beacon_ie = WMI_TLV_P2P_GO_SET_BEACON_IE, +++ .p2p_go_set_probe_resp_ie = WMI_TLV_P2P_GO_SET_PROBE_RESP_IE, +++ .p2p_set_vendor_ie_data_cmdid = WMI_TLV_P2P_SET_VENDOR_IE_DATA_CMDID, +++ .ap_ps_peer_param_cmdid = WMI_TLV_AP_PS_PEER_PARAM_CMDID, +++ .ap_ps_peer_uapsd_coex_cmdid = WMI_TLV_AP_PS_PEER_UAPSD_COEX_CMDID, +++ .peer_rate_retry_sched_cmdid = WMI_TLV_PEER_RATE_RETRY_SCHED_CMDID, +++ .wlan_profile_trigger_cmdid = WMI_TLV_WLAN_PROFILE_TRIGGER_CMDID, +++ .wlan_profile_set_hist_intvl_cmdid = +++ WMI_TLV_WLAN_PROFILE_SET_HIST_INTVL_CMDID, +++ .wlan_profile_get_profile_data_cmdid = +++ WMI_TLV_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, +++ .wlan_profile_enable_profile_id_cmdid = +++ WMI_TLV_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, +++ .wlan_profile_list_profile_id_cmdid = +++ WMI_TLV_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, +++ .pdev_suspend_cmdid = WMI_TLV_PDEV_SUSPEND_CMDID, +++ .pdev_resume_cmdid = WMI_TLV_PDEV_RESUME_CMDID, +++ .add_bcn_filter_cmdid = WMI_TLV_ADD_BCN_FILTER_CMDID, +++ .rmv_bcn_filter_cmdid = WMI_TLV_RMV_BCN_FILTER_CMDID, +++ .wow_add_wake_pattern_cmdid = WMI_TLV_WOW_ADD_WAKE_PATTERN_CMDID, +++ .wow_del_wake_pattern_cmdid = WMI_TLV_WOW_DEL_WAKE_PATTERN_CMDID, +++ .wow_enable_disable_wake_event_cmdid = +++ WMI_TLV_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, +++ .wow_enable_cmdid = WMI_TLV_WOW_ENABLE_CMDID, +++ .wow_hostwakeup_from_sleep_cmdid = +++ WMI_TLV_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, +++ .rtt_measreq_cmdid = WMI_TLV_RTT_MEASREQ_CMDID, +++ .rtt_tsf_cmdid = WMI_TLV_RTT_TSF_CMDID, +++ .vdev_spectral_scan_configure_cmdid = WMI_TLV_SPECTRAL_SCAN_CONF_CMDID, +++ .vdev_spectral_scan_enable_cmdid = WMI_TLV_SPECTRAL_SCAN_ENABLE_CMDID, +++ .request_stats_cmdid = WMI_TLV_REQUEST_STATS_CMDID, +++ .set_arp_ns_offload_cmdid = WMI_TLV_SET_ARP_NS_OFFLOAD_CMDID, +++ .network_list_offload_config_cmdid = +++ WMI_TLV_NETWORK_LIST_OFFLOAD_CONFIG_CMDID, +++ .gtk_offload_cmdid = WMI_TLV_GTK_OFFLOAD_CMDID, +++ .csa_offload_enable_cmdid = WMI_TLV_CSA_OFFLOAD_ENABLE_CMDID, +++ .csa_offload_chanswitch_cmdid = WMI_TLV_CSA_OFFLOAD_CHANSWITCH_CMDID, +++ .chatter_set_mode_cmdid = WMI_TLV_CHATTER_SET_MODE_CMDID, +++ .peer_tid_addba_cmdid = WMI_TLV_PEER_TID_ADDBA_CMDID, +++ .peer_tid_delba_cmdid = WMI_TLV_PEER_TID_DELBA_CMDID, +++ .sta_dtim_ps_method_cmdid = WMI_TLV_STA_DTIM_PS_METHOD_CMDID, +++ .sta_uapsd_auto_trig_cmdid = WMI_TLV_STA_UAPSD_AUTO_TRIG_CMDID, +++ .sta_keepalive_cmd = WMI_TLV_STA_KEEPALIVE_CMDID, +++ .echo_cmdid = WMI_TLV_ECHO_CMDID, +++ .pdev_utf_cmdid = WMI_TLV_PDEV_UTF_CMDID, +++ .dbglog_cfg_cmdid = WMI_TLV_DBGLOG_CFG_CMDID, +++ .pdev_qvit_cmdid = WMI_TLV_PDEV_QVIT_CMDID, +++ .pdev_ftm_intg_cmdid = WMI_TLV_PDEV_FTM_INTG_CMDID, +++ .vdev_set_keepalive_cmdid = WMI_TLV_VDEV_SET_KEEPALIVE_CMDID, +++ .vdev_get_keepalive_cmdid = WMI_TLV_VDEV_GET_KEEPALIVE_CMDID, +++ .force_fw_hang_cmdid = WMI_TLV_FORCE_FW_HANG_CMDID, +++ .gpio_config_cmdid = WMI_TLV_GPIO_CONFIG_CMDID, +++ .gpio_output_cmdid = WMI_TLV_GPIO_OUTPUT_CMDID, +++ .pdev_get_temperature_cmdid = WMI_TLV_CMD_UNSUPPORTED, +++ .vdev_set_wmm_params_cmdid = WMI_TLV_VDEV_SET_WMM_PARAMS_CMDID, +++}; +++ +++static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = { +++ .tx_chain_mask = WMI_TLV_PDEV_PARAM_TX_CHAIN_MASK, +++ .rx_chain_mask = WMI_TLV_PDEV_PARAM_RX_CHAIN_MASK, +++ .txpower_limit2g = WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT2G, +++ .txpower_limit5g = WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT5G, +++ .txpower_scale = WMI_TLV_PDEV_PARAM_TXPOWER_SCALE, +++ .beacon_gen_mode = WMI_TLV_PDEV_PARAM_BEACON_GEN_MODE, +++ .beacon_tx_mode = WMI_TLV_PDEV_PARAM_BEACON_TX_MODE, +++ .resmgr_offchan_mode = WMI_TLV_PDEV_PARAM_RESMGR_OFFCHAN_MODE, +++ .protection_mode = WMI_TLV_PDEV_PARAM_PROTECTION_MODE, +++ .dynamic_bw = WMI_TLV_PDEV_PARAM_DYNAMIC_BW, +++ .non_agg_sw_retry_th = WMI_TLV_PDEV_PARAM_NON_AGG_SW_RETRY_TH, +++ .agg_sw_retry_th = WMI_TLV_PDEV_PARAM_AGG_SW_RETRY_TH, +++ .sta_kickout_th = WMI_TLV_PDEV_PARAM_STA_KICKOUT_TH, +++ .ac_aggrsize_scaling = WMI_TLV_PDEV_PARAM_AC_AGGRSIZE_SCALING, +++ .ltr_enable = WMI_TLV_PDEV_PARAM_LTR_ENABLE, +++ .ltr_ac_latency_be = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BE, +++ .ltr_ac_latency_bk = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BK, +++ .ltr_ac_latency_vi = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VI, +++ .ltr_ac_latency_vo = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VO, +++ .ltr_ac_latency_timeout = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT, +++ .ltr_sleep_override = WMI_TLV_PDEV_PARAM_LTR_SLEEP_OVERRIDE, +++ .ltr_rx_override = WMI_TLV_PDEV_PARAM_LTR_RX_OVERRIDE, +++ .ltr_tx_activity_timeout = WMI_TLV_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT, +++ .l1ss_enable = WMI_TLV_PDEV_PARAM_L1SS_ENABLE, +++ .dsleep_enable = WMI_TLV_PDEV_PARAM_DSLEEP_ENABLE, +++ .pcielp_txbuf_flush = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_FLUSH, +++ .pcielp_txbuf_watermark = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_EN, +++ .pcielp_txbuf_tmo_en = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_EN, +++ .pcielp_txbuf_tmo_value = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE, +++ .pdev_stats_update_period = WMI_TLV_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD, +++ .vdev_stats_update_period = WMI_TLV_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD, +++ .peer_stats_update_period = WMI_TLV_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD, +++ .bcnflt_stats_update_period = +++ WMI_TLV_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, +++ .pmf_qos = WMI_TLV_PDEV_PARAM_PMF_QOS, +++ .arp_ac_override = WMI_TLV_PDEV_PARAM_ARP_AC_OVERRIDE, +++ .dcs = WMI_TLV_PDEV_PARAM_DCS, +++ .ani_enable = WMI_TLV_PDEV_PARAM_ANI_ENABLE, +++ .ani_poll_period = WMI_TLV_PDEV_PARAM_ANI_POLL_PERIOD, +++ .ani_listen_period = WMI_TLV_PDEV_PARAM_ANI_LISTEN_PERIOD, +++ .ani_ofdm_level = WMI_TLV_PDEV_PARAM_ANI_OFDM_LEVEL, +++ .ani_cck_level = WMI_TLV_PDEV_PARAM_ANI_CCK_LEVEL, +++ .dyntxchain = WMI_TLV_PDEV_PARAM_DYNTXCHAIN, +++ .proxy_sta = WMI_TLV_PDEV_PARAM_PROXY_STA, +++ .idle_ps_config = WMI_TLV_PDEV_PARAM_IDLE_PS_CONFIG, +++ .power_gating_sleep = WMI_TLV_PDEV_PARAM_POWER_GATING_SLEEP, +++ .fast_channel_reset = WMI_TLV_PDEV_PARAM_UNSUPPORTED, +++ .burst_dur = WMI_TLV_PDEV_PARAM_BURST_DUR, +++ .burst_enable = WMI_TLV_PDEV_PARAM_BURST_ENABLE, +++ .cal_period = WMI_PDEV_PARAM_UNSUPPORTED, +++}; +++ +++static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = { +++ .rts_threshold = WMI_TLV_VDEV_PARAM_RTS_THRESHOLD, +++ .fragmentation_threshold = WMI_TLV_VDEV_PARAM_FRAGMENTATION_THRESHOLD, +++ .beacon_interval = WMI_TLV_VDEV_PARAM_BEACON_INTERVAL, +++ .listen_interval = WMI_TLV_VDEV_PARAM_LISTEN_INTERVAL, +++ .multicast_rate = WMI_TLV_VDEV_PARAM_MULTICAST_RATE, +++ .mgmt_tx_rate = WMI_TLV_VDEV_PARAM_MGMT_TX_RATE, +++ .slot_time = WMI_TLV_VDEV_PARAM_SLOT_TIME, +++ .preamble = WMI_TLV_VDEV_PARAM_PREAMBLE, +++ .swba_time = WMI_TLV_VDEV_PARAM_SWBA_TIME, +++ .wmi_vdev_stats_update_period = WMI_TLV_VDEV_STATS_UPDATE_PERIOD, +++ .wmi_vdev_pwrsave_ageout_time = WMI_TLV_VDEV_PWRSAVE_AGEOUT_TIME, +++ .wmi_vdev_host_swba_interval = WMI_TLV_VDEV_HOST_SWBA_INTERVAL, +++ .dtim_period = WMI_TLV_VDEV_PARAM_DTIM_PERIOD, +++ .wmi_vdev_oc_scheduler_air_time_limit = +++ WMI_TLV_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT, +++ .wds = WMI_TLV_VDEV_PARAM_WDS, +++ .atim_window = WMI_TLV_VDEV_PARAM_ATIM_WINDOW, +++ .bmiss_count_max = WMI_TLV_VDEV_PARAM_BMISS_COUNT_MAX, +++ .bmiss_first_bcnt = WMI_TLV_VDEV_PARAM_BMISS_FIRST_BCNT, +++ .bmiss_final_bcnt = WMI_TLV_VDEV_PARAM_BMISS_FINAL_BCNT, +++ .feature_wmm = WMI_TLV_VDEV_PARAM_FEATURE_WMM, +++ .chwidth = WMI_TLV_VDEV_PARAM_CHWIDTH, +++ .chextoffset = WMI_TLV_VDEV_PARAM_CHEXTOFFSET, +++ .disable_htprotection = WMI_TLV_VDEV_PARAM_DISABLE_HTPROTECTION, +++ .sta_quickkickout = WMI_TLV_VDEV_PARAM_STA_QUICKKICKOUT, +++ .mgmt_rate = WMI_TLV_VDEV_PARAM_MGMT_RATE, +++ .protection_mode = WMI_TLV_VDEV_PARAM_PROTECTION_MODE, +++ .fixed_rate = WMI_TLV_VDEV_PARAM_FIXED_RATE, +++ .sgi = WMI_TLV_VDEV_PARAM_SGI, +++ .ldpc = WMI_TLV_VDEV_PARAM_LDPC, +++ .tx_stbc = WMI_TLV_VDEV_PARAM_TX_STBC, +++ .rx_stbc = WMI_TLV_VDEV_PARAM_RX_STBC, +++ .intra_bss_fwd = WMI_TLV_VDEV_PARAM_INTRA_BSS_FWD, +++ .def_keyid = WMI_TLV_VDEV_PARAM_DEF_KEYID, +++ .nss = WMI_TLV_VDEV_PARAM_NSS, +++ .bcast_data_rate = WMI_TLV_VDEV_PARAM_BCAST_DATA_RATE, +++ .mcast_data_rate = WMI_TLV_VDEV_PARAM_MCAST_DATA_RATE, +++ .mcast_indicate = WMI_TLV_VDEV_PARAM_MCAST_INDICATE, +++ .dhcp_indicate = WMI_TLV_VDEV_PARAM_DHCP_INDICATE, +++ .unknown_dest_indicate = WMI_TLV_VDEV_PARAM_UNKNOWN_DEST_INDICATE, +++ .ap_keepalive_min_idle_inactive_time_secs = +++ WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, +++ .ap_keepalive_max_idle_inactive_time_secs = +++ WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, +++ .ap_keepalive_max_unresponsive_time_secs = +++ WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, +++ .ap_enable_nawds = WMI_TLV_VDEV_PARAM_AP_ENABLE_NAWDS, +++ .mcast2ucast_set = WMI_TLV_VDEV_PARAM_UNSUPPORTED, +++ .enable_rtscts = WMI_TLV_VDEV_PARAM_ENABLE_RTSCTS, +++ .txbf = WMI_TLV_VDEV_PARAM_TXBF, +++ .packet_powersave = WMI_TLV_VDEV_PARAM_PACKET_POWERSAVE, +++ .drop_unencry = WMI_TLV_VDEV_PARAM_DROP_UNENCRY, +++ .tx_encap_type = WMI_TLV_VDEV_PARAM_TX_ENCAP_TYPE, +++ .ap_detect_out_of_sync_sleeping_sta_time_secs = +++ WMI_TLV_VDEV_PARAM_UNSUPPORTED, +++}; +++ +++static const struct wmi_ops wmi_tlv_ops = { +++ .rx = ath10k_wmi_tlv_op_rx, +++ .map_svc = wmi_tlv_svc_map, +++ +++ .pull_scan = ath10k_wmi_tlv_op_pull_scan_ev, +++ .pull_mgmt_rx = ath10k_wmi_tlv_op_pull_mgmt_rx_ev, +++ .pull_ch_info = ath10k_wmi_tlv_op_pull_ch_info_ev, +++ .pull_vdev_start = ath10k_wmi_tlv_op_pull_vdev_start_ev, +++ .pull_peer_kick = ath10k_wmi_tlv_op_pull_peer_kick_ev, +++ .pull_swba = ath10k_wmi_tlv_op_pull_swba_ev, +++ .pull_phyerr = ath10k_wmi_tlv_op_pull_phyerr_ev, +++ .pull_svc_rdy = ath10k_wmi_tlv_op_pull_svc_rdy_ev, +++ .pull_rdy = ath10k_wmi_tlv_op_pull_rdy_ev, +++ .pull_fw_stats = ath10k_wmi_tlv_op_pull_fw_stats, +++ +++ .gen_pdev_suspend = ath10k_wmi_tlv_op_gen_pdev_suspend, +++ .gen_pdev_resume = ath10k_wmi_tlv_op_gen_pdev_resume, +++ .gen_pdev_set_rd = ath10k_wmi_tlv_op_gen_pdev_set_rd, +++ .gen_pdev_set_param = ath10k_wmi_tlv_op_gen_pdev_set_param, +++ .gen_init = ath10k_wmi_tlv_op_gen_init, +++ .gen_start_scan = ath10k_wmi_tlv_op_gen_start_scan, +++ .gen_stop_scan = ath10k_wmi_tlv_op_gen_stop_scan, +++ .gen_vdev_create = ath10k_wmi_tlv_op_gen_vdev_create, +++ .gen_vdev_delete = ath10k_wmi_tlv_op_gen_vdev_delete, +++ .gen_vdev_start = ath10k_wmi_tlv_op_gen_vdev_start, +++ .gen_vdev_stop = ath10k_wmi_tlv_op_gen_vdev_stop, +++ .gen_vdev_up = ath10k_wmi_tlv_op_gen_vdev_up, +++ .gen_vdev_down = ath10k_wmi_tlv_op_gen_vdev_down, +++ .gen_vdev_set_param = ath10k_wmi_tlv_op_gen_vdev_set_param, +++ .gen_vdev_install_key = ath10k_wmi_tlv_op_gen_vdev_install_key, +++ .gen_vdev_wmm_conf = ath10k_wmi_tlv_op_gen_vdev_wmm_conf, +++ .gen_peer_create = ath10k_wmi_tlv_op_gen_peer_create, +++ .gen_peer_delete = ath10k_wmi_tlv_op_gen_peer_delete, +++ .gen_peer_flush = ath10k_wmi_tlv_op_gen_peer_flush, +++ .gen_peer_set_param = ath10k_wmi_tlv_op_gen_peer_set_param, +++ .gen_peer_assoc = ath10k_wmi_tlv_op_gen_peer_assoc, +++ .gen_set_psmode = ath10k_wmi_tlv_op_gen_set_psmode, +++ .gen_set_sta_ps = ath10k_wmi_tlv_op_gen_set_sta_ps, +++ .gen_set_ap_ps = ath10k_wmi_tlv_op_gen_set_ap_ps, +++ .gen_scan_chan_list = ath10k_wmi_tlv_op_gen_scan_chan_list, +++ .gen_beacon_dma = ath10k_wmi_tlv_op_gen_beacon_dma, +++ .gen_pdev_set_wmm = ath10k_wmi_tlv_op_gen_pdev_set_wmm, +++ .gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats, +++ .gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang, +++ /* .gen_mgmt_tx = not implemented; HTT is used */ +++ .gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg, +++ .gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable, +++ .gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable, +++ /* .gen_pdev_set_quiet_mode not implemented */ +++ /* .gen_pdev_get_temperature not implemented */ +++ /* .gen_addba_clear_resp not implemented */ +++ /* .gen_addba_send not implemented */ +++ /* .gen_addba_set_resp not implemented */ +++ /* .gen_delba_send not implemented */ +++ .gen_bcn_tmpl = ath10k_wmi_tlv_op_gen_bcn_tmpl, +++ .gen_prb_tmpl = ath10k_wmi_tlv_op_gen_prb_tmpl, +++ .gen_p2p_go_bcn_ie = ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie, +++ .gen_vdev_sta_uapsd = ath10k_wmi_tlv_op_gen_vdev_sta_uapsd, +++ .gen_sta_keepalive = ath10k_wmi_tlv_op_gen_sta_keepalive, +++}; +++ +++/************/ +++/* TLV init */ +++/************/ +++ +++void ath10k_wmi_tlv_attach(struct ath10k *ar) +++{ +++ ar->wmi.cmd = &wmi_tlv_cmd_map; +++ ar->wmi.vdev_param = &wmi_tlv_vdev_param_map; +++ ar->wmi.pdev_param = &wmi_tlv_pdev_param_map; +++ ar->wmi.ops = &wmi_tlv_ops; +++} ++--- /dev/null +++++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h ++@@ -0,0 +1,1459 @@ +++/* +++ * Copyright (c) 2005-2011 Atheros Communications Inc. +++ * Copyright (c) 2011-2014 Qualcomm Atheros, Inc. +++ * +++ * Permission to use, copy, modify, and/or distribute this software for any +++ * purpose with or without fee is hereby granted, provided that the above +++ * copyright notice and this permission notice appear in all copies. +++ * +++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +++ */ +++#ifndef _WMI_TLV_H +++#define _WMI_TLV_H +++ +++#define WMI_TLV_CMD(grp_id) (((grp_id) << 12) | 0x1) +++#define WMI_TLV_EV(grp_id) (((grp_id) << 12) | 0x1) +++#define WMI_TLV_CMD_UNSUPPORTED 0 +++#define WMI_TLV_PDEV_PARAM_UNSUPPORTED 0 +++#define WMI_TLV_VDEV_PARAM_UNSUPPORTED 0 +++ +++enum wmi_tlv_grp_id { +++ WMI_TLV_GRP_START = 0x3, +++ WMI_TLV_GRP_SCAN = WMI_TLV_GRP_START, +++ WMI_TLV_GRP_PDEV, +++ WMI_TLV_GRP_VDEV, +++ WMI_TLV_GRP_PEER, +++ WMI_TLV_GRP_MGMT, +++ WMI_TLV_GRP_BA_NEG, +++ WMI_TLV_GRP_STA_PS, +++ WMI_TLV_GRP_DFS, +++ WMI_TLV_GRP_ROAM, +++ WMI_TLV_GRP_OFL_SCAN, +++ WMI_TLV_GRP_P2P, +++ WMI_TLV_GRP_AP_PS, +++ WMI_TLV_GRP_RATECTL, +++ WMI_TLV_GRP_PROFILE, +++ WMI_TLV_GRP_SUSPEND, +++ WMI_TLV_GRP_BCN_FILTER, +++ WMI_TLV_GRP_WOW, +++ WMI_TLV_GRP_RTT, +++ WMI_TLV_GRP_SPECTRAL, +++ WMI_TLV_GRP_STATS, +++ WMI_TLV_GRP_ARP_NS_OFL, +++ WMI_TLV_GRP_NLO_OFL, +++ WMI_TLV_GRP_GTK_OFL, +++ WMI_TLV_GRP_CSA_OFL, +++ WMI_TLV_GRP_CHATTER, +++ WMI_TLV_GRP_TID_ADDBA, +++ WMI_TLV_GRP_MISC, +++ WMI_TLV_GRP_GPIO, +++ WMI_TLV_GRP_FWTEST, +++ WMI_TLV_GRP_TDLS, +++ WMI_TLV_GRP_RESMGR, +++ WMI_TLV_GRP_STA_SMPS, +++ WMI_TLV_GRP_WLAN_HB, +++ WMI_TLV_GRP_RMC, +++ WMI_TLV_GRP_MHF_OFL, +++ WMI_TLV_GRP_LOCATION_SCAN, +++ WMI_TLV_GRP_OEM, +++ WMI_TLV_GRP_NAN, +++ WMI_TLV_GRP_COEX, +++ WMI_TLV_GRP_OBSS_OFL, +++ WMI_TLV_GRP_LPI, +++ WMI_TLV_GRP_EXTSCAN, +++ WMI_TLV_GRP_DHCP_OFL, +++ WMI_TLV_GRP_IPA, +++ WMI_TLV_GRP_MDNS_OFL, +++ WMI_TLV_GRP_SAP_OFL, +++}; +++ +++enum wmi_tlv_cmd_id { +++ WMI_TLV_INIT_CMDID = 0x1, +++ WMI_TLV_START_SCAN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SCAN), +++ WMI_TLV_STOP_SCAN_CMDID, +++ WMI_TLV_SCAN_CHAN_LIST_CMDID, +++ WMI_TLV_SCAN_SCH_PRIO_TBL_CMDID, +++ WMI_TLV_SCAN_UPDATE_REQUEST_CMDID, +++ WMI_TLV_SCAN_PROB_REQ_OUI_CMDID, +++ WMI_TLV_PDEV_SET_REGDOMAIN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_PDEV), +++ WMI_TLV_PDEV_SET_CHANNEL_CMDID, +++ WMI_TLV_PDEV_SET_PARAM_CMDID, +++ WMI_TLV_PDEV_PKTLOG_ENABLE_CMDID, +++ WMI_TLV_PDEV_PKTLOG_DISABLE_CMDID, +++ WMI_TLV_PDEV_SET_WMM_PARAMS_CMDID, +++ WMI_TLV_PDEV_SET_HT_CAP_IE_CMDID, +++ WMI_TLV_PDEV_SET_VHT_CAP_IE_CMDID, +++ WMI_TLV_PDEV_SET_DSCP_TID_MAP_CMDID, +++ WMI_TLV_PDEV_SET_QUIET_MODE_CMDID, +++ WMI_TLV_PDEV_GREEN_AP_PS_ENABLE_CMDID, +++ WMI_TLV_PDEV_GET_TPC_CONFIG_CMDID, +++ WMI_TLV_PDEV_SET_BASE_MACADDR_CMDID, +++ WMI_TLV_PDEV_DUMP_CMDID, +++ WMI_TLV_PDEV_SET_LED_CONFIG_CMDID, +++ WMI_TLV_PDEV_GET_TEMPERATURE_CMDID, +++ WMI_TLV_PDEV_SET_LED_FLASHING_CMDID, +++ WMI_TLV_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_VDEV), +++ WMI_TLV_VDEV_DELETE_CMDID, +++ WMI_TLV_VDEV_START_REQUEST_CMDID, +++ WMI_TLV_VDEV_RESTART_REQUEST_CMDID, +++ WMI_TLV_VDEV_UP_CMDID, +++ WMI_TLV_VDEV_STOP_CMDID, +++ WMI_TLV_VDEV_DOWN_CMDID, +++ WMI_TLV_VDEV_SET_PARAM_CMDID, +++ WMI_TLV_VDEV_INSTALL_KEY_CMDID, +++ WMI_TLV_VDEV_WNM_SLEEPMODE_CMDID, +++ WMI_TLV_VDEV_WMM_ADDTS_CMDID, +++ WMI_TLV_VDEV_WMM_DELTS_CMDID, +++ WMI_TLV_VDEV_SET_WMM_PARAMS_CMDID, +++ WMI_TLV_VDEV_SET_GTX_PARAMS_CMDID, +++ WMI_TLV_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID, +++ WMI_TLV_VDEV_PLMREQ_START_CMDID, +++ WMI_TLV_VDEV_PLMREQ_STOP_CMDID, +++ WMI_TLV_PEER_CREATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_PEER), +++ WMI_TLV_PEER_DELETE_CMDID, +++ WMI_TLV_PEER_FLUSH_TIDS_CMDID, +++ WMI_TLV_PEER_SET_PARAM_CMDID, +++ WMI_TLV_PEER_ASSOC_CMDID, +++ WMI_TLV_PEER_ADD_WDS_ENTRY_CMDID, +++ WMI_TLV_PEER_REMOVE_WDS_ENTRY_CMDID, +++ WMI_TLV_PEER_MCAST_GROUP_CMDID, +++ WMI_TLV_PEER_INFO_REQ_CMDID, +++ WMI_TLV_PEER_GET_ESTIMATED_LINKSPEED_CMDID, +++ WMI_TLV_BCN_TX_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MGMT), +++ WMI_TLV_PDEV_SEND_BCN_CMDID, +++ WMI_TLV_BCN_TMPL_CMDID, +++ WMI_TLV_BCN_FILTER_RX_CMDID, +++ WMI_TLV_PRB_REQ_FILTER_RX_CMDID, +++ WMI_TLV_MGMT_TX_CMDID, +++ WMI_TLV_PRB_TMPL_CMDID, +++ WMI_TLV_ADDBA_CLEAR_RESP_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_BA_NEG), +++ WMI_TLV_ADDBA_SEND_CMDID, +++ WMI_TLV_ADDBA_STATUS_CMDID, +++ WMI_TLV_DELBA_SEND_CMDID, +++ WMI_TLV_ADDBA_SET_RESP_CMDID, +++ WMI_TLV_SEND_SINGLEAMSDU_CMDID, +++ WMI_TLV_STA_POWERSAVE_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_STA_PS), +++ WMI_TLV_STA_POWERSAVE_PARAM_CMDID, +++ WMI_TLV_STA_MIMO_PS_MODE_CMDID, +++ WMI_TLV_PDEV_DFS_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_DFS), +++ WMI_TLV_PDEV_DFS_DISABLE_CMDID, +++ WMI_TLV_DFS_PHYERR_FILTER_ENA_CMDID, +++ WMI_TLV_DFS_PHYERR_FILTER_DIS_CMDID, +++ WMI_TLV_ROAM_SCAN_MODE = WMI_TLV_CMD(WMI_TLV_GRP_ROAM), +++ WMI_TLV_ROAM_SCAN_RSSI_THRESHOLD, +++ WMI_TLV_ROAM_SCAN_PERIOD, +++ WMI_TLV_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, +++ WMI_TLV_ROAM_AP_PROFILE, +++ WMI_TLV_ROAM_CHAN_LIST, +++ WMI_TLV_ROAM_SCAN_CMD, +++ WMI_TLV_ROAM_SYNCH_COMPLETE, +++ WMI_TLV_ROAM_SET_RIC_REQUEST_CMDID, +++ WMI_TLV_ROAM_INVOKE_CMDID, +++ WMI_TLV_OFL_SCAN_ADD_AP_PROFILE = WMI_TLV_CMD(WMI_TLV_GRP_OFL_SCAN), +++ WMI_TLV_OFL_SCAN_REMOVE_AP_PROFILE, +++ WMI_TLV_OFL_SCAN_PERIOD, +++ WMI_TLV_P2P_DEV_SET_DEVICE_INFO = WMI_TLV_CMD(WMI_TLV_GRP_P2P), +++ WMI_TLV_P2P_DEV_SET_DISCOVERABILITY, +++ WMI_TLV_P2P_GO_SET_BEACON_IE, +++ WMI_TLV_P2P_GO_SET_PROBE_RESP_IE, +++ WMI_TLV_P2P_SET_VENDOR_IE_DATA_CMDID, +++ WMI_TLV_P2P_DISC_OFFLOAD_CONFIG_CMDID, +++ WMI_TLV_P2P_DISC_OFFLOAD_APPIE_CMDID, +++ WMI_TLV_P2P_DISC_OFFLOAD_PATTERN_CMDID, +++ WMI_TLV_P2P_SET_OPPPS_PARAM_CMDID, +++ WMI_TLV_AP_PS_PEER_PARAM_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_AP_PS), +++ WMI_TLV_AP_PS_PEER_UAPSD_COEX_CMDID, +++ WMI_TLV_PEER_RATE_RETRY_SCHED_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RATECTL), +++ WMI_TLV_WLAN_PROFILE_TRIGGER_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_PROFILE), +++ WMI_TLV_WLAN_PROFILE_SET_HIST_INTVL_CMDID, +++ WMI_TLV_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, +++ WMI_TLV_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, +++ WMI_TLV_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, +++ WMI_TLV_PDEV_SUSPEND_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SUSPEND), +++ WMI_TLV_PDEV_RESUME_CMDID, +++ WMI_TLV_ADD_BCN_FILTER_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_BCN_FILTER), +++ WMI_TLV_RMV_BCN_FILTER_CMDID, +++ WMI_TLV_WOW_ADD_WAKE_PATTERN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_WOW), +++ WMI_TLV_WOW_DEL_WAKE_PATTERN_CMDID, +++ WMI_TLV_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, +++ WMI_TLV_WOW_ENABLE_CMDID, +++ WMI_TLV_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, +++ WMI_TLV_WOW_ACER_IOAC_ADD_KEEPALIVE_CMDID, +++ WMI_TLV_WOW_ACER_IOAC_DEL_KEEPALIVE_CMDID, +++ WMI_TLV_WOW_ACER_IOAC_ADD_WAKE_PATTERN_CMDID, +++ WMI_TLV_WOW_ACER_IOAC_DEL_WAKE_PATTERN_CMDID, +++ WMI_TLV_D0_WOW_ENABLE_DISABLE_CMDID, +++ WMI_TLV_EXTWOW_ENABLE_CMDID, +++ WMI_TLV_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID, +++ WMI_TLV_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID, +++ WMI_TLV_RTT_MEASREQ_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RTT), +++ WMI_TLV_RTT_TSF_CMDID, +++ WMI_TLV_SPECTRAL_SCAN_CONF_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SPECTRAL), +++ WMI_TLV_SPECTRAL_SCAN_ENABLE_CMDID, +++ WMI_TLV_REQUEST_STATS_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_STATS), +++ WMI_TLV_MCC_SCHED_TRAFFIC_STATS_CMDID, +++ WMI_TLV_REQUEST_STATS_EXT_CMDID, +++ WMI_TLV_REQUEST_LINK_STATS_CMDID, +++ WMI_TLV_START_LINK_STATS_CMDID, +++ WMI_TLV_CLEAR_LINK_STATS_CMDID, +++ WMI_TLV_SET_ARP_NS_OFFLOAD_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_ARP_NS_OFL), +++ WMI_TLV_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID, +++ WMI_TLV_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID, +++ WMI_TLV_NETWORK_LIST_OFFLOAD_CONFIG_CMDID = +++ WMI_TLV_CMD(WMI_TLV_GRP_NLO_OFL), +++ WMI_TLV_APFIND_CMDID, +++ WMI_TLV_GTK_OFFLOAD_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_GTK_OFL), +++ WMI_TLV_CSA_OFFLOAD_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_CSA_OFL), +++ WMI_TLV_CSA_OFFLOAD_CHANSWITCH_CMDID, +++ WMI_TLV_CHATTER_SET_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_CHATTER), +++ WMI_TLV_CHATTER_ADD_COALESCING_FILTER_CMDID, +++ WMI_TLV_CHATTER_DELETE_COALESCING_FILTER_CMDID, +++ WMI_TLV_CHATTER_COALESCING_QUERY_CMDID, +++ WMI_TLV_PEER_TID_ADDBA_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_TID_ADDBA), +++ WMI_TLV_PEER_TID_DELBA_CMDID, +++ WMI_TLV_STA_DTIM_PS_METHOD_CMDID, +++ WMI_TLV_STA_UAPSD_AUTO_TRIG_CMDID, +++ WMI_TLV_STA_KEEPALIVE_CMDID, +++ WMI_TLV_BA_REQ_SSN_CMDID, +++ WMI_TLV_ECHO_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MISC), +++ WMI_TLV_PDEV_UTF_CMDID, +++ WMI_TLV_DBGLOG_CFG_CMDID, +++ WMI_TLV_PDEV_QVIT_CMDID, +++ WMI_TLV_PDEV_FTM_INTG_CMDID, +++ WMI_TLV_VDEV_SET_KEEPALIVE_CMDID, +++ WMI_TLV_VDEV_GET_KEEPALIVE_CMDID, +++ WMI_TLV_FORCE_FW_HANG_CMDID, +++ WMI_TLV_SET_MCASTBCAST_FILTER_CMDID, +++ WMI_TLV_THERMAL_MGMT_CMDID, +++ WMI_TLV_HOST_AUTO_SHUTDOWN_CFG_CMDID, +++ WMI_TLV_TPC_CHAINMASK_CONFIG_CMDID, +++ WMI_TLV_SET_ANTENNA_DIVERSITY_CMDID, +++ WMI_TLV_GPIO_CONFIG_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_GPIO), +++ WMI_TLV_GPIO_OUTPUT_CMDID, +++ WMI_TLV_TXBF_CMDID, +++ WMI_TLV_FWTEST_VDEV_MCC_SET_TBTT_MODE_CMDID = +++ WMI_TLV_CMD(WMI_TLV_GRP_FWTEST), +++ WMI_TLV_FWTEST_P2P_SET_NOA_PARAM_CMDID, +++ WMI_TLV_UNIT_TEST_CMDID, +++ WMI_TLV_TDLS_SET_STATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_TDLS), +++ WMI_TLV_TDLS_PEER_UPDATE_CMDID, +++ WMI_TLV_TDLS_SET_OFFCHAN_MODE_CMDID, +++ WMI_TLV_RESMGR_ADAPTIVE_OCS_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RESMGR), +++ WMI_TLV_RESMGR_SET_CHAN_TIME_QUOTA_CMDID, +++ WMI_TLV_RESMGR_SET_CHAN_LATENCY_CMDID, +++ WMI_TLV_STA_SMPS_FORCE_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_STA_SMPS), +++ WMI_TLV_STA_SMPS_PARAM_CMDID, +++ WMI_TLV_HB_SET_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_WLAN_HB), +++ WMI_TLV_HB_SET_TCP_PARAMS_CMDID, +++ WMI_TLV_HB_SET_TCP_PKT_FILTER_CMDID, +++ WMI_TLV_HB_SET_UDP_PARAMS_CMDID, +++ WMI_TLV_HB_SET_UDP_PKT_FILTER_CMDID, +++ WMI_TLV_RMC_SET_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RMC), +++ WMI_TLV_RMC_SET_ACTION_PERIOD_CMDID, +++ WMI_TLV_RMC_CONFIG_CMDID, +++ WMI_TLV_MHF_OFFLOAD_SET_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MHF_OFL), +++ WMI_TLV_MHF_OFFLOAD_PLUMB_ROUTING_TBL_CMDID, +++ WMI_TLV_BATCH_SCAN_ENABLE_CMDID = +++ WMI_TLV_CMD(WMI_TLV_GRP_LOCATION_SCAN), +++ WMI_TLV_BATCH_SCAN_DISABLE_CMDID, +++ WMI_TLV_BATCH_SCAN_TRIGGER_RESULT_CMDID, +++ WMI_TLV_OEM_REQ_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_OEM), +++ WMI_TLV_NAN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_NAN), +++ WMI_TLV_MODEM_POWER_STATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_COEX), +++ WMI_TLV_CHAN_AVOID_UPDATE_CMDID, +++ WMI_TLV_OBSS_SCAN_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_OBSS_OFL), +++ WMI_TLV_OBSS_SCAN_DISABLE_CMDID, +++ WMI_TLV_LPI_MGMT_SNOOPING_CONFIG_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_LPI), +++ WMI_TLV_LPI_START_SCAN_CMDID, +++ WMI_TLV_LPI_STOP_SCAN_CMDID, +++ WMI_TLV_EXTSCAN_START_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_EXTSCAN), +++ WMI_TLV_EXTSCAN_STOP_CMDID, +++ WMI_TLV_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID, +++ WMI_TLV_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID, +++ WMI_TLV_EXTSCAN_GET_CACHED_RESULTS_CMDID, +++ WMI_TLV_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID, +++ WMI_TLV_EXTSCAN_SET_CAPABILITIES_CMDID, +++ WMI_TLV_EXTSCAN_GET_CAPABILITIES_CMDID, +++ WMI_TLV_SET_DHCP_SERVER_OFFLOAD_CMDID = +++ WMI_TLV_CMD(WMI_TLV_GRP_DHCP_OFL), +++ WMI_TLV_IPA_OFFLOAD_ENABLE_DISABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_IPA), +++ WMI_TLV_MDNS_OFFLOAD_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MDNS_OFL), +++ WMI_TLV_MDNS_SET_FQDN_CMDID, +++ WMI_TLV_MDNS_SET_RESPONSE_CMDID, +++ WMI_TLV_MDNS_GET_STATS_CMDID, +++ WMI_TLV_SAP_OFL_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SAP_OFL), +++}; +++ +++enum wmi_tlv_event_id { +++ WMI_TLV_SERVICE_READY_EVENTID = 0x1, +++ WMI_TLV_READY_EVENTID, +++ WMI_TLV_SCAN_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_SCAN), +++ WMI_TLV_PDEV_TPC_CONFIG_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_PDEV), +++ WMI_TLV_CHAN_INFO_EVENTID, +++ WMI_TLV_PHYERR_EVENTID, +++ WMI_TLV_PDEV_DUMP_EVENTID, +++ WMI_TLV_TX_PAUSE_EVENTID, +++ WMI_TLV_DFS_RADAR_EVENTID, +++ WMI_TLV_PDEV_L1SS_TRACK_EVENTID, +++ WMI_TLV_PDEV_TEMPERATURE_EVENTID, +++ WMI_TLV_VDEV_START_RESP_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_VDEV), +++ WMI_TLV_VDEV_STOPPED_EVENTID, +++ WMI_TLV_VDEV_INSTALL_KEY_COMPLETE_EVENTID, +++ WMI_TLV_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID, +++ WMI_TLV_PEER_STA_KICKOUT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_PEER), +++ WMI_TLV_PEER_INFO_EVENTID, +++ WMI_TLV_PEER_TX_FAIL_CNT_THR_EVENTID, +++ WMI_TLV_PEER_ESTIMATED_LINKSPEED_EVENTID, +++ WMI_TLV_PEER_STATE_EVENTID, +++ WMI_TLV_MGMT_RX_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_MGMT), +++ WMI_TLV_HOST_SWBA_EVENTID, +++ WMI_TLV_TBTTOFFSET_UPDATE_EVENTID, +++ WMI_TLV_OFFLOAD_BCN_TX_STATUS_EVENTID, +++ WMI_TLV_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID, +++ WMI_TLV_TX_DELBA_COMPLETE_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_BA_NEG), +++ WMI_TLV_TX_ADDBA_COMPLETE_EVENTID, +++ WMI_TLV_BA_RSP_SSN_EVENTID, +++ WMI_TLV_AGGR_STATE_TRIG_EVENTID, +++ WMI_TLV_ROAM_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_ROAM), +++ WMI_TLV_PROFILE_MATCH, +++ WMI_TLV_ROAM_SYNCH_EVENTID, +++ WMI_TLV_P2P_DISC_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_P2P), +++ WMI_TLV_P2P_NOA_EVENTID, +++ WMI_TLV_PDEV_RESUME_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_SUSPEND), +++ WMI_TLV_WOW_WAKEUP_HOST_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_WOW), +++ WMI_TLV_D0_WOW_DISABLE_ACK_EVENTID, +++ WMI_TLV_RTT_MEASUREMENT_REPORT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_RTT), +++ WMI_TLV_TSF_MEASUREMENT_REPORT_EVENTID, +++ WMI_TLV_RTT_ERROR_REPORT_EVENTID, +++ WMI_TLV_STATS_EXT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_STATS), +++ WMI_TLV_IFACE_LINK_STATS_EVENTID, +++ WMI_TLV_PEER_LINK_STATS_EVENTID, +++ WMI_TLV_RADIO_LINK_STATS_EVENTID, +++ WMI_TLV_NLO_MATCH_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_NLO_OFL), +++ WMI_TLV_NLO_SCAN_COMPLETE_EVENTID, +++ WMI_TLV_APFIND_EVENTID, +++ WMI_TLV_GTK_OFFLOAD_STATUS_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_GTK_OFL), +++ WMI_TLV_GTK_REKEY_FAIL_EVENTID, +++ WMI_TLV_CSA_HANDLING_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_CSA_OFL), +++ WMI_TLV_CHATTER_PC_QUERY_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_CHATTER), +++ WMI_TLV_ECHO_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_MISC), +++ WMI_TLV_PDEV_UTF_EVENTID, +++ WMI_TLV_DEBUG_MESG_EVENTID, +++ WMI_TLV_UPDATE_STATS_EVENTID, +++ WMI_TLV_DEBUG_PRINT_EVENTID, +++ WMI_TLV_DCS_INTERFERENCE_EVENTID, +++ WMI_TLV_PDEV_QVIT_EVENTID, +++ WMI_TLV_WLAN_PROFILE_DATA_EVENTID, +++ WMI_TLV_PDEV_FTM_INTG_EVENTID, +++ WMI_TLV_WLAN_FREQ_AVOID_EVENTID, +++ WMI_TLV_VDEV_GET_KEEPALIVE_EVENTID, +++ WMI_TLV_THERMAL_MGMT_EVENTID, +++ WMI_TLV_DIAG_DATA_CONTAINER_EVENTID, +++ WMI_TLV_HOST_AUTO_SHUTDOWN_EVENTID, +++ WMI_TLV_UPDATE_WHAL_MIB_STATS_EVENTID, +++ WMI_TLV_UPDATE_VDEV_RATE_STATS_EVENTID, +++ WMI_TLV_DIAG_EVENTID, +++ WMI_TLV_GPIO_INPUT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_GPIO), +++ WMI_TLV_UPLOADH_EVENTID, +++ WMI_TLV_CAPTUREH_EVENTID, +++ WMI_TLV_RFKILL_STATE_CHANGE_EVENTID, +++ WMI_TLV_TDLS_PEER_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_TDLS), +++ WMI_TLV_BATCH_SCAN_ENABLED_EVENTID = +++ WMI_TLV_EV(WMI_TLV_GRP_LOCATION_SCAN), +++ WMI_TLV_BATCH_SCAN_RESULT_EVENTID, +++ WMI_TLV_OEM_CAPABILITY_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_OEM), +++ WMI_TLV_OEM_MEASUREMENT_REPORT_EVENTID, +++ WMI_TLV_OEM_ERROR_REPORT_EVENTID, +++ WMI_TLV_NAN_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_NAN), +++ WMI_TLV_LPI_RESULT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_LPI), +++ WMI_TLV_LPI_STATUS_EVENTID, +++ WMI_TLV_LPI_HANDOFF_EVENTID, +++ WMI_TLV_EXTSCAN_START_STOP_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_EXTSCAN), +++ WMI_TLV_EXTSCAN_OPERATION_EVENTID, +++ WMI_TLV_EXTSCAN_TABLE_USAGE_EVENTID, +++ WMI_TLV_EXTSCAN_CACHED_RESULTS_EVENTID, +++ WMI_TLV_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID, +++ WMI_TLV_EXTSCAN_HOTLIST_MATCH_EVENTID, +++ WMI_TLV_EXTSCAN_CAPABILITIES_EVENTID, +++ WMI_TLV_MDNS_STATS_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_MDNS_OFL), +++ WMI_TLV_SAP_OFL_ADD_STA_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_SAP_OFL), +++ WMI_TLV_SAP_OFL_DEL_STA_EVENTID, +++}; +++ +++enum wmi_tlv_pdev_param { +++ WMI_TLV_PDEV_PARAM_TX_CHAIN_MASK = 0x1, +++ WMI_TLV_PDEV_PARAM_RX_CHAIN_MASK, +++ WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT2G, +++ WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT5G, +++ WMI_TLV_PDEV_PARAM_TXPOWER_SCALE, +++ WMI_TLV_PDEV_PARAM_BEACON_GEN_MODE, +++ WMI_TLV_PDEV_PARAM_BEACON_TX_MODE, +++ WMI_TLV_PDEV_PARAM_RESMGR_OFFCHAN_MODE, +++ WMI_TLV_PDEV_PARAM_PROTECTION_MODE, +++ WMI_TLV_PDEV_PARAM_DYNAMIC_BW, +++ WMI_TLV_PDEV_PARAM_NON_AGG_SW_RETRY_TH, +++ WMI_TLV_PDEV_PARAM_AGG_SW_RETRY_TH, +++ WMI_TLV_PDEV_PARAM_STA_KICKOUT_TH, +++ WMI_TLV_PDEV_PARAM_AC_AGGRSIZE_SCALING, +++ WMI_TLV_PDEV_PARAM_LTR_ENABLE, +++ WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BE, +++ WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BK, +++ WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VI, +++ WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VO, +++ WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT, +++ WMI_TLV_PDEV_PARAM_LTR_SLEEP_OVERRIDE, +++ WMI_TLV_PDEV_PARAM_LTR_RX_OVERRIDE, +++ WMI_TLV_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT, +++ WMI_TLV_PDEV_PARAM_L1SS_ENABLE, +++ WMI_TLV_PDEV_PARAM_DSLEEP_ENABLE, +++ WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_FLUSH, +++ WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_WATERMARK, +++ WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_EN, +++ WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE, +++ WMI_TLV_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD, +++ WMI_TLV_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD, +++ WMI_TLV_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD, +++ WMI_TLV_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, +++ WMI_TLV_PDEV_PARAM_PMF_QOS, +++ WMI_TLV_PDEV_PARAM_ARP_AC_OVERRIDE, +++ WMI_TLV_PDEV_PARAM_DCS, +++ WMI_TLV_PDEV_PARAM_ANI_ENABLE, +++ WMI_TLV_PDEV_PARAM_ANI_POLL_PERIOD, +++ WMI_TLV_PDEV_PARAM_ANI_LISTEN_PERIOD, +++ WMI_TLV_PDEV_PARAM_ANI_OFDM_LEVEL, +++ WMI_TLV_PDEV_PARAM_ANI_CCK_LEVEL, +++ WMI_TLV_PDEV_PARAM_DYNTXCHAIN, +++ WMI_TLV_PDEV_PARAM_PROXY_STA, +++ WMI_TLV_PDEV_PARAM_IDLE_PS_CONFIG, +++ WMI_TLV_PDEV_PARAM_POWER_GATING_SLEEP, +++ WMI_TLV_PDEV_PARAM_RFKILL_ENABLE, +++ WMI_TLV_PDEV_PARAM_BURST_DUR, +++ WMI_TLV_PDEV_PARAM_BURST_ENABLE, +++ WMI_TLV_PDEV_PARAM_HW_RFKILL_CONFIG, +++ WMI_TLV_PDEV_PARAM_LOW_POWER_RF_ENABLE, +++ WMI_TLV_PDEV_PARAM_L1SS_TRACK, +++ WMI_TLV_PDEV_PARAM_HYST_EN, +++ WMI_TLV_PDEV_PARAM_POWER_COLLAPSE_ENABLE, +++ WMI_TLV_PDEV_PARAM_LED_SYS_STATE, +++ WMI_TLV_PDEV_PARAM_LED_ENABLE, +++ WMI_TLV_PDEV_PARAM_AUDIO_OVER_WLAN_LATENCY, +++ WMI_TLV_PDEV_PARAM_AUDIO_OVER_WLAN_ENABLE, +++ WMI_TLV_PDEV_PARAM_WHAL_MIB_STATS_UPDATE_ENABLE, +++ WMI_TLV_PDEV_PARAM_VDEV_RATE_STATS_UPDATE_PERIOD, +++ WMI_TLV_PDEV_PARAM_TXPOWER_REASON_NONE, +++ WMI_TLV_PDEV_PARAM_TXPOWER_REASON_SAR, +++ WMI_TLV_PDEV_PARAM_TXPOWER_REASON_MAX, +++}; +++ +++enum wmi_tlv_vdev_param { +++ WMI_TLV_VDEV_PARAM_RTS_THRESHOLD = 0x1, +++ WMI_TLV_VDEV_PARAM_FRAGMENTATION_THRESHOLD, +++ WMI_TLV_VDEV_PARAM_BEACON_INTERVAL, +++ WMI_TLV_VDEV_PARAM_LISTEN_INTERVAL, +++ WMI_TLV_VDEV_PARAM_MULTICAST_RATE, +++ WMI_TLV_VDEV_PARAM_MGMT_TX_RATE, +++ WMI_TLV_VDEV_PARAM_SLOT_TIME, +++ WMI_TLV_VDEV_PARAM_PREAMBLE, +++ WMI_TLV_VDEV_PARAM_SWBA_TIME, +++ WMI_TLV_VDEV_STATS_UPDATE_PERIOD, +++ WMI_TLV_VDEV_PWRSAVE_AGEOUT_TIME, +++ WMI_TLV_VDEV_HOST_SWBA_INTERVAL, +++ WMI_TLV_VDEV_PARAM_DTIM_PERIOD, +++ WMI_TLV_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT, +++ WMI_TLV_VDEV_PARAM_WDS, +++ WMI_TLV_VDEV_PARAM_ATIM_WINDOW, +++ WMI_TLV_VDEV_PARAM_BMISS_COUNT_MAX, +++ WMI_TLV_VDEV_PARAM_BMISS_FIRST_BCNT, +++ WMI_TLV_VDEV_PARAM_BMISS_FINAL_BCNT, +++ WMI_TLV_VDEV_PARAM_FEATURE_WMM, +++ WMI_TLV_VDEV_PARAM_CHWIDTH, +++ WMI_TLV_VDEV_PARAM_CHEXTOFFSET, +++ WMI_TLV_VDEV_PARAM_DISABLE_HTPROTECTION, +++ WMI_TLV_VDEV_PARAM_STA_QUICKKICKOUT, +++ WMI_TLV_VDEV_PARAM_MGMT_RATE, +++ WMI_TLV_VDEV_PARAM_PROTECTION_MODE, +++ WMI_TLV_VDEV_PARAM_FIXED_RATE, +++ WMI_TLV_VDEV_PARAM_SGI, +++ WMI_TLV_VDEV_PARAM_LDPC, +++ WMI_TLV_VDEV_PARAM_TX_STBC, +++ WMI_TLV_VDEV_PARAM_RX_STBC, +++ WMI_TLV_VDEV_PARAM_INTRA_BSS_FWD, +++ WMI_TLV_VDEV_PARAM_DEF_KEYID, +++ WMI_TLV_VDEV_PARAM_NSS, +++ WMI_TLV_VDEV_PARAM_BCAST_DATA_RATE, +++ WMI_TLV_VDEV_PARAM_MCAST_DATA_RATE, +++ WMI_TLV_VDEV_PARAM_MCAST_INDICATE, +++ WMI_TLV_VDEV_PARAM_DHCP_INDICATE, +++ WMI_TLV_VDEV_PARAM_UNKNOWN_DEST_INDICATE, +++ WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, +++ WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, +++ WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, +++ WMI_TLV_VDEV_PARAM_AP_ENABLE_NAWDS, +++ WMI_TLV_VDEV_PARAM_ENABLE_RTSCTS, +++ WMI_TLV_VDEV_PARAM_TXBF, +++ WMI_TLV_VDEV_PARAM_PACKET_POWERSAVE, +++ WMI_TLV_VDEV_PARAM_DROP_UNENCRY, +++ WMI_TLV_VDEV_PARAM_TX_ENCAP_TYPE, +++ WMI_TLV_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, +++ WMI_TLV_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE, +++ WMI_TLV_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM, +++ WMI_TLV_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE, +++ WMI_TLV_VDEV_PARAM_EARLY_RX_SLOP_STEP, +++ WMI_TLV_VDEV_PARAM_EARLY_RX_INIT_SLOP, +++ WMI_TLV_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE, +++ WMI_TLV_VDEV_PARAM_TX_PWRLIMIT, +++ WMI_TLV_VDEV_PARAM_SNR_NUM_FOR_CAL, +++ WMI_TLV_VDEV_PARAM_ROAM_FW_OFFLOAD, +++ WMI_TLV_VDEV_PARAM_ENABLE_RMC, +++ WMI_TLV_VDEV_PARAM_IBSS_MAX_BCN_LOST_MS, +++ WMI_TLV_VDEV_PARAM_MAX_RATE, +++ WMI_TLV_VDEV_PARAM_EARLY_RX_DRIFT_SAMPLE, +++ WMI_TLV_VDEV_PARAM_SET_IBSS_TX_FAIL_CNT_THR, +++ WMI_TLV_VDEV_PARAM_EBT_RESYNC_TIMEOUT, +++ WMI_TLV_VDEV_PARAM_AGGR_TRIG_EVENT_ENABLE, +++ WMI_TLV_VDEV_PARAM_IS_IBSS_POWER_SAVE_ALLOWED, +++ WMI_TLV_VDEV_PARAM_IS_POWER_COLLAPSE_ALLOWED, +++ WMI_TLV_VDEV_PARAM_IS_AWAKE_ON_TXRX_ENABLED, +++ WMI_TLV_VDEV_PARAM_INACTIVITY_CNT, +++ WMI_TLV_VDEV_PARAM_TXSP_END_INACTIVITY_TIME_MS, +++ WMI_TLV_VDEV_PARAM_DTIM_POLICY, +++ WMI_TLV_VDEV_PARAM_IBSS_PS_WARMUP_TIME_SECS, +++ WMI_TLV_VDEV_PARAM_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE, +++}; +++ +++enum wmi_tlv_tag { +++ WMI_TLV_TAG_LAST_RESERVED = 15, +++ +++ WMI_TLV_TAG_FIRST_ARRAY_ENUM, +++ WMI_TLV_TAG_ARRAY_UINT32 = WMI_TLV_TAG_FIRST_ARRAY_ENUM, +++ WMI_TLV_TAG_ARRAY_BYTE, +++ WMI_TLV_TAG_ARRAY_STRUCT, +++ WMI_TLV_TAG_ARRAY_FIXED_STRUCT, +++ WMI_TLV_TAG_LAST_ARRAY_ENUM = 31, +++ +++ WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT, +++ WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES, +++ WMI_TLV_TAG_STRUCT_WLAN_HOST_MEM_REQ, +++ WMI_TLV_TAG_STRUCT_READY_EVENT, +++ WMI_TLV_TAG_STRUCT_SCAN_EVENT, +++ WMI_TLV_TAG_STRUCT_PDEV_TPC_CONFIG_EVENT, +++ WMI_TLV_TAG_STRUCT_CHAN_INFO_EVENT, +++ WMI_TLV_TAG_STRUCT_COMB_PHYERR_RX_HDR, +++ WMI_TLV_TAG_STRUCT_VDEV_START_RESPONSE_EVENT, +++ WMI_TLV_TAG_STRUCT_VDEV_STOPPED_EVENT, +++ WMI_TLV_TAG_STRUCT_VDEV_INSTALL_KEY_COMPLETE_EVENT, +++ WMI_TLV_TAG_STRUCT_PEER_STA_KICKOUT_EVENT, +++ WMI_TLV_TAG_STRUCT_MGMT_RX_HDR, +++ WMI_TLV_TAG_STRUCT_TBTT_OFFSET_EVENT, +++ WMI_TLV_TAG_STRUCT_TX_DELBA_COMPLETE_EVENT, +++ WMI_TLV_TAG_STRUCT_TX_ADDBA_COMPLETE_EVENT, +++ WMI_TLV_TAG_STRUCT_ROAM_EVENT, +++ WMI_TLV_TAG_STRUCT_WOW_EVENT_INFO, +++ WMI_TLV_TAG_STRUCT_WOW_EVENT_INFO_SECTION_BITMAP, +++ WMI_TLV_TAG_STRUCT_RTT_EVENT_HEADER, +++ WMI_TLV_TAG_STRUCT_RTT_ERROR_REPORT_EVENT, +++ WMI_TLV_TAG_STRUCT_RTT_MEAS_EVENT, +++ WMI_TLV_TAG_STRUCT_ECHO_EVENT, +++ WMI_TLV_TAG_STRUCT_FTM_INTG_EVENT, +++ WMI_TLV_TAG_STRUCT_VDEV_GET_KEEPALIVE_EVENT, +++ WMI_TLV_TAG_STRUCT_GPIO_INPUT_EVENT, +++ WMI_TLV_TAG_STRUCT_CSA_EVENT, +++ WMI_TLV_TAG_STRUCT_GTK_OFFLOAD_STATUS_EVENT, +++ WMI_TLV_TAG_STRUCT_IGTK_INFO, +++ WMI_TLV_TAG_STRUCT_DCS_INTERFERENCE_EVENT, +++ WMI_TLV_TAG_STRUCT_ATH_DCS_CW_INT, +++ WMI_TLV_TAG_STRUCT_ATH_DCS_WLAN_INT_STAT, +++ WMI_TLV_TAG_STRUCT_WLAN_PROFILE_CTX_T, +++ WMI_TLV_TAG_STRUCT_WLAN_PROFILE_T, +++ WMI_TLV_TAG_STRUCT_PDEV_QVIT_EVENT, +++ WMI_TLV_TAG_STRUCT_HOST_SWBA_EVENT, +++ WMI_TLV_TAG_STRUCT_TIM_INFO, +++ WMI_TLV_TAG_STRUCT_P2P_NOA_INFO, +++ WMI_TLV_TAG_STRUCT_STATS_EVENT, +++ WMI_TLV_TAG_STRUCT_AVOID_FREQ_RANGES_EVENT, +++ WMI_TLV_TAG_STRUCT_AVOID_FREQ_RANGE_DESC, +++ WMI_TLV_TAG_STRUCT_GTK_REKEY_FAIL_EVENT, +++ WMI_TLV_TAG_STRUCT_INIT_CMD, +++ WMI_TLV_TAG_STRUCT_RESOURCE_CONFIG, +++ WMI_TLV_TAG_STRUCT_WLAN_HOST_MEMORY_CHUNK, +++ WMI_TLV_TAG_STRUCT_START_SCAN_CMD, +++ WMI_TLV_TAG_STRUCT_STOP_SCAN_CMD, +++ WMI_TLV_TAG_STRUCT_SCAN_CHAN_LIST_CMD, +++ WMI_TLV_TAG_STRUCT_CHANNEL, +++ WMI_TLV_TAG_STRUCT_PDEV_SET_REGDOMAIN_CMD, +++ WMI_TLV_TAG_STRUCT_PDEV_SET_PARAM_CMD, +++ WMI_TLV_TAG_STRUCT_PDEV_SET_WMM_PARAMS_CMD, +++ WMI_TLV_TAG_STRUCT_WMM_PARAMS, +++ WMI_TLV_TAG_STRUCT_PDEV_SET_QUIET_CMD, +++ WMI_TLV_TAG_STRUCT_VDEV_CREATE_CMD, +++ WMI_TLV_TAG_STRUCT_VDEV_DELETE_CMD, +++ WMI_TLV_TAG_STRUCT_VDEV_START_REQUEST_CMD, +++ WMI_TLV_TAG_STRUCT_P2P_NOA_DESCRIPTOR, +++ WMI_TLV_TAG_STRUCT_P2P_GO_SET_BEACON_IE, +++ WMI_TLV_TAG_STRUCT_GTK_OFFLOAD_CMD, +++ WMI_TLV_TAG_STRUCT_VDEV_UP_CMD, +++ WMI_TLV_TAG_STRUCT_VDEV_STOP_CMD, +++ WMI_TLV_TAG_STRUCT_VDEV_DOWN_CMD, +++ WMI_TLV_TAG_STRUCT_VDEV_SET_PARAM_CMD, +++ WMI_TLV_TAG_STRUCT_VDEV_INSTALL_KEY_CMD, +++ WMI_TLV_TAG_STRUCT_PEER_CREATE_CMD, +++ WMI_TLV_TAG_STRUCT_PEER_DELETE_CMD, +++ WMI_TLV_TAG_STRUCT_PEER_FLUSH_TIDS_CMD, +++ WMI_TLV_TAG_STRUCT_PEER_SET_PARAM_CMD, +++ WMI_TLV_TAG_STRUCT_PEER_ASSOC_COMPLETE_CMD, +++ WMI_TLV_TAG_STRUCT_VHT_RATE_SET, +++ WMI_TLV_TAG_STRUCT_BCN_TMPL_CMD, +++ WMI_TLV_TAG_STRUCT_PRB_TMPL_CMD, +++ WMI_TLV_TAG_STRUCT_BCN_PRB_INFO, +++ WMI_TLV_TAG_STRUCT_PEER_TID_ADDBA_CMD, +++ WMI_TLV_TAG_STRUCT_PEER_TID_DELBA_CMD, +++ WMI_TLV_TAG_STRUCT_STA_POWERSAVE_MODE_CMD, +++ WMI_TLV_TAG_STRUCT_STA_POWERSAVE_PARAM_CMD, +++ WMI_TLV_TAG_STRUCT_STA_DTIM_PS_METHOD_CMD, +++ WMI_TLV_TAG_STRUCT_ROAM_SCAN_MODE, +++ WMI_TLV_TAG_STRUCT_ROAM_SCAN_RSSI_THRESHOLD, +++ WMI_TLV_TAG_STRUCT_ROAM_SCAN_PERIOD, +++ WMI_TLV_TAG_STRUCT_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, +++ WMI_TLV_TAG_STRUCT_PDEV_SUSPEND_CMD, +++ WMI_TLV_TAG_STRUCT_PDEV_RESUME_CMD, +++ WMI_TLV_TAG_STRUCT_ADD_BCN_FILTER_CMD, +++ WMI_TLV_TAG_STRUCT_RMV_BCN_FILTER_CMD, +++ WMI_TLV_TAG_STRUCT_WOW_ENABLE_CMD, +++ WMI_TLV_TAG_STRUCT_WOW_HOSTWAKEUP_FROM_SLEEP_CMD, +++ WMI_TLV_TAG_STRUCT_STA_UAPSD_AUTO_TRIG_CMD, +++ WMI_TLV_TAG_STRUCT_STA_UAPSD_AUTO_TRIG_PARAM, +++ WMI_TLV_TAG_STRUCT_SET_ARP_NS_OFFLOAD_CMD, +++ WMI_TLV_TAG_STRUCT_ARP_OFFLOAD_TUPLE, +++ WMI_TLV_TAG_STRUCT_NS_OFFLOAD_TUPLE, +++ WMI_TLV_TAG_STRUCT_FTM_INTG_CMD, +++ WMI_TLV_TAG_STRUCT_STA_KEEPALIVE_CMD, +++ WMI_TLV_TAG_STRUCT_STA_KEEPALVE_ARP_RESPONSE, +++ WMI_TLV_TAG_STRUCT_P2P_SET_VENDOR_IE_DATA_CMD, +++ WMI_TLV_TAG_STRUCT_AP_PS_PEER_CMD, +++ WMI_TLV_TAG_STRUCT_PEER_RATE_RETRY_SCHED_CMD, +++ WMI_TLV_TAG_STRUCT_WLAN_PROFILE_TRIGGER_CMD, +++ WMI_TLV_TAG_STRUCT_WLAN_PROFILE_SET_HIST_INTVL_CMD, +++ WMI_TLV_TAG_STRUCT_WLAN_PROFILE_GET_PROF_DATA_CMD, +++ WMI_TLV_TAG_STRUCT_WLAN_PROFILE_ENABLE_PROFILE_ID_CMD, +++ WMI_TLV_TAG_STRUCT_WOW_DEL_PATTERN_CMD, +++ WMI_TLV_TAG_STRUCT_WOW_ADD_DEL_EVT_CMD, +++ WMI_TLV_TAG_STRUCT_RTT_MEASREQ_HEAD, +++ WMI_TLV_TAG_STRUCT_RTT_MEASREQ_BODY, +++ WMI_TLV_TAG_STRUCT_RTT_TSF_CMD, +++ WMI_TLV_TAG_STRUCT_VDEV_SPECTRAL_CONFIGURE_CMD, +++ WMI_TLV_TAG_STRUCT_VDEV_SPECTRAL_ENABLE_CMD, +++ WMI_TLV_TAG_STRUCT_REQUEST_STATS_CMD, +++ WMI_TLV_TAG_STRUCT_NLO_CONFIG_CMD, +++ WMI_TLV_TAG_STRUCT_NLO_CONFIGURED_PARAMETERS, +++ WMI_TLV_TAG_STRUCT_CSA_OFFLOAD_ENABLE_CMD, +++ WMI_TLV_TAG_STRUCT_CSA_OFFLOAD_CHANSWITCH_CMD, +++ WMI_TLV_TAG_STRUCT_CHATTER_SET_MODE_CMD, +++ WMI_TLV_TAG_STRUCT_ECHO_CMD, +++ WMI_TLV_TAG_STRUCT_VDEV_SET_KEEPALIVE_CMD, +++ WMI_TLV_TAG_STRUCT_VDEV_GET_KEEPALIVE_CMD, +++ WMI_TLV_TAG_STRUCT_FORCE_FW_HANG_CMD, +++ WMI_TLV_TAG_STRUCT_GPIO_CONFIG_CMD, +++ WMI_TLV_TAG_STRUCT_GPIO_OUTPUT_CMD, +++ WMI_TLV_TAG_STRUCT_PEER_ADD_WDS_ENTRY_CMD, +++ WMI_TLV_TAG_STRUCT_PEER_REMOVE_WDS_ENTRY_CMD, +++ WMI_TLV_TAG_STRUCT_BCN_TX_HDR, +++ WMI_TLV_TAG_STRUCT_BCN_SEND_FROM_HOST_CMD, +++ WMI_TLV_TAG_STRUCT_MGMT_TX_HDR, +++ WMI_TLV_TAG_STRUCT_ADDBA_CLEAR_RESP_CMD, +++ WMI_TLV_TAG_STRUCT_ADDBA_SEND_CMD, +++ WMI_TLV_TAG_STRUCT_DELBA_SEND_CMD, +++ WMI_TLV_TAG_STRUCT_ADDBA_SETRESPONSE_CMD, +++ WMI_TLV_TAG_STRUCT_SEND_SINGLEAMSDU_CMD, +++ WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_ENABLE_CMD, +++ WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_DISABLE_CMD, +++ WMI_TLV_TAG_STRUCT_PDEV_SET_HT_IE_CMD, +++ WMI_TLV_TAG_STRUCT_PDEV_SET_VHT_IE_CMD, +++ WMI_TLV_TAG_STRUCT_PDEV_SET_DSCP_TID_MAP_CMD, +++ WMI_TLV_TAG_STRUCT_PDEV_GREEN_AP_PS_ENABLE_CMD, +++ WMI_TLV_TAG_STRUCT_PDEV_GET_TPC_CONFIG_CMD, +++ WMI_TLV_TAG_STRUCT_PDEV_SET_BASE_MACADDR_CMD, +++ WMI_TLV_TAG_STRUCT_PEER_MCAST_GROUP_CMD, +++ WMI_TLV_TAG_STRUCT_ROAM_AP_PROFILE, +++ WMI_TLV_TAG_STRUCT_AP_PROFILE, +++ WMI_TLV_TAG_STRUCT_SCAN_SCH_PRIORITY_TABLE_CMD, +++ WMI_TLV_TAG_STRUCT_PDEV_DFS_ENABLE_CMD, +++ WMI_TLV_TAG_STRUCT_PDEV_DFS_DISABLE_CMD, +++ WMI_TLV_TAG_STRUCT_WOW_ADD_PATTERN_CMD, +++ WMI_TLV_TAG_STRUCT_WOW_BITMAP_PATTERN_T, +++ WMI_TLV_TAG_STRUCT_WOW_IPV4_SYNC_PATTERN_T, +++ WMI_TLV_TAG_STRUCT_WOW_IPV6_SYNC_PATTERN_T, +++ WMI_TLV_TAG_STRUCT_WOW_MAGIC_PATTERN_CMD, +++ WMI_TLV_TAG_STRUCT_SCAN_UPDATE_REQUEST_CMD, +++ WMI_TLV_TAG_STRUCT_CHATTER_PKT_COALESCING_FILTER, +++ WMI_TLV_TAG_STRUCT_CHATTER_COALESCING_ADD_FILTER_CMD, +++ WMI_TLV_TAG_STRUCT_CHATTER_COALESCING_DELETE_FILTER_CMD, +++ WMI_TLV_TAG_STRUCT_CHATTER_COALESCING_QUERY_CMD, +++ WMI_TLV_TAG_STRUCT_TXBF_CMD, +++ WMI_TLV_TAG_STRUCT_DEBUG_LOG_CONFIG_CMD, +++ WMI_TLV_TAG_STRUCT_NLO_EVENT, +++ WMI_TLV_TAG_STRUCT_CHATTER_QUERY_REPLY_EVENT, +++ WMI_TLV_TAG_STRUCT_UPLOAD_H_HDR, +++ WMI_TLV_TAG_STRUCT_CAPTURE_H_EVENT_HDR, +++ WMI_TLV_TAG_STRUCT_VDEV_WNM_SLEEPMODE_CMD, +++ WMI_TLV_TAG_STRUCT_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD, +++ WMI_TLV_TAG_STRUCT_VDEV_WMM_ADDTS_CMD, +++ WMI_TLV_TAG_STRUCT_VDEV_WMM_DELTS_CMD, +++ WMI_TLV_TAG_STRUCT_VDEV_SET_WMM_PARAMS_CMD, +++ WMI_TLV_TAG_STRUCT_TDLS_SET_STATE_CMD, +++ WMI_TLV_TAG_STRUCT_TDLS_PEER_UPDATE_CMD, +++ WMI_TLV_TAG_STRUCT_TDLS_PEER_EVENT, +++ WMI_TLV_TAG_STRUCT_TDLS_PEER_CAPABILITIES, +++ WMI_TLV_TAG_STRUCT_VDEV_MCC_SET_TBTT_MODE_CMD, +++ WMI_TLV_TAG_STRUCT_ROAM_CHAN_LIST, +++ WMI_TLV_TAG_STRUCT_VDEV_MCC_BCN_INTVL_CHANGE_EVENT, +++ WMI_TLV_TAG_STRUCT_RESMGR_ADAPTIVE_OCS_CMD, +++ WMI_TLV_TAG_STRUCT_RESMGR_SET_CHAN_TIME_QUOTA_CMD, +++ WMI_TLV_TAG_STRUCT_RESMGR_SET_CHAN_LATENCY_CMD, +++ WMI_TLV_TAG_STRUCT_BA_REQ_SSN_CMD, +++ WMI_TLV_TAG_STRUCT_BA_RSP_SSN_EVENT, +++ WMI_TLV_TAG_STRUCT_STA_SMPS_FORCE_MODE_CMD, +++ WMI_TLV_TAG_STRUCT_SET_MCASTBCAST_FILTER_CMD, +++ WMI_TLV_TAG_STRUCT_P2P_SET_OPPPS_CMD, +++ WMI_TLV_TAG_STRUCT_P2P_SET_NOA_CMD, +++ WMI_TLV_TAG_STRUCT_BA_REQ_SSN_CMD_SUB_STRUCT_PARAM, +++ WMI_TLV_TAG_STRUCT_BA_REQ_SSN_EVENT_SUB_STRUCT_PARAM, +++ WMI_TLV_TAG_STRUCT_STA_SMPS_PARAM_CMD, +++ WMI_TLV_TAG_STRUCT_VDEV_SET_GTX_PARAMS_CMD, +++ WMI_TLV_TAG_STRUCT_MCC_SCHED_TRAFFIC_STATS_CMD, +++ WMI_TLV_TAG_STRUCT_MCC_SCHED_STA_TRAFFIC_STATS, +++ WMI_TLV_TAG_STRUCT_OFFLOAD_BCN_TX_STATUS_EVENT, +++ WMI_TLV_TAG_STRUCT_P2P_NOA_EVENT, +++ WMI_TLV_TAG_STRUCT_HB_SET_ENABLE_CMD, +++ WMI_TLV_TAG_STRUCT_HB_SET_TCP_PARAMS_CMD, +++ WMI_TLV_TAG_STRUCT_HB_SET_TCP_PKT_FILTER_CMD, +++ WMI_TLV_TAG_STRUCT_HB_SET_UDP_PARAMS_CMD, +++ WMI_TLV_TAG_STRUCT_HB_SET_UDP_PKT_FILTER_CMD, +++ WMI_TLV_TAG_STRUCT_HB_IND_EVENT, +++ WMI_TLV_TAG_STRUCT_TX_PAUSE_EVENT, +++ WMI_TLV_TAG_STRUCT_RFKILL_EVENT, +++ WMI_TLV_TAG_STRUCT_DFS_RADAR_EVENT, +++ WMI_TLV_TAG_STRUCT_DFS_PHYERR_FILTER_ENA_CMD, +++ WMI_TLV_TAG_STRUCT_DFS_PHYERR_FILTER_DIS_CMD, +++ WMI_TLV_TAG_STRUCT_BATCH_SCAN_RESULT_SCAN_LIST, +++ WMI_TLV_TAG_STRUCT_BATCH_SCAN_RESULT_NETWORK_INFO, +++ WMI_TLV_TAG_STRUCT_BATCH_SCAN_ENABLE_CMD, +++ WMI_TLV_TAG_STRUCT_BATCH_SCAN_DISABLE_CMD, +++ WMI_TLV_TAG_STRUCT_BATCH_SCAN_TRIGGER_RESULT_CMD, +++ WMI_TLV_TAG_STRUCT_BATCH_SCAN_ENABLED_EVENT, +++ WMI_TLV_TAG_STRUCT_BATCH_SCAN_RESULT_EVENT, +++ WMI_TLV_TAG_STRUCT_VDEV_PLMREQ_START_CMD, +++ WMI_TLV_TAG_STRUCT_VDEV_PLMREQ_STOP_CMD, +++ WMI_TLV_TAG_STRUCT_THERMAL_MGMT_CMD, +++ WMI_TLV_TAG_STRUCT_THERMAL_MGMT_EVENT, +++ WMI_TLV_TAG_STRUCT_PEER_INFO_REQ_CMD, +++ WMI_TLV_TAG_STRUCT_PEER_INFO_EVENT, +++ WMI_TLV_TAG_STRUCT_PEER_INFO, +++ WMI_TLV_TAG_STRUCT_PEER_TX_FAIL_CNT_THR_EVENT, +++ WMI_TLV_TAG_STRUCT_RMC_SET_MODE_CMD, +++ WMI_TLV_TAG_STRUCT_RMC_SET_ACTION_PERIOD_CMD, +++ WMI_TLV_TAG_STRUCT_RMC_CONFIG_CMD, +++ WMI_TLV_TAG_STRUCT_MHF_OFFLOAD_SET_MODE_CMD, +++ WMI_TLV_TAG_STRUCT_MHF_OFFLOAD_PLUMB_ROUTING_TABLE_CMD, +++ WMI_TLV_TAG_STRUCT_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD, +++ WMI_TLV_TAG_STRUCT_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD, +++ WMI_TLV_TAG_STRUCT_NAN_CMD_PARAM, +++ WMI_TLV_TAG_STRUCT_NAN_EVENT_HDR, +++ WMI_TLV_TAG_STRUCT_PDEV_L1SS_TRACK_EVENT, +++ WMI_TLV_TAG_STRUCT_DIAG_DATA_CONTAINER_EVENT, +++ WMI_TLV_TAG_STRUCT_MODEM_POWER_STATE_CMD_PARAM, +++ WMI_TLV_TAG_STRUCT_PEER_GET_ESTIMATED_LINKSPEED_CMD, +++ WMI_TLV_TAG_STRUCT_PEER_ESTIMATED_LINKSPEED_EVENT, +++ WMI_TLV_TAG_STRUCT_AGGR_STATE_TRIG_EVENT, +++ WMI_TLV_TAG_STRUCT_MHF_OFFLOAD_ROUTING_TABLE_ENTRY, +++ WMI_TLV_TAG_STRUCT_ROAM_SCAN_CMD, +++ WMI_TLV_TAG_STRUCT_REQ_STATS_EXT_CMD, +++ WMI_TLV_TAG_STRUCT_STATS_EXT_EVENT, +++ WMI_TLV_TAG_STRUCT_OBSS_SCAN_ENABLE_CMD, +++ WMI_TLV_TAG_STRUCT_OBSS_SCAN_DISABLE_CMD, +++ WMI_TLV_TAG_STRUCT_OFFLOAD_PRB_RSP_TX_STATUS_EVENT, +++ WMI_TLV_TAG_STRUCT_PDEV_SET_LED_CONFIG_CMD, +++ WMI_TLV_TAG_STRUCT_HOST_AUTO_SHUTDOWN_CFG_CMD, +++ WMI_TLV_TAG_STRUCT_HOST_AUTO_SHUTDOWN_EVENT, +++ WMI_TLV_TAG_STRUCT_UPDATE_WHAL_MIB_STATS_EVENT, +++ WMI_TLV_TAG_STRUCT_CHAN_AVOID_UPDATE_CMD_PARAM, +++ WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_PKT_PATTERN_T, +++ WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_TMR_PATTERN_T, +++ WMI_TLV_TAG_STRUCT_WOW_IOAC_ADD_KEEPALIVE_CMD, +++ WMI_TLV_TAG_STRUCT_WOW_IOAC_DEL_KEEPALIVE_CMD, +++ WMI_TLV_TAG_STRUCT_WOW_IOAC_KEEPALIVE_T, +++ WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_ADD_PATTERN_CMD, +++ WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_DEL_PATTERN_CMD, +++ WMI_TLV_TAG_STRUCT_START_LINK_STATS_CMD, +++ WMI_TLV_TAG_STRUCT_CLEAR_LINK_STATS_CMD, +++ WMI_TLV_TAG_STRUCT_REQUEST_LINK_STATS_CMD, +++ WMI_TLV_TAG_STRUCT_IFACE_LINK_STATS_EVENT, +++ WMI_TLV_TAG_STRUCT_RADIO_LINK_STATS_EVENT, +++ WMI_TLV_TAG_STRUCT_PEER_STATS_EVENT, +++ WMI_TLV_TAG_STRUCT_CHANNEL_STATS, +++ WMI_TLV_TAG_STRUCT_RADIO_LINK_STATS, +++ WMI_TLV_TAG_STRUCT_RATE_STATS, +++ WMI_TLV_TAG_STRUCT_PEER_LINK_STATS, +++ WMI_TLV_TAG_STRUCT_WMM_AC_STATS, +++ WMI_TLV_TAG_STRUCT_IFACE_LINK_STATS, +++ WMI_TLV_TAG_STRUCT_LPI_MGMT_SNOOPING_CONFIG_CMD, +++ WMI_TLV_TAG_STRUCT_LPI_START_SCAN_CMD, +++ WMI_TLV_TAG_STRUCT_LPI_STOP_SCAN_CMD, +++ WMI_TLV_TAG_STRUCT_LPI_RESULT_EVENT, +++ WMI_TLV_TAG_STRUCT_PEER_STATE_EVENT, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_BUCKET_CMD, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_BUCKET_CHANNEL_EVENT, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_START_CMD, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_STOP_CMD, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMD, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_BSSID_PARAM_CMD, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMD, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_GET_CACHED_RESULTS_CMD, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMD, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_SET_CAPABILITIES_CMD, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_GET_CAPABILITIES_CMD, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_OPERATION_EVENT, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_START_STOP_EVENT, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_TABLE_USAGE_EVENT, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_DESCRIPTOR_EVENT, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_RSSI_INFO_EVENT, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_CACHED_RESULTS_EVENT, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_RESULTS_EVENT, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_RESULT_BSSID_EVENT, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_HOTLIST_MATCH_EVENT, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_CAPABILITIES_EVENT, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_CACHE_CAPABILITIES_EVENT, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_MONITOR_CAPABILITIES_EVENT, +++ WMI_TLV_TAG_STRUCT_EXTSCAN_HOTLIST_MONITOR_CAPABILITIES_EVENT, +++ WMI_TLV_TAG_STRUCT_D0_WOW_ENABLE_DISABLE_CMD, +++ WMI_TLV_TAG_STRUCT_D0_WOW_DISABLE_ACK_EVENT, +++ WMI_TLV_TAG_STRUCT_UNIT_TEST_CMD, +++ WMI_TLV_TAG_STRUCT_ROAM_OFFLOAD_TLV_PARAM, +++ WMI_TLV_TAG_STRUCT_ROAM_11I_OFFLOAD_TLV_PARAM, +++ WMI_TLV_TAG_STRUCT_ROAM_11R_OFFLOAD_TLV_PARAM, +++ WMI_TLV_TAG_STRUCT_ROAM_ESE_OFFLOAD_TLV_PARAM, +++ WMI_TLV_TAG_STRUCT_ROAM_SYNCH_EVENT, +++ WMI_TLV_TAG_STRUCT_ROAM_SYNCH_COMPLETE, +++ WMI_TLV_TAG_STRUCT_EXTWOW_ENABLE_CMD, +++ WMI_TLV_TAG_STRUCT_EXTWOW_SET_APP_TYPE1_PARAMS_CMD, +++ WMI_TLV_TAG_STRUCT_EXTWOW_SET_APP_TYPE2_PARAMS_CMD, +++ WMI_TLV_TAG_STRUCT_LPI_STATUS_EVENT, +++ WMI_TLV_TAG_STRUCT_LPI_HANDOFF_EVENT, +++ WMI_TLV_TAG_STRUCT_VDEV_RATE_STATS_EVENT, +++ WMI_TLV_TAG_STRUCT_VDEV_RATE_HT_INFO, +++ WMI_TLV_TAG_STRUCT_RIC_REQUEST, +++ WMI_TLV_TAG_STRUCT_PDEV_GET_TEMPERATURE_CMD, +++ WMI_TLV_TAG_STRUCT_PDEV_TEMPERATURE_EVENT, +++ WMI_TLV_TAG_STRUCT_SET_DHCP_SERVER_OFFLOAD_CMD, +++ WMI_TLV_TAG_STRUCT_TPC_CHAINMASK_CONFIG_CMD, +++ WMI_TLV_TAG_STRUCT_RIC_TSPEC, +++ WMI_TLV_TAG_STRUCT_TPC_CHAINMASK_CONFIG, +++ WMI_TLV_TAG_STRUCT_IPA_OFFLOAD_CMD, +++ WMI_TLV_TAG_STRUCT_SCAN_PROB_REQ_OUI_CMD, +++ WMI_TLV_TAG_STRUCT_KEY_MATERIAL, +++ WMI_TLV_TAG_STRUCT_TDLS_SET_OFFCHAN_MODE_CMD, +++ WMI_TLV_TAG_STRUCT_SET_LED_FLASHING_CMD, +++ WMI_TLV_TAG_STRUCT_MDNS_OFFLOAD_CMD, +++ WMI_TLV_TAG_STRUCT_MDNS_SET_FQDN_CMD, +++ WMI_TLV_TAG_STRUCT_MDNS_SET_RESP_CMD, +++ WMI_TLV_TAG_STRUCT_MDNS_GET_STATS_CMD, +++ WMI_TLV_TAG_STRUCT_MDNS_STATS_EVENT, +++ WMI_TLV_TAG_STRUCT_ROAM_INVOKE_CMD, +++ WMI_TLV_TAG_STRUCT_PDEV_RESUME_EVENT, +++ WMI_TLV_TAG_STRUCT_PDEV_SET_ANTENNA_DIVERSITY_CMD, +++ WMI_TLV_TAG_STRUCT_SAP_OFL_ENABLE_CMD, +++ WMI_TLV_TAG_STRUCT_SAP_OFL_ADD_STA_EVENT, +++ WMI_TLV_TAG_STRUCT_SAP_OFL_DEL_STA_EVENT, +++ WMI_TLV_TAG_STRUCT_APFIND_CMD_PARAM, +++ WMI_TLV_TAG_STRUCT_APFIND_EVENT_HDR, +++ +++ WMI_TLV_TAG_MAX +++}; +++ +++enum wmi_tlv_service { +++ WMI_TLV_SERVICE_BEACON_OFFLOAD = 0, +++ WMI_TLV_SERVICE_SCAN_OFFLOAD, +++ WMI_TLV_SERVICE_ROAM_SCAN_OFFLOAD, +++ WMI_TLV_SERVICE_BCN_MISS_OFFLOAD, +++ WMI_TLV_SERVICE_STA_PWRSAVE, +++ WMI_TLV_SERVICE_STA_ADVANCED_PWRSAVE, +++ WMI_TLV_SERVICE_AP_UAPSD, +++ WMI_TLV_SERVICE_AP_DFS, +++ WMI_TLV_SERVICE_11AC, +++ WMI_TLV_SERVICE_BLOCKACK, +++ WMI_TLV_SERVICE_PHYERR, +++ WMI_TLV_SERVICE_BCN_FILTER, +++ WMI_TLV_SERVICE_RTT, +++ WMI_TLV_SERVICE_WOW, +++ WMI_TLV_SERVICE_RATECTRL_CACHE, +++ WMI_TLV_SERVICE_IRAM_TIDS, +++ WMI_TLV_SERVICE_ARPNS_OFFLOAD, +++ WMI_TLV_SERVICE_NLO, +++ WMI_TLV_SERVICE_GTK_OFFLOAD, +++ WMI_TLV_SERVICE_SCAN_SCH, +++ WMI_TLV_SERVICE_CSA_OFFLOAD, +++ WMI_TLV_SERVICE_CHATTER, +++ WMI_TLV_SERVICE_COEX_FREQAVOID, +++ WMI_TLV_SERVICE_PACKET_POWER_SAVE, +++ WMI_TLV_SERVICE_FORCE_FW_HANG, +++ WMI_TLV_SERVICE_GPIO, +++ WMI_TLV_SERVICE_STA_DTIM_PS_MODULATED_DTIM, +++ WMI_TLV_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, +++ WMI_TLV_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, +++ WMI_TLV_SERVICE_STA_KEEP_ALIVE, +++ WMI_TLV_SERVICE_TX_ENCAP, +++ WMI_TLV_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, +++ WMI_TLV_SERVICE_EARLY_RX, +++ WMI_TLV_SERVICE_STA_SMPS, +++ WMI_TLV_SERVICE_FWTEST, +++ WMI_TLV_SERVICE_STA_WMMAC, +++ WMI_TLV_SERVICE_TDLS, +++ WMI_TLV_SERVICE_BURST, +++ WMI_TLV_SERVICE_MCC_BCN_INTERVAL_CHANGE, +++ WMI_TLV_SERVICE_ADAPTIVE_OCS, +++ WMI_TLV_SERVICE_BA_SSN_SUPPORT, +++ WMI_TLV_SERVICE_FILTER_IPSEC_NATKEEPALIVE, +++ WMI_TLV_SERVICE_WLAN_HB, +++ WMI_TLV_SERVICE_LTE_ANT_SHARE_SUPPORT, +++ WMI_TLV_SERVICE_BATCH_SCAN, +++ WMI_TLV_SERVICE_QPOWER, +++ WMI_TLV_SERVICE_PLMREQ, +++ WMI_TLV_SERVICE_THERMAL_MGMT, +++ WMI_TLV_SERVICE_RMC, +++ WMI_TLV_SERVICE_MHF_OFFLOAD, +++ WMI_TLV_SERVICE_COEX_SAR, +++ WMI_TLV_SERVICE_BCN_TXRATE_OVERRIDE, +++ WMI_TLV_SERVICE_NAN, +++ WMI_TLV_SERVICE_L1SS_STAT, +++ WMI_TLV_SERVICE_ESTIMATE_LINKSPEED, +++ WMI_TLV_SERVICE_OBSS_SCAN, +++ WMI_TLV_SERVICE_TDLS_OFFCHAN, +++ WMI_TLV_SERVICE_TDLS_UAPSD_BUFFER_STA, +++ WMI_TLV_SERVICE_TDLS_UAPSD_SLEEP_STA, +++ WMI_TLV_SERVICE_IBSS_PWRSAVE, +++ WMI_TLV_SERVICE_LPASS, +++ WMI_TLV_SERVICE_EXTSCAN, +++ WMI_TLV_SERVICE_D0WOW, +++ WMI_TLV_SERVICE_HSOFFLOAD, +++ WMI_TLV_SERVICE_ROAM_HO_OFFLOAD, +++ WMI_TLV_SERVICE_RX_FULL_REORDER, +++ WMI_TLV_SERVICE_DHCP_OFFLOAD, +++ WMI_TLV_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT, +++ WMI_TLV_SERVICE_MDNS_OFFLOAD, +++ WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD, +++}; +++ +++#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \ +++ ((svc_id) < (len) && \ +++ __le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \ +++ BIT((svc_id)%(sizeof(u32)))) +++ +++#define SVCMAP(x, y, len) \ +++ do { \ +++ if (WMI_SERVICE_IS_ENABLED((in), (x), (len))) \ +++ __set_bit(y, out); \ +++ } while (0) +++ +++static inline void +++wmi_tlv_svc_map(const __le32 *in, unsigned long *out, size_t len) +++{ +++ SVCMAP(WMI_TLV_SERVICE_BEACON_OFFLOAD, +++ WMI_SERVICE_BEACON_OFFLOAD, len); +++ SVCMAP(WMI_TLV_SERVICE_SCAN_OFFLOAD, +++ WMI_SERVICE_SCAN_OFFLOAD, len); +++ SVCMAP(WMI_TLV_SERVICE_ROAM_SCAN_OFFLOAD, +++ WMI_SERVICE_ROAM_SCAN_OFFLOAD, len); +++ SVCMAP(WMI_TLV_SERVICE_BCN_MISS_OFFLOAD, +++ WMI_SERVICE_BCN_MISS_OFFLOAD, len); +++ SVCMAP(WMI_TLV_SERVICE_STA_PWRSAVE, +++ WMI_SERVICE_STA_PWRSAVE, len); +++ SVCMAP(WMI_TLV_SERVICE_STA_ADVANCED_PWRSAVE, +++ WMI_SERVICE_STA_ADVANCED_PWRSAVE, len); +++ SVCMAP(WMI_TLV_SERVICE_AP_UAPSD, +++ WMI_SERVICE_AP_UAPSD, len); +++ SVCMAP(WMI_TLV_SERVICE_AP_DFS, +++ WMI_SERVICE_AP_DFS, len); +++ SVCMAP(WMI_TLV_SERVICE_11AC, +++ WMI_SERVICE_11AC, len); +++ SVCMAP(WMI_TLV_SERVICE_BLOCKACK, +++ WMI_SERVICE_BLOCKACK, len); +++ SVCMAP(WMI_TLV_SERVICE_PHYERR, +++ WMI_SERVICE_PHYERR, len); +++ SVCMAP(WMI_TLV_SERVICE_BCN_FILTER, +++ WMI_SERVICE_BCN_FILTER, len); +++ SVCMAP(WMI_TLV_SERVICE_RTT, +++ WMI_SERVICE_RTT, len); +++ SVCMAP(WMI_TLV_SERVICE_WOW, +++ WMI_SERVICE_WOW, len); +++ SVCMAP(WMI_TLV_SERVICE_RATECTRL_CACHE, +++ WMI_SERVICE_RATECTRL_CACHE, len); +++ SVCMAP(WMI_TLV_SERVICE_IRAM_TIDS, +++ WMI_SERVICE_IRAM_TIDS, len); +++ SVCMAP(WMI_TLV_SERVICE_ARPNS_OFFLOAD, +++ WMI_SERVICE_ARPNS_OFFLOAD, len); +++ SVCMAP(WMI_TLV_SERVICE_NLO, +++ WMI_SERVICE_NLO, len); +++ SVCMAP(WMI_TLV_SERVICE_GTK_OFFLOAD, +++ WMI_SERVICE_GTK_OFFLOAD, len); +++ SVCMAP(WMI_TLV_SERVICE_SCAN_SCH, +++ WMI_SERVICE_SCAN_SCH, len); +++ SVCMAP(WMI_TLV_SERVICE_CSA_OFFLOAD, +++ WMI_SERVICE_CSA_OFFLOAD, len); +++ SVCMAP(WMI_TLV_SERVICE_CHATTER, +++ WMI_SERVICE_CHATTER, len); +++ SVCMAP(WMI_TLV_SERVICE_COEX_FREQAVOID, +++ WMI_SERVICE_COEX_FREQAVOID, len); +++ SVCMAP(WMI_TLV_SERVICE_PACKET_POWER_SAVE, +++ WMI_SERVICE_PACKET_POWER_SAVE, len); +++ SVCMAP(WMI_TLV_SERVICE_FORCE_FW_HANG, +++ WMI_SERVICE_FORCE_FW_HANG, len); +++ SVCMAP(WMI_TLV_SERVICE_GPIO, +++ WMI_SERVICE_GPIO, len); +++ SVCMAP(WMI_TLV_SERVICE_STA_DTIM_PS_MODULATED_DTIM, +++ WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM, len); +++ SVCMAP(WMI_TLV_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, +++ WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, len); +++ SVCMAP(WMI_TLV_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, +++ WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, len); +++ SVCMAP(WMI_TLV_SERVICE_STA_KEEP_ALIVE, +++ WMI_SERVICE_STA_KEEP_ALIVE, len); +++ SVCMAP(WMI_TLV_SERVICE_TX_ENCAP, +++ WMI_SERVICE_TX_ENCAP, len); +++ SVCMAP(WMI_TLV_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, +++ WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, len); +++ SVCMAP(WMI_TLV_SERVICE_EARLY_RX, +++ WMI_SERVICE_EARLY_RX, len); +++ SVCMAP(WMI_TLV_SERVICE_STA_SMPS, +++ WMI_SERVICE_STA_SMPS, len); +++ SVCMAP(WMI_TLV_SERVICE_FWTEST, +++ WMI_SERVICE_FWTEST, len); +++ SVCMAP(WMI_TLV_SERVICE_STA_WMMAC, +++ WMI_SERVICE_STA_WMMAC, len); +++ SVCMAP(WMI_TLV_SERVICE_TDLS, +++ WMI_SERVICE_TDLS, len); +++ SVCMAP(WMI_TLV_SERVICE_BURST, +++ WMI_SERVICE_BURST, len); +++ SVCMAP(WMI_TLV_SERVICE_MCC_BCN_INTERVAL_CHANGE, +++ WMI_SERVICE_MCC_BCN_INTERVAL_CHANGE, len); +++ SVCMAP(WMI_TLV_SERVICE_ADAPTIVE_OCS, +++ WMI_SERVICE_ADAPTIVE_OCS, len); +++ SVCMAP(WMI_TLV_SERVICE_BA_SSN_SUPPORT, +++ WMI_SERVICE_BA_SSN_SUPPORT, len); +++ SVCMAP(WMI_TLV_SERVICE_FILTER_IPSEC_NATKEEPALIVE, +++ WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE, len); +++ SVCMAP(WMI_TLV_SERVICE_WLAN_HB, +++ WMI_SERVICE_WLAN_HB, len); +++ SVCMAP(WMI_TLV_SERVICE_LTE_ANT_SHARE_SUPPORT, +++ WMI_SERVICE_LTE_ANT_SHARE_SUPPORT, len); +++ SVCMAP(WMI_TLV_SERVICE_BATCH_SCAN, +++ WMI_SERVICE_BATCH_SCAN, len); +++ SVCMAP(WMI_TLV_SERVICE_QPOWER, +++ WMI_SERVICE_QPOWER, len); +++ SVCMAP(WMI_TLV_SERVICE_PLMREQ, +++ WMI_SERVICE_PLMREQ, len); +++ SVCMAP(WMI_TLV_SERVICE_THERMAL_MGMT, +++ WMI_SERVICE_THERMAL_MGMT, len); +++ SVCMAP(WMI_TLV_SERVICE_RMC, +++ WMI_SERVICE_RMC, len); +++ SVCMAP(WMI_TLV_SERVICE_MHF_OFFLOAD, +++ WMI_SERVICE_MHF_OFFLOAD, len); +++ SVCMAP(WMI_TLV_SERVICE_COEX_SAR, +++ WMI_SERVICE_COEX_SAR, len); +++ SVCMAP(WMI_TLV_SERVICE_BCN_TXRATE_OVERRIDE, +++ WMI_SERVICE_BCN_TXRATE_OVERRIDE, len); +++ SVCMAP(WMI_TLV_SERVICE_NAN, +++ WMI_SERVICE_NAN, len); +++ SVCMAP(WMI_TLV_SERVICE_L1SS_STAT, +++ WMI_SERVICE_L1SS_STAT, len); +++ SVCMAP(WMI_TLV_SERVICE_ESTIMATE_LINKSPEED, +++ WMI_SERVICE_ESTIMATE_LINKSPEED, len); +++ SVCMAP(WMI_TLV_SERVICE_OBSS_SCAN, +++ WMI_SERVICE_OBSS_SCAN, len); +++ SVCMAP(WMI_TLV_SERVICE_TDLS_OFFCHAN, +++ WMI_SERVICE_TDLS_OFFCHAN, len); +++ SVCMAP(WMI_TLV_SERVICE_TDLS_UAPSD_BUFFER_STA, +++ WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, len); +++ SVCMAP(WMI_TLV_SERVICE_TDLS_UAPSD_SLEEP_STA, +++ WMI_SERVICE_TDLS_UAPSD_SLEEP_STA, len); +++ SVCMAP(WMI_TLV_SERVICE_IBSS_PWRSAVE, +++ WMI_SERVICE_IBSS_PWRSAVE, len); +++ SVCMAP(WMI_TLV_SERVICE_LPASS, +++ WMI_SERVICE_LPASS, len); +++ SVCMAP(WMI_TLV_SERVICE_EXTSCAN, +++ WMI_SERVICE_EXTSCAN, len); +++ SVCMAP(WMI_TLV_SERVICE_D0WOW, +++ WMI_SERVICE_D0WOW, len); +++ SVCMAP(WMI_TLV_SERVICE_HSOFFLOAD, +++ WMI_SERVICE_HSOFFLOAD, len); +++ SVCMAP(WMI_TLV_SERVICE_ROAM_HO_OFFLOAD, +++ WMI_SERVICE_ROAM_HO_OFFLOAD, len); +++ SVCMAP(WMI_TLV_SERVICE_RX_FULL_REORDER, +++ WMI_SERVICE_RX_FULL_REORDER, len); +++ SVCMAP(WMI_TLV_SERVICE_DHCP_OFFLOAD, +++ WMI_SERVICE_DHCP_OFFLOAD, len); +++ SVCMAP(WMI_TLV_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT, +++ WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT, len); +++ SVCMAP(WMI_TLV_SERVICE_MDNS_OFFLOAD, +++ WMI_SERVICE_MDNS_OFFLOAD, len); +++ SVCMAP(WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD, +++ WMI_SERVICE_SAP_AUTH_OFFLOAD, len); +++} +++ +++#undef SVCMAP +++ +++struct wmi_tlv { +++ __le16 len; +++ __le16 tag; +++ u8 value[0]; +++} __packed; +++ +++#define WMI_TLV_MGMT_RX_NUM_RSSI 4 +++ +++struct wmi_tlv_mgmt_rx_ev { +++ __le32 channel; +++ __le32 snr; +++ __le32 rate; +++ __le32 phy_mode; +++ __le32 buf_len; +++ __le32 status; +++ __le32 rssi[WMI_TLV_MGMT_RX_NUM_RSSI]; +++} __packed; +++ +++struct wmi_tlv_abi_version { +++ __le32 abi_ver0; +++ __le32 abi_ver1; +++ __le32 abi_ver_ns0; +++ __le32 abi_ver_ns1; +++ __le32 abi_ver_ns2; +++ __le32 abi_ver_ns3; +++} __packed; +++ +++enum wmi_tlv_hw_bd_id { +++ WMI_TLV_HW_BD_LEGACY = 0, +++ WMI_TLV_HW_BD_QCA6174 = 1, +++ WMI_TLV_HW_BD_QCA2582 = 2, +++}; +++ +++struct wmi_tlv_hw_bd_info { +++ u8 rev; +++ u8 project_id; +++ u8 custom_id; +++ u8 reference_design_id; +++} __packed; +++ +++struct wmi_tlv_svc_rdy_ev { +++ __le32 fw_build_vers; +++ struct wmi_tlv_abi_version abi; +++ __le32 phy_capability; +++ __le32 max_frag_entry; +++ __le32 num_rf_chains; +++ __le32 ht_cap_info; +++ __le32 vht_cap_info; +++ __le32 vht_supp_mcs; +++ __le32 hw_min_tx_power; +++ __le32 hw_max_tx_power; +++ __le32 sys_cap_info; +++ __le32 min_pkt_size_enable; +++ __le32 max_bcn_ie_size; +++ __le32 num_mem_reqs; +++ __le32 max_num_scan_chans; +++ __le32 hw_bd_id; /* 0 means hw_bd_info is invalid */ +++ struct wmi_tlv_hw_bd_info hw_bd_info[5]; +++} __packed; +++ +++struct wmi_tlv_rdy_ev { +++ struct wmi_tlv_abi_version abi; +++ struct wmi_mac_addr mac_addr; +++ __le32 status; +++} __packed; +++ +++struct wmi_tlv_resource_config { +++ __le32 num_vdevs; +++ __le32 num_peers; +++ __le32 num_offload_peers; +++ __le32 num_offload_reorder_bufs; +++ __le32 num_peer_keys; +++ __le32 num_tids; +++ __le32 ast_skid_limit; +++ __le32 tx_chain_mask; +++ __le32 rx_chain_mask; +++ __le32 rx_timeout_pri[4]; +++ __le32 rx_decap_mode; +++ __le32 scan_max_pending_reqs; +++ __le32 bmiss_offload_max_vdev; +++ __le32 roam_offload_max_vdev; +++ __le32 roam_offload_max_ap_profiles; +++ __le32 num_mcast_groups; +++ __le32 num_mcast_table_elems; +++ __le32 mcast2ucast_mode; +++ __le32 tx_dbg_log_size; +++ __le32 num_wds_entries; +++ __le32 dma_burst_size; +++ __le32 mac_aggr_delim; +++ __le32 rx_skip_defrag_timeout_dup_detection_check; +++ __le32 vow_config; +++ __le32 gtk_offload_max_vdev; +++ __le32 num_msdu_desc; +++ __le32 max_frag_entries; +++ __le32 num_tdls_vdevs; +++ __le32 num_tdls_conn_table_entries; +++ __le32 beacon_tx_offload_max_vdev; +++ __le32 num_multicast_filter_entries; +++ __le32 num_wow_filters; +++ __le32 num_keep_alive_pattern; +++ __le32 keep_alive_pattern_size; +++ __le32 max_tdls_concurrent_sleep_sta; +++ __le32 max_tdls_concurrent_buffer_sta; +++} __packed; +++ +++struct wmi_tlv_init_cmd { +++ struct wmi_tlv_abi_version abi; +++ __le32 num_host_mem_chunks; +++} __packed; +++ +++struct wmi_tlv_pdev_set_param_cmd { +++ __le32 pdev_id; /* not used yet */ +++ __le32 param_id; +++ __le32 param_value; +++} __packed; +++ +++struct wmi_tlv_pdev_set_rd_cmd { +++ __le32 pdev_id; /* not used yet */ +++ __le32 regd; +++ __le32 regd_2ghz; +++ __le32 regd_5ghz; +++ __le32 conform_limit_2ghz; +++ __le32 conform_limit_5ghz; +++} __packed; +++ +++struct wmi_tlv_scan_chan_list_cmd { +++ __le32 num_scan_chans; +++} __packed; +++ +++struct wmi_tlv_start_scan_cmd { +++ struct wmi_start_scan_common common; +++ __le32 burst_duration_ms; +++ __le32 num_channels; +++ __le32 num_bssids; +++ __le32 num_ssids; +++ __le32 ie_len; +++ __le32 num_probes; +++} __packed; +++ +++struct wmi_tlv_vdev_start_cmd { +++ __le32 vdev_id; +++ __le32 requestor_id; +++ __le32 bcn_intval; +++ __le32 dtim_period; +++ __le32 flags; +++ struct wmi_ssid ssid; +++ __le32 bcn_tx_rate; +++ __le32 bcn_tx_power; +++ __le32 num_noa_descr; +++ __le32 disable_hw_ack; +++} __packed; +++ +++enum { +++ WMI_TLV_PEER_TYPE_DEFAULT = 0, /* generic / non-BSS / self-peer */ +++ WMI_TLV_PEER_TYPE_BSS = 1, +++ WMI_TLV_PEER_TYPE_TDLS = 2, +++ WMI_TLV_PEER_TYPE_HOST_MAX = 127, +++ WMI_TLV_PEER_TYPE_ROAMOFFLOAD_TMP = 128, +++}; +++ +++struct wmi_tlv_peer_create_cmd { +++ __le32 vdev_id; +++ struct wmi_mac_addr peer_addr; +++ __le32 peer_type; +++} __packed; +++ +++struct wmi_tlv_peer_assoc_cmd { +++ struct wmi_mac_addr mac_addr; +++ __le32 vdev_id; +++ __le32 new_assoc; +++ __le32 assoc_id; +++ __le32 flags; +++ __le32 caps; +++ __le32 listen_intval; +++ __le32 ht_caps; +++ __le32 max_mpdu; +++ __le32 mpdu_density; +++ __le32 rate_caps; +++ __le32 nss; +++ __le32 vht_caps; +++ __le32 phy_mode; +++ __le32 ht_info[2]; +++ __le32 num_legacy_rates; +++ __le32 num_ht_rates; +++} __packed; +++ +++struct wmi_tlv_pdev_suspend { +++ __le32 pdev_id; /* not used yet */ +++ __le32 opt; +++} __packed; +++ +++struct wmi_tlv_pdev_set_wmm_cmd { +++ __le32 pdev_id; /* not used yet */ +++ __le32 dg_type; /* no idea.. */ +++} __packed; +++ +++struct wmi_tlv_vdev_wmm_params { +++ __le32 dummy; +++ struct wmi_wmm_params params; +++} __packed; +++ +++struct wmi_tlv_vdev_set_wmm_cmd { +++ __le32 vdev_id; +++ struct wmi_tlv_vdev_wmm_params vdev_wmm_params[4]; +++} __packed; +++ +++struct wmi_tlv_phyerr_ev { +++ __le32 num_phyerrs; +++ __le32 tsf_l32; +++ __le32 tsf_u32; +++ __le32 buf_len; +++} __packed; +++ +++enum wmi_tlv_dbglog_param { +++ WMI_TLV_DBGLOG_PARAM_LOG_LEVEL = 1, +++ WMI_TLV_DBGLOG_PARAM_VDEV_ENABLE, +++ WMI_TLV_DBGLOG_PARAM_VDEV_DISABLE, +++ WMI_TLV_DBGLOG_PARAM_VDEV_ENABLE_BITMAP, +++ WMI_TLV_DBGLOG_PARAM_VDEV_DISABLE_BITMAP, +++}; +++ +++enum wmi_tlv_dbglog_log_level { +++ WMI_TLV_DBGLOG_LOG_LEVEL_VERBOSE = 0, +++ WMI_TLV_DBGLOG_LOG_LEVEL_INFO, +++ WMI_TLV_DBGLOG_LOG_LEVEL_INFO_LVL_1, +++ WMI_TLV_DBGLOG_LOG_LEVEL_INFO_LVL_2, +++ WMI_TLV_DBGLOG_LOG_LEVEL_WARN, +++ WMI_TLV_DBGLOG_LOG_LEVEL_ERR, +++}; +++ +++#define WMI_TLV_DBGLOG_BITMAP_MAX_IDS 512 +++#define WMI_TLV_DBGLOG_BITMAP_MAX_WORDS (WMI_TLV_DBGLOG_BITMAP_MAX_IDS / \ +++ sizeof(__le32)) +++#define WMI_TLV_DBGLOG_ALL_MODULES 0xffff +++#define WMI_TLV_DBGLOG_LOG_LEVEL_VALUE(module_id, log_level) \ +++ (((module_id << 16) & 0xffff0000) | \ +++ ((log_level << 0) & 0x000000ff)) +++ +++struct wmi_tlv_dbglog_cmd { +++ __le32 param; +++ __le32 value; +++} __packed; +++ +++struct wmi_tlv_resume_cmd { +++ __le32 reserved; +++} __packed; +++ +++struct wmi_tlv_req_stats_cmd { +++ __le32 stats_id; /* wmi_stats_id */ +++ __le32 vdev_id; +++ struct wmi_mac_addr peer_macaddr; +++} __packed; +++ +++struct wmi_tlv_vdev_stats { +++ __le32 vdev_id; +++ __le32 beacon_snr; +++ __le32 data_snr; +++ __le32 num_tx_frames[4]; /* per-AC */ +++ __le32 num_rx_frames; +++ __le32 num_tx_frames_retries[4]; +++ __le32 num_tx_frames_failures[4]; +++ __le32 num_rts_fail; +++ __le32 num_rts_success; +++ __le32 num_rx_err; +++ __le32 num_rx_discard; +++ __le32 num_tx_not_acked; +++ __le32 tx_rate_history[10]; +++ __le32 beacon_rssi_history[10]; +++} __packed; +++ +++struct wmi_tlv_pktlog_enable { +++ __le32 reserved; +++ __le32 filter; +++} __packed; +++ +++struct wmi_tlv_pktlog_disable { +++ __le32 reserved; +++} __packed; +++ +++enum wmi_tlv_bcn_tx_status { +++ WMI_TLV_BCN_TX_STATUS_OK, +++ WMI_TLV_BCN_TX_STATUS_XRETRY, +++ WMI_TLV_BCN_TX_STATUS_DROP, +++ WMI_TLV_BCN_TX_STATUS_FILTERED, +++}; +++ +++struct wmi_tlv_bcn_tx_status_ev { +++ __le32 vdev_id; +++ __le32 tx_status; +++} __packed; +++ +++struct wmi_tlv_bcn_prb_info { +++ __le32 caps; +++ __le32 erp; +++ u8 ies[0]; +++} __packed; +++ +++struct wmi_tlv_bcn_tmpl_cmd { +++ __le32 vdev_id; +++ __le32 tim_ie_offset; +++ __le32 buf_len; +++} __packed; +++ +++struct wmi_tlv_prb_tmpl_cmd { +++ __le32 vdev_id; +++ __le32 buf_len; +++} __packed; +++ +++struct wmi_tlv_p2p_go_bcn_ie { +++ __le32 vdev_id; +++ __le32 ie_len; +++} __packed; +++ +++enum wmi_tlv_diag_item_type { +++ WMI_TLV_DIAG_ITEM_TYPE_FW_EVENT, +++ WMI_TLV_DIAG_ITEM_TYPE_FW_LOG, +++ WMI_TLV_DIAG_ITEM_TYPE_FW_DEBUG_MSG, +++}; +++ +++struct wmi_tlv_diag_item { +++ u8 type; +++ u8 reserved; +++ __le16 len; +++ __le32 timestamp; +++ __le32 code; +++ u8 payload[0]; +++} __packed; +++ +++struct wmi_tlv_diag_data_ev { +++ __le32 num_items; +++} __packed; +++ +++struct wmi_tlv_sta_keepalive_cmd { +++ __le32 vdev_id; +++ __le32 enabled; +++ __le32 method; /* WMI_STA_KEEPALIVE_METHOD_ */ +++ __le32 interval; /* in seconds */ +++} __packed; +++ +++struct wmi_tlv_stats_ev { +++ __le32 stats_id; /* WMI_STAT_ */ +++ __le32 num_pdev_stats; +++ __le32 num_vdev_stats; +++ __le32 num_peer_stats; +++ __le32 num_bcnflt_stats; +++ __le32 num_chan_stats; +++} __packed; +++ +++void ath10k_wmi_tlv_attach(struct ath10k *ar); +++ +++#endif ++--- a/backport-include/linux/etherdevice.h +++++ b/backport-include/linux/etherdevice.h ++@@ -148,6 +148,29 @@ static inline bool ether_addr_equal_unal ++ return memcmp(addr1, addr2, ETH_ALEN) == 0; ++ #endif ++ } +++ +++/** +++ * ether_addr_copy - Copy an Ethernet address +++ * @dst: Pointer to a six-byte array Ethernet address destination +++ * @src: Pointer to a six-byte array Ethernet address source +++ * +++ * Please note: dst & src must both be aligned to u16. +++ */ +++#define ether_addr_copy LINUX_BACKPORT(ether_addr_copy) +++static inline void ether_addr_copy(u8 *dst, const u8 *src) +++{ +++#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) +++ *(u32 *)dst = *(const u32 *)src; +++ *(u16 *)(dst + 4) = *(const u16 *)(src + 4); +++#else +++ u16 *a = (u16 *)dst; +++ const u16 *b = (const u16 *)src; +++ +++ a[0] = b[0]; +++ a[1] = b[1]; +++ a[2] = b[2]; +++#endif +++} ++ #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0) */ ++ ++ #endif /* _BACKPORT_LINUX_ETHERDEVICE_H */ ++--- a/drivers/net/wireless/ath/spectral_common.h +++++ b/drivers/net/wireless/ath/spectral_common.h ++@@ -20,6 +20,11 @@ ++ #define SPECTRAL_HT20_NUM_BINS 56 ++ #define SPECTRAL_HT20_40_NUM_BINS 128 ++ +++/* TODO: could possibly be 512, but no samples this large +++ * could be acquired so far. +++ */ +++#define SPECTRAL_ATH10K_MAX_NUM_BINS 256 +++ ++ /* FFT sample format given to userspace via debugfs. ++ * ++ * Please keep the type/length at the front position and change ++@@ -31,6 +36,7 @@ ++ enum ath_fft_sample_type { ++ ATH_FFT_SAMPLE_HT20 = 1, ++ ATH_FFT_SAMPLE_HT20_40, +++ ATH_FFT_SAMPLE_ATH10K, ++ }; ++ ++ struct fft_sample_tlv { ++@@ -85,4 +91,23 @@ struct fft_sample_ht20_40 { ++ u8 data[SPECTRAL_HT20_40_NUM_BINS]; ++ } __packed; ++ +++struct fft_sample_ath10k { +++ struct fft_sample_tlv tlv; +++ u8 chan_width_mhz; +++ __be16 freq1; +++ __be16 freq2; +++ __be16 noise; +++ __be16 max_magnitude; +++ __be16 total_gain_db; +++ __be16 base_pwr_db; +++ __be64 tsf; +++ s8 max_index; +++ u8 rssi; +++ u8 relpwr_db; +++ u8 avgpwr_db; +++ u8 max_exp; +++ +++ u8 data[0]; +++} __packed; +++ ++ #endif /* SPECTRAL_COMMON_H */ +diff --git a/package/kernel/mac80211/patches/920-ath10k_allow_fallback_to_board_bin_on_empty_otp_stream.patch b/package/kernel/mac80211/patches/920-ath10k_allow_fallback_to_board_bin_on_empty_otp_stream.patch +index 6a5c766..6a3d2a4 100644 +--- a/package/kernel/mac80211/patches/920-ath10k_allow_fallback_to_board_bin_on_empty_otp_stream.patch ++++ b/package/kernel/mac80211/patches/920-ath10k_allow_fallback_to_board_bin_on_empty_otp_stream.patch +@@ -1,14 +1,14 @@ + --- a/drivers/net/wireless/ath/ath10k/core.c + +++ b/drivers/net/wireless/ath/ath10k/core.c +-@@ -277,7 +277,10 @@ static int ath10k_download_and_run_otp(s ++@@ -387,7 +387,10 @@ static int ath10k_download_and_run_otp(s + +- ath10k_dbg(ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); + +-- if (result != 0) { ++- if (!skip_otp && result != 0) { + + if (result == 2) { +-+ ath10k_warn("otp stream is empty, using board.bin contents"); +++ ath10k_warn(ar, "otp stream is empty, using board.bin contents"); + + return 0; +-+ } else if (result != 0) { +- ath10k_err("otp calibration failed: %d", result); +++ } else if (!skip_otp && result != 0) { ++ ath10k_err(ar, "otp calibration failed: %d", result); + return -EINVAL; + } +diff --git a/package/kernel/mac80211/patches/921-ath10k_init_devices_synchronously.patch b/package/kernel/mac80211/patches/921-ath10k_init_devices_synchronously.patch +new file mode 100644 +index 0000000..c664faa +--- /dev/null ++++ b/package/kernel/mac80211/patches/921-ath10k_init_devices_synchronously.patch +@@ -0,0 +1,33 @@ ++From: Sven Eckelmann ++Date: Tue, 18 Nov 2014 12:29:28 +0100 ++Subject: [PATCH] ath10k: Don't initialize devices asynchronously ++ ++OpenWrt requires all PHYs to be initialized to create the configuration files ++during bootup. ath10k violates this because it delays the creation of the PHY ++to a not well defined point in the future. ++ ++Forcing the work to be done immediately works around this problem but may also ++delay the boot when firmware images cannot be found. ++ ++Signed-off-by: Sven Eckelmann ++--- ++ ++--- a/drivers/net/wireless/ath/ath10k/core.c +++++ b/drivers/net/wireless/ath/ath10k/core.c ++@@ -1321,6 +1321,16 @@ int ath10k_core_register(struct ath10k * ++ ar->chip_id = chip_id; ++ queue_work(ar->workqueue, &ar->register_work); ++ +++ /* OpenWrt requires all PHYs to be initialized to create the +++ * configuration files during bootup. ath10k violates this +++ * because it delays the creation of the PHY to a not well defined +++ * point in the future. +++ * +++ * Forcing the work to be done immediately works around this problem +++ * but may also delay the boot when firmware images cannot be found. +++ */ +++ flush_workqueue(ar->workqueue); +++ ++ return 0; ++ } ++ EXPORT_SYMBOL(ath10k_core_register); +diff --git a/package/kernel/mac80211/patches/930-ath10k_add_tpt_led_trigger.patch b/package/kernel/mac80211/patches/930-ath10k_add_tpt_led_trigger.patch +new file mode 100644 +index 0000000..54174b1 +--- /dev/null ++++ b/package/kernel/mac80211/patches/930-ath10k_add_tpt_led_trigger.patch +@@ -0,0 +1,37 @@ ++--- a/drivers/net/wireless/ath/ath10k/mac.c +++++ b/drivers/net/wireless/ath/ath10k/mac.c ++@@ -5405,6 +5405,21 @@ struct ath10k_vif *ath10k_get_arvif(stru ++ return arvif_iter.arvif; ++ } ++ +++#ifdef CPTCFG_MAC80211_LEDS +++static const struct ieee80211_tpt_blink ath10k_tpt_blink[] = { +++ { .throughput = 0 * 1024, .blink_time = 334 }, +++ { .throughput = 1 * 1024, .blink_time = 260 }, +++ { .throughput = 2 * 1024, .blink_time = 220 }, +++ { .throughput = 5 * 1024, .blink_time = 190 }, +++ { .throughput = 10 * 1024, .blink_time = 170 }, +++ { .throughput = 25 * 1024, .blink_time = 150 }, +++ { .throughput = 54 * 1024, .blink_time = 130 }, +++ { .throughput = 120 * 1024, .blink_time = 110 }, +++ { .throughput = 265 * 1024, .blink_time = 80 }, +++ { .throughput = 586 * 1024, .blink_time = 50 }, +++}; +++#endif +++ ++ int ath10k_mac_register(struct ath10k *ar) ++ { ++ struct ieee80211_supported_band *band; ++@@ -5567,6 +5582,12 @@ int ath10k_mac_register(struct ath10k *a ++ goto err_free; ++ } ++ +++#if CPTCFG_MAC80211_LEDS +++ ieee80211_create_tpt_led_trigger(ar->hw, +++ IEEE80211_TPT_LEDTRIG_FL_RADIO, ath10k_tpt_blink, +++ ARRAY_SIZE(ath10k_tpt_blink)); +++#endif +++ ++ ret = ieee80211_register_hw(ar->hw); ++ if (ret) { ++ ath10k_err(ar, "failed to register ieee80211: %d\n", ret); +diff --git a/package/kernel/mac80211/patches/950-ath10k_AP_IBSS.patch b/package/kernel/mac80211/patches/950-ath10k_AP_IBSS.patch +new file mode 100644 +index 0000000..0011b5d +--- /dev/null ++++ b/package/kernel/mac80211/patches/950-ath10k_AP_IBSS.patch +@@ -0,0 +1,32 @@ ++--- a/drivers/net/wireless/ath/ath10k/mac.c +++++ b/drivers/net/wireless/ath/ath10k/mac.c ++@@ -5253,6 +5253,10 @@ static const struct ieee80211_iface_limi ++ .max = 7, ++ .types = BIT(NL80211_IFTYPE_AP) ++ }, +++ { +++ .max = 1, +++ .types = BIT(NL80211_IFTYPE_ADHOC) +++ }, ++ }; ++ ++ static const struct ieee80211_iface_limit ath10k_10x_if_limits[] = { ++@@ -5260,6 +5264,10 @@ static const struct ieee80211_iface_limi ++ .max = 8, ++ .types = BIT(NL80211_IFTYPE_AP) ++ }, +++ { +++ .max = 1, +++ .types = BIT(NL80211_IFTYPE_ADHOC) +++ }, ++ }; ++ ++ static const struct ieee80211_iface_combination ath10k_if_comb[] = { ++@@ -5555,6 +5563,7 @@ int ath10k_mac_register(struct ath10k *a ++ ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb; ++ ar->hw->wiphy->n_iface_combinations = ++ ARRAY_SIZE(ath10k_10x_if_comb); +++ ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); ++ break; ++ case ATH10K_FW_WMI_OP_VERSION_UNSET: ++ case ATH10K_FW_WMI_OP_VERSION_MAX: diff --git a/patches/openwrt/0018-ath10k-update-firmware-to-the-latest-version.patch b/patches/openwrt/0018-ath10k-update-firmware-to-the-latest-version.patch new file mode 100644 index 00000000..56ddc5ea --- /dev/null +++ b/patches/openwrt/0018-ath10k-update-firmware-to-the-latest-version.patch @@ -0,0 +1,41 @@ +From: Matthias Schiffer +Date: Tue, 10 Mar 2015 13:17:06 +0100 +Subject: ath10k: update firmware to the latest version + +Signed-off-by: Felix Fietkau + +diff --git a/package/kernel/mac80211/Makefile b/package/kernel/mac80211/Makefile +index b96e782..629692d 100644 +--- a/package/kernel/mac80211/Makefile ++++ b/package/kernel/mac80211/Makefile +@@ -129,7 +129,7 @@ endef + $(eval $(call Download,linux-firmware)) + + PKG_ATH10K_LINUX_FIRMWARE_NAME:=ath10k-firmware +-PKG_ATH10K_LINUX_FIRMWARE_VERSION:=38eeda3ae6f90fde5546bdd48ee4ff3090f238c0 ++PKG_ATH10K_LINUX_FIRMWARE_VERSION:=232b419e71dab27b52b96e80ea7649ed67bdac77 + PKG_ATH10K_LINUX_FIRMWARE_SOURCE:=$(PKG_ATH10K_LINUX_FIRMWARE_NAME)-$(PKG_ATH10K_LINUX_FIRMWARE_VERSION).tar.bz2 + PKG_ATH10K_LINUX_FIRMWARE_PROTO:=git + PKG_ATH10K_LINUX_FIRMWARE_SOURCE_URL:=https://github.com/kvalo/ath10k-firmware.git +@@ -1821,18 +1821,17 @@ endef + + define KernelPackage/ath10k/install + $(INSTALL_DIR) $(1)/lib/firmware/ath10k/QCA988X/hw2.0 +-ifeq ($(CONFIG_ATH10K_STA_FW),y) + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/$(PKG_ATH10K_LINUX_FIRMWARE_SUBDIR)/ath10k/QCA988X/hw2.0/board.bin \ + $(1)/lib/firmware/ath10k/QCA988X/hw2.0/ ++ifeq ($(CONFIG_ATH10K_STA_FW),y) + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/$(PKG_ATH10K_LINUX_FIRMWARE_SUBDIR)/main/firmware-2.bin_999.999.0.636 \ + $(1)/lib/firmware/ath10k/QCA988X/hw2.0/firmware-2.bin + else + $(INSTALL_DATA) \ +- $(PKG_BUILD_DIR)/$(PKG_ATH10K_LINUX_FIRMWARE_SUBDIR)/ath10k/QCA988X/hw2.0/board.bin \ +- $(PKG_BUILD_DIR)/$(PKG_ATH10K_LINUX_FIRMWARE_SUBDIR)/ath10k/QCA988X/hw2.0/firmware-2.bin \ +- $(1)/lib/firmware/ath10k/QCA988X/hw2.0/ ++ $(PKG_BUILD_DIR)/$(PKG_ATH10K_LINUX_FIRMWARE_SUBDIR)/10.2/firmware-3.bin_10.2-00082-4-2 \ ++ $(1)/lib/firmware/ath10k/QCA988X/hw2.0/firmware-3.bin + endif + endef + diff --git a/patches/openwrt/0019-ath10k-add-Candelatech-community-firmware-as-an-additional-choice.patch b/patches/openwrt/0019-ath10k-add-Candelatech-community-firmware-as-an-additional-choice.patch new file mode 100644 index 00000000..0fa623f4 --- /dev/null +++ b/patches/openwrt/0019-ath10k-add-Candelatech-community-firmware-as-an-additional-choice.patch @@ -0,0 +1,81 @@ +From: Matthias Schiffer +Date: Tue, 10 Mar 2015 13:17:14 +0100 +Subject: ath10k: add Candelatech community firmware as an additional choice + +diff --git a/package/kernel/mac80211/Makefile b/package/kernel/mac80211/Makefile +index 629692d..d77842a 100644 +--- a/package/kernel/mac80211/Makefile ++++ b/package/kernel/mac80211/Makefile +@@ -605,6 +605,14 @@ This module adds support for wireless adapters based on + Atheros USB AR9271 and AR7010 family of chipsets. + endef + ++ATH10K_CT_COMMUNITY_FW:=firmware-2-ct-full-community-13.bin ++define Download/ath10k-firmware-ct-community ++ FILE:=$(ATH10K_CT_COMMUNITY_FW) ++ URL:=http://www.candelatech.com/downloads/ ++ MD5SUM:=a3decc529b0171ae9ec4495089ab354a ++endef ++$(eval $(call Download,ath10k-firmware-ct-community)) ++ + define KernelPackage/ath10k + $(call KernelPackage/mac80211/Default) + TITLE:=Atheros 802.11ac wireless cards support +@@ -625,13 +633,31 @@ endef + define KernelPackage/ath10k/config + if PACKAGE_kmod-ath10k + ++ choice ++ prompt "ath10k firmware flavour" ++ default ATH10K_AP_FW ++ help ++ This option allows you to choose between different ath10k firmwares. ++ ++ config ATH10K_AP_FW ++ bool "Firmware optimized for AP operation" ++ help ++ Use the ath10k firmware optimized for access point operation. ++ Supports only AP mode, will crash in IBSS (ad-hoc) mode. ++ + config ATH10K_STA_FW + bool "Firmware optimized for STA operation" +- default n + help + Use the ath10k firmware optimized for wireless client instead +- of access point operation. ++ of access point operation. Might be unstable in AP mode. ++ ++ config ATH10K_CT_COMMUNITY_FW ++ bool "Firmware by Candela Technologies (community version)" ++ help ++ Supports both AP and IBSS (ad-hoc) mode. Doesn't support ++ encryption when using multiple VIFs. + ++ endchoice + endif + endef + +@@ -1824,14 +1850,20 @@ define KernelPackage/ath10k/install + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/$(PKG_ATH10K_LINUX_FIRMWARE_SUBDIR)/ath10k/QCA988X/hw2.0/board.bin \ + $(1)/lib/firmware/ath10k/QCA988X/hw2.0/ ++ifeq ($(CONFIG_ATH10K_AP_FW),y) ++ $(INSTALL_DATA) \ ++ $(PKG_BUILD_DIR)/$(PKG_ATH10K_LINUX_FIRMWARE_SUBDIR)/10.2/firmware-3.bin_10.2-00082-4-2 \ ++ $(1)/lib/firmware/ath10k/QCA988X/hw2.0/firmware-3.bin ++endif + ifeq ($(CONFIG_ATH10K_STA_FW),y) + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/$(PKG_ATH10K_LINUX_FIRMWARE_SUBDIR)/main/firmware-2.bin_999.999.0.636 \ + $(1)/lib/firmware/ath10k/QCA988X/hw2.0/firmware-2.bin +-else ++endif ++ifeq ($(CONFIG_ATH10K_CT_COMMUNITY_FW),y) + $(INSTALL_DATA) \ +- $(PKG_BUILD_DIR)/$(PKG_ATH10K_LINUX_FIRMWARE_SUBDIR)/10.2/firmware-3.bin_10.2-00082-4-2 \ +- $(1)/lib/firmware/ath10k/QCA988X/hw2.0/firmware-3.bin ++ $(DL_DIR)/$(ATH10K_CT_COMMUNITY_FW) \ ++ $(1)/lib/firmware/ath10k/QCA988X/hw2.0/firmware-2.bin + endif + endef +