Commit 9e4b4269 authored by John W. Linville's avatar John W. Linville

Merge branch 'for-linville' of git://github.com/kvalo/ath

parents 161d7855 9797febc
...@@ -63,7 +63,7 @@ enum ath_bus_type { ...@@ -63,7 +63,7 @@ enum ath_bus_type {
}; };
struct reg_dmn_pair_mapping { struct reg_dmn_pair_mapping {
u16 regDmnEnum; u16 reg_domain;
u16 reg_5ghz_ctl; u16 reg_5ghz_ctl;
u16 reg_2ghz_ctl; u16 reg_2ghz_ctl;
}; };
......
...@@ -55,8 +55,7 @@ static void ath10k_send_suspend_complete(struct ath10k *ar) ...@@ -55,8 +55,7 @@ static void ath10k_send_suspend_complete(struct ath10k *ar)
{ {
ath10k_dbg(ATH10K_DBG_BOOT, "boot suspend complete\n"); ath10k_dbg(ATH10K_DBG_BOOT, "boot suspend complete\n");
ar->is_target_paused = true; complete(&ar->target_suspend);
wake_up(&ar->event_queue);
} }
static int ath10k_init_connect_htc(struct ath10k *ar) static int ath10k_init_connect_htc(struct ath10k *ar)
...@@ -470,8 +469,12 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) ...@@ -470,8 +469,12 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
if (index == ie_len) if (index == ie_len)
break; break;
if (data[index] & (1 << bit)) if (data[index] & (1 << bit)) {
ath10k_dbg(ATH10K_DBG_BOOT,
"Enabling feature bit: %i\n",
i);
__set_bit(i, ar->fw_features); __set_bit(i, ar->fw_features);
}
} }
ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "", ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "",
...@@ -699,6 +702,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, ...@@ -699,6 +702,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
init_completion(&ar->scan.started); init_completion(&ar->scan.started);
init_completion(&ar->scan.completed); init_completion(&ar->scan.completed);
init_completion(&ar->scan.on_channel); init_completion(&ar->scan.on_channel);
init_completion(&ar->target_suspend);
init_completion(&ar->install_key_done); init_completion(&ar->install_key_done);
init_completion(&ar->vdev_setup_done); init_completion(&ar->vdev_setup_done);
...@@ -722,8 +726,6 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, ...@@ -722,8 +726,6 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work); INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work);
skb_queue_head_init(&ar->wmi_mgmt_tx_queue); skb_queue_head_init(&ar->wmi_mgmt_tx_queue);
init_waitqueue_head(&ar->event_queue);
INIT_WORK(&ar->restart_work, ath10k_core_restart); INIT_WORK(&ar->restart_work, ath10k_core_restart);
return ar; return ar;
...@@ -856,10 +858,34 @@ int ath10k_core_start(struct ath10k *ar) ...@@ -856,10 +858,34 @@ int ath10k_core_start(struct ath10k *ar)
} }
EXPORT_SYMBOL(ath10k_core_start); EXPORT_SYMBOL(ath10k_core_start);
int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt)
{
int ret;
reinit_completion(&ar->target_suspend);
ret = ath10k_wmi_pdev_suspend_target(ar, suspend_opt);
if (ret) {
ath10k_warn("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");
return -ETIMEDOUT;
}
return 0;
}
void ath10k_core_stop(struct ath10k *ar) void ath10k_core_stop(struct ath10k *ar)
{ {
lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->conf_mutex);
/* try to suspend target */
ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR);
ath10k_debug_stop(ar); ath10k_debug_stop(ar);
ath10k_htc_stop(&ar->htc); ath10k_htc_stop(&ar->htc);
ath10k_htt_detach(&ar->htt); ath10k_htt_detach(&ar->htt);
......
...@@ -46,6 +46,18 @@ ...@@ -46,6 +46,18 @@
#define ATH10K_MAX_NUM_MGMT_PENDING 128 #define ATH10K_MAX_NUM_MGMT_PENDING 128
/* number of failed packets */
#define ATH10K_KICKOUT_THRESHOLD 50
/*
* Use insanely high numbers to make sure that the firmware implementation
* won't start, we have the same functionality already in hostapd. Unit
* is seconds.
*/
#define ATH10K_KEEPALIVE_MIN_IDLE 3747
#define ATH10K_KEEPALIVE_MAX_IDLE 3895
#define ATH10K_KEEPALIVE_MAX_UNRESPONSIVE 3900
struct ath10k; struct ath10k;
struct ath10k_skb_cb { struct ath10k_skb_cb {
...@@ -61,6 +73,11 @@ struct ath10k_skb_cb { ...@@ -61,6 +73,11 @@ struct ath10k_skb_cb {
u8 frag_len; u8 frag_len;
u8 pad_len; u8 pad_len;
} __packed htt; } __packed htt;
struct {
bool dtim_zero;
bool deliver_cab;
} bcn;
} __packed; } __packed;
static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb) static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb)
...@@ -211,6 +228,18 @@ struct ath10k_peer { ...@@ -211,6 +228,18 @@ struct ath10k_peer {
struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1]; struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
}; };
struct ath10k_sta {
struct ath10k_vif *arvif;
/* the following are protected by ar->data_lock */
u32 changed; /* IEEE80211_RC_* */
u32 bw;
u32 nss;
u32 smps;
struct work_struct update_wk;
};
#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ) #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ)
struct ath10k_vif { struct ath10k_vif {
...@@ -222,10 +251,17 @@ struct ath10k_vif { ...@@ -222,10 +251,17 @@ struct ath10k_vif {
u32 beacon_interval; u32 beacon_interval;
u32 dtim_period; u32 dtim_period;
struct sk_buff *beacon; struct sk_buff *beacon;
/* protected by data_lock */
bool beacon_sent;
struct ath10k *ar; struct ath10k *ar;
struct ieee80211_vif *vif; struct ieee80211_vif *vif;
bool is_started;
bool is_up;
u32 aid;
u8 bssid[ETH_ALEN];
struct work_struct wep_key_work; struct work_struct wep_key_work;
struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1]; struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1];
u8 def_wep_key_idx; u8 def_wep_key_idx;
...@@ -235,7 +271,6 @@ struct ath10k_vif { ...@@ -235,7 +271,6 @@ struct ath10k_vif {
union { union {
struct { struct {
u8 bssid[ETH_ALEN];
u32 uapsd; u32 uapsd;
} sta; } sta;
struct { struct {
...@@ -249,9 +284,6 @@ struct ath10k_vif { ...@@ -249,9 +284,6 @@ struct ath10k_vif {
u32 noa_len; u32 noa_len;
u8 *noa_data; u8 *noa_data;
} ap; } ap;
struct {
u8 bssid[ETH_ALEN];
} ibss;
} u; } u;
u8 fixed_rate; u8 fixed_rate;
...@@ -355,8 +387,7 @@ struct ath10k { ...@@ -355,8 +387,7 @@ struct ath10k {
const struct ath10k_hif_ops *ops; const struct ath10k_hif_ops *ops;
} hif; } hif;
wait_queue_head_t event_queue; struct completion target_suspend;
bool is_target_paused;
struct ath10k_bmi bmi; struct ath10k_bmi bmi;
struct ath10k_wmi wmi; struct ath10k_wmi wmi;
...@@ -412,6 +443,9 @@ struct ath10k { ...@@ -412,6 +443,9 @@ struct ath10k {
/* valid during scan; needed for mgmt rx during scan */ /* valid during scan; needed for mgmt rx during scan */
struct ieee80211_channel *scan_channel; struct ieee80211_channel *scan_channel;
/* current operating channel definition */
struct cfg80211_chan_def chandef;
int free_vdev_map; int free_vdev_map;
int monitor_vdev_id; int monitor_vdev_id;
bool monitor_enabled; bool monitor_enabled;
...@@ -470,6 +504,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, ...@@ -470,6 +504,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
void ath10k_core_destroy(struct ath10k *ar); void ath10k_core_destroy(struct ath10k *ar);
int ath10k_core_start(struct ath10k *ar); int ath10k_core_start(struct ath10k *ar);
int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt);
void ath10k_core_stop(struct ath10k *ar); void ath10k_core_stop(struct ath10k *ar);
int ath10k_core_register(struct ath10k *ar, u32 chip_id); int ath10k_core_register(struct ath10k *ar, u32 chip_id);
void ath10k_core_unregister(struct ath10k *ar); void ath10k_core_unregister(struct ath10k *ar);
......
...@@ -92,7 +92,7 @@ static inline void ath10k_debug_read_target_stats(struct ath10k *ar, ...@@ -92,7 +92,7 @@ static inline void ath10k_debug_read_target_stats(struct ath10k *ar,
#ifdef CONFIG_ATH10K_DEBUG #ifdef CONFIG_ATH10K_DEBUG
__printf(2, 3) void ath10k_dbg(enum ath10k_debug_mask mask, __printf(2, 3) void ath10k_dbg(enum ath10k_debug_mask mask,
const char *fmt, ...); const char *fmt, ...);
void ath10k_dbg_dump(enum ath10k_debug_mask mask, void ath10k_dbg_dump(enum ath10k_debug_mask mask,
const char *msg, const char *prefix, const char *msg, const char *prefix,
const void *buf, size_t len); const void *buf, size_t len);
......
...@@ -324,7 +324,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, ...@@ -324,7 +324,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
msdu->len + skb_tailroom(msdu), msdu->len + skb_tailroom(msdu),
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx: ", ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx pop: ",
msdu->data, msdu->len + skb_tailroom(msdu)); msdu->data, msdu->len + skb_tailroom(msdu));
rx_desc = (struct htt_rx_desc *)msdu->data; rx_desc = (struct htt_rx_desc *)msdu->data;
...@@ -417,8 +417,8 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, ...@@ -417,8 +417,8 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
next->len + skb_tailroom(next), next->len + skb_tailroom(next),
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx: ", ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL,
next->data, "htt rx chained: ", next->data,
next->len + skb_tailroom(next)); next->len + skb_tailroom(next));
skb_trim(next, 0); skb_trim(next, 0);
...@@ -430,12 +430,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, ...@@ -430,12 +430,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
msdu_chaining = 1; msdu_chaining = 1;
} }
if (msdu_len > 0) {
/* This may suggest FW bug? */
ath10k_warn("htt rx msdu len not consumed (%d)\n",
msdu_len);
}
last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) & last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) &
RX_MSDU_END_INFO0_LAST_MSDU; RX_MSDU_END_INFO0_LAST_MSDU;
...@@ -751,7 +745,7 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info) ...@@ -751,7 +745,7 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info)
/* This shouldn't happen. If it does than it may be a FW bug. */ /* This shouldn't happen. If it does than it may be a FW bug. */
if (skb->next) { if (skb->next) {
ath10k_warn("received chained non A-MSDU frame\n"); ath10k_warn("htt rx received chained non A-MSDU frame\n");
ath10k_htt_rx_free_msdu_chain(skb->next); ath10k_htt_rx_free_msdu_chain(skb->next);
skb->next = NULL; skb->next = NULL;
} }
...@@ -937,6 +931,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, ...@@ -937,6 +931,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
} }
if (ath10k_htt_rx_has_decrypt_err(msdu_head)) { if (ath10k_htt_rx_has_decrypt_err(msdu_head)) {
ath10k_dbg(ATH10K_DBG_HTT,
"htt rx dropping due to decrypt-err\n");
ath10k_htt_rx_free_msdu_chain(msdu_head); ath10k_htt_rx_free_msdu_chain(msdu_head);
continue; continue;
} }
...@@ -945,12 +941,14 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, ...@@ -945,12 +941,14 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
/* Skip mgmt frames while we handle this in WMI */ /* Skip mgmt frames while we handle this in WMI */
if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL) { if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL) {
ath10k_dbg(ATH10K_DBG_HTT, "htt rx mgmt ctrl\n");
ath10k_htt_rx_free_msdu_chain(msdu_head); ath10k_htt_rx_free_msdu_chain(msdu_head);
continue; continue;
} }
if (status != HTT_RX_IND_MPDU_STATUS_OK && if (status != HTT_RX_IND_MPDU_STATUS_OK &&
status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR && status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR &&
status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER &&
!htt->ar->monitor_enabled) { !htt->ar->monitor_enabled) {
ath10k_dbg(ATH10K_DBG_HTT, ath10k_dbg(ATH10K_DBG_HTT,
"htt rx ignoring frame w/ status %d\n", "htt rx ignoring frame w/ status %d\n",
...@@ -960,6 +958,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, ...@@ -960,6 +958,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
} }
if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) { if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) {
ath10k_dbg(ATH10K_DBG_HTT,
"htt rx CAC running\n");
ath10k_htt_rx_free_msdu_chain(msdu_head); ath10k_htt_rx_free_msdu_chain(msdu_head);
continue; continue;
} }
...@@ -967,7 +967,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, ...@@ -967,7 +967,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
/* FIXME: we do not support chaining yet. /* FIXME: we do not support chaining yet.
* this needs investigation */ * this needs investigation */
if (msdu_chaining) { if (msdu_chaining) {
ath10k_warn("msdu_chaining is true\n"); ath10k_warn("htt rx msdu_chaining is true\n");
ath10k_htt_rx_free_msdu_chain(msdu_head); ath10k_htt_rx_free_msdu_chain(msdu_head);
continue; continue;
} }
...@@ -975,6 +975,15 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, ...@@ -975,6 +975,15 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
info.skb = msdu_head; info.skb = msdu_head;
info.fcs_err = ath10k_htt_rx_has_fcs_err(msdu_head); info.fcs_err = ath10k_htt_rx_has_fcs_err(msdu_head);
info.mic_err = ath10k_htt_rx_has_mic_err(msdu_head); info.mic_err = ath10k_htt_rx_has_mic_err(msdu_head);
if (info.fcs_err)
ath10k_dbg(ATH10K_DBG_HTT,
"htt rx has FCS err\n");
if (info.mic_err)
ath10k_dbg(ATH10K_DBG_HTT,
"htt rx has MIC err\n");
info.signal = ATH10K_DEFAULT_NOISE_FLOOR; info.signal = ATH10K_DEFAULT_NOISE_FLOOR;
info.signal += rx->ppdu.combined_rssi; info.signal += rx->ppdu.combined_rssi;
...@@ -1095,7 +1104,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, ...@@ -1095,7 +1104,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
skb_trim(info.skb, info.skb->len - trim); skb_trim(info.skb, info.skb->len - trim);
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt frag mpdu: ", ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ",
info.skb->data, info.skb->len); info.skb->data, info.skb->len);
ath10k_process_rx(htt->ar, &info); ath10k_process_rx(htt->ar, &info);
...@@ -1116,7 +1125,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) ...@@ -1116,7 +1125,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
if (!IS_ALIGNED((unsigned long)skb->data, 4)) if (!IS_ALIGNED((unsigned long)skb->data, 4))
ath10k_warn("unaligned htt message, expect trouble\n"); ath10k_warn("unaligned htt message, expect trouble\n");
ath10k_dbg(ATH10K_DBG_HTT, "HTT RX, msg_type: 0x%0X\n", ath10k_dbg(ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n",
resp->hdr.msg_type); resp->hdr.msg_type);
switch (resp->hdr.msg_type) { switch (resp->hdr.msg_type) {
case HTT_T2H_MSG_TYPE_VERSION_CONF: { case HTT_T2H_MSG_TYPE_VERSION_CONF: {
......
...@@ -460,9 +460,9 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) ...@@ -460,9 +460,9 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
DMA_TO_DEVICE); DMA_TO_DEVICE);
} }
ath10k_dbg(ATH10K_DBG_HTT, "msdu 0x%llx\n", ath10k_dbg(ATH10K_DBG_HTT, "tx-msdu 0x%llx\n",
(unsigned long long) ATH10K_SKB_CB(msdu)->paddr); (unsigned long long) ATH10K_SKB_CB(msdu)->paddr);
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "msdu: ", ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "tx-msdu: ",
msdu->data, msdu->len); msdu->data, msdu->len);
skb_put(txdesc, desc_len); skb_put(txdesc, desc_len);
......
...@@ -205,8 +205,11 @@ enum ath10k_mcast2ucast_mode { ...@@ -205,8 +205,11 @@ enum ath10k_mcast2ucast_mode {
#define WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x0006c000 #define WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x0006c000
#define PCIE_LOCAL_BASE_ADDRESS 0x00080000 #define PCIE_LOCAL_BASE_ADDRESS 0x00080000
#define SOC_RESET_CONTROL_ADDRESS 0x00000000
#define SOC_RESET_CONTROL_OFFSET 0x00000000 #define SOC_RESET_CONTROL_OFFSET 0x00000000
#define SOC_RESET_CONTROL_SI0_RST_MASK 0x00000001 #define SOC_RESET_CONTROL_SI0_RST_MASK 0x00000001
#define SOC_RESET_CONTROL_CE_RST_MASK 0x00040000
#define SOC_RESET_CONTROL_CPU_WARM_RST_MASK 0x00000040
#define SOC_CPU_CLOCK_OFFSET 0x00000020 #define SOC_CPU_CLOCK_OFFSET 0x00000020
#define SOC_CPU_CLOCK_STANDARD_LSB 0 #define SOC_CPU_CLOCK_STANDARD_LSB 0
#define SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 #define SOC_CPU_CLOCK_STANDARD_MASK 0x00000003
...@@ -216,6 +219,8 @@ enum ath10k_mcast2ucast_mode { ...@@ -216,6 +219,8 @@ enum ath10k_mcast2ucast_mode {
#define SOC_LPO_CAL_OFFSET 0x000000e0 #define SOC_LPO_CAL_OFFSET 0x000000e0
#define SOC_LPO_CAL_ENABLE_LSB 20 #define SOC_LPO_CAL_ENABLE_LSB 20
#define SOC_LPO_CAL_ENABLE_MASK 0x00100000 #define SOC_LPO_CAL_ENABLE_MASK 0x00100000
#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 0x000000ec
#define SOC_CHIP_ID_REV_LSB 8 #define SOC_CHIP_ID_REV_LSB 8
...@@ -273,6 +278,7 @@ enum ath10k_mcast2ucast_mode { ...@@ -273,6 +278,7 @@ enum ath10k_mcast2ucast_mode {
#define PCIE_INTR_CAUSE_ADDRESS 0x000c #define PCIE_INTR_CAUSE_ADDRESS 0x000c
#define PCIE_INTR_CLR_ADDRESS 0x0014 #define PCIE_INTR_CLR_ADDRESS 0x0014
#define SCRATCH_3_ADDRESS 0x0030 #define SCRATCH_3_ADDRESS 0x0030
#define CPU_INTR_ADDRESS 0x0010
/* Firmware indications to the Host via SCRATCH_3 register. */ /* Firmware indications to the Host via SCRATCH_3 register. */
#define FW_INDICATOR_ADDRESS (SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS) #define FW_INDICATOR_ADDRESS (SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS)
......
...@@ -339,6 +339,50 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr) ...@@ -339,6 +339,50 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
return 0; return 0;
} }
static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
{
struct ath10k *ar = arvif->ar;
u32 param;
int ret;
param = ar->wmi.pdev_param->sta_kickout_th;
ret = ath10k_wmi_pdev_set_param(ar, param,
ATH10K_KICKOUT_THRESHOLD);
if (ret) {
ath10k_warn("Failed to set kickout threshold: %d\n", ret);
return ret;
}
param = ar->wmi.vdev_param->ap_keepalive_min_idle_inactive_time_secs;
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 : %d\n",
ret);
return ret;
}
param = ar->wmi.vdev_param->ap_keepalive_max_idle_inactive_time_secs;
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: %d\n",
ret);
return ret;
}
param = ar->wmi.vdev_param->ap_keepalive_max_unresponsive_time_secs;
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: %d\n",
ret);
return ret;
}
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; struct ath10k *ar = arvif->ar;
...@@ -444,8 +488,7 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar) ...@@ -444,8 +488,7 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
static int ath10k_vdev_start(struct ath10k_vif *arvif) static int ath10k_vdev_start(struct ath10k_vif *arvif)
{ {
struct ath10k *ar = arvif->ar; struct ath10k *ar = arvif->ar;
struct ieee80211_conf *conf = &ar->hw->conf; struct cfg80211_chan_def *chandef = &ar->chandef;
struct ieee80211_channel *channel = conf->chandef.chan;
struct wmi_vdev_start_request_arg arg = {}; struct wmi_vdev_start_request_arg arg = {};
int ret = 0; int ret = 0;
...@@ -457,16 +500,14 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif) ...@@ -457,16 +500,14 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif)
arg.dtim_period = arvif->dtim_period; arg.dtim_period = arvif->dtim_period;
arg.bcn_intval = arvif->beacon_interval; arg.bcn_intval = arvif->beacon_interval;
arg.channel.freq = channel->center_freq; arg.channel.freq = chandef->chan->center_freq;
arg.channel.band_center_freq1 = chandef->center_freq1;
arg.channel.band_center_freq1 = conf->chandef.center_freq1; arg.channel.mode = chan_to_phymode(chandef);
arg.channel.mode = chan_to_phymode(&conf->chandef);
arg.channel.min_power = 0; arg.channel.min_power = 0;
arg.channel.max_power = channel->max_power * 2; arg.channel.max_power = chandef->chan->max_power * 2;
arg.channel.max_reg_power = channel->max_reg_power * 2; arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
arg.channel.max_antenna_gain = channel->max_antenna_gain * 2; arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2;
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
arg.ssid = arvif->u.ap.ssid; arg.ssid = arvif->u.ap.ssid;
...@@ -475,7 +516,7 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif) ...@@ -475,7 +516,7 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif)
/* For now allow DFS for AP mode */ /* For now allow DFS for AP mode */
arg.channel.chan_radar = arg.channel.chan_radar =
!!(channel->flags & IEEE80211_CHAN_RADAR); !!(chandef->chan->flags & IEEE80211_CHAN_RADAR);
} else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { } else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
arg.ssid = arvif->vif->bss_conf.ssid; arg.ssid = arvif->vif->bss_conf.ssid;
arg.ssid_len = arvif->vif->bss_conf.ssid_len; arg.ssid_len = arvif->vif->bss_conf.ssid_len;
...@@ -527,7 +568,8 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif) ...@@ -527,7 +568,8 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif)
static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
{ {
struct ieee80211_channel *channel = ar->hw->conf.chandef.chan; struct cfg80211_chan_def *chandef = &ar->chandef;
struct ieee80211_channel *channel = chandef->chan;
struct wmi_vdev_start_request_arg arg = {}; struct wmi_vdev_start_request_arg arg = {};
int ret = 0; int ret = 0;
...@@ -540,11 +582,11 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) ...@@ -540,11 +582,11 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
arg.vdev_id = vdev_id; arg.vdev_id = vdev_id;
arg.channel.freq = channel->center_freq; arg.channel.freq = channel->center_freq;
arg.channel.band_center_freq1 = ar->hw->conf.chandef.center_freq1; arg.channel.band_center_freq1 = chandef->center_freq1;
/* TODO setup this dynamically, what in case we /* TODO setup this dynamically, what in case we
don't have any vifs? */ don't have any vifs? */
arg.channel.mode = chan_to_phymode(&ar->hw->conf.chandef); arg.channel.mode = chan_to_phymode(chandef);
arg.channel.chan_radar = arg.channel.chan_radar =
!!(channel->flags & IEEE80211_CHAN_RADAR); !!(channel->flags & IEEE80211_CHAN_RADAR);
...@@ -791,6 +833,20 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, ...@@ -791,6 +833,20 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
if (!info->enable_beacon) { if (!info->enable_beacon) {
ath10k_vdev_stop(arvif); ath10k_vdev_stop(arvif);
arvif->is_started = false;
arvif->is_up = false;
spin_lock_bh(&arvif->ar->data_lock);
if (arvif->beacon) {
ath10k_skb_unmap(arvif->ar->dev, arvif->beacon);
dev_kfree_skb_any(arvif->beacon);
arvif->beacon = NULL;
arvif->beacon_sent = false;
}
spin_unlock_bh(&arvif->ar->data_lock);
return; return;
} }
...@@ -800,12 +856,21 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, ...@@ -800,12 +856,21 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
if (ret) if (ret)
return; return;
ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, 0, info->bssid); arvif->aid = 0;
memcpy(arvif->bssid, info->bssid, ETH_ALEN);
ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
arvif->bssid);
if (ret) { if (ret) {
ath10k_warn("Failed to bring up VDEV: %d\n", ath10k_warn("Failed to bring up VDEV: %d\n",
arvif->vdev_id); arvif->vdev_id);
ath10k_vdev_stop(arvif);
return; return;
} }
arvif->is_started = true;
arvif->is_up = true;
ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id); ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
} }
...@@ -824,18 +889,18 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, ...@@ -824,18 +889,18 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
ath10k_warn("Failed to delete IBSS self peer:%pM for VDEV:%d ret:%d\n", ath10k_warn("Failed to delete IBSS self peer:%pM for VDEV:%d ret:%d\n",
self_peer, arvif->vdev_id, ret); self_peer, arvif->vdev_id, ret);
if (is_zero_ether_addr(arvif->u.ibss.bssid)) if (is_zero_ether_addr(arvif->bssid))
return; return;
ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id,
arvif->u.ibss.bssid); arvif->bssid);
if (ret) { if (ret) {
ath10k_warn("Failed to delete IBSS BSSID peer:%pM for VDEV:%d ret:%d\n", ath10k_warn("Failed to delete IBSS BSSID peer:%pM for VDEV:%d ret:%d\n",
arvif->u.ibss.bssid, arvif->vdev_id, ret); arvif->bssid, arvif->vdev_id, ret);
return; return;
} }
memset(arvif->u.ibss.bssid, 0, ETH_ALEN); memset(arvif->bssid, 0, ETH_ALEN);
return; return;
} }
...@@ -1017,7 +1082,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, ...@@ -1017,7 +1082,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
struct wmi_peer_assoc_complete_arg *arg) struct wmi_peer_assoc_complete_arg *arg)
{ {
const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
int smps;
int i, n; int i, n;
lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->conf_mutex);
...@@ -1063,17 +1127,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, ...@@ -1063,17 +1127,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
arg->peer_flags |= WMI_PEER_STBC; arg->peer_flags |= WMI_PEER_STBC;
} }
smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS;
smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT;
if (smps == WLAN_HT_CAP_SM_PS_STATIC) {
arg->peer_flags |= WMI_PEER_SPATIAL_MUX;
arg->peer_flags |= WMI_PEER_STATIC_MIMOPS;
} else if (smps == WLAN_HT_CAP_SM_PS_DYNAMIC) {
arg->peer_flags |= WMI_PEER_SPATIAL_MUX;
arg->peer_flags |= WMI_PEER_DYN_MIMOPS;
}
if (ht_cap->mcs.rx_mask[1] && ht_cap->mcs.rx_mask[2]) if (ht_cap->mcs.rx_mask[1] && ht_cap->mcs.rx_mask[2])
arg->peer_rate_caps |= WMI_RC_TS_FLAG; arg->peer_rate_caps |= WMI_RC_TS_FLAG;
else if (ht_cap->mcs.rx_mask[1]) else if (ht_cap->mcs.rx_mask[1])
...@@ -1083,8 +1136,23 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, ...@@ -1083,8 +1136,23 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
if (ht_cap->mcs.rx_mask[i/8] & (1 << i%8)) if (ht_cap->mcs.rx_mask[i/8] & (1 << i%8))
arg->peer_ht_rates.rates[n++] = i; arg->peer_ht_rates.rates[n++] = i;
arg->peer_ht_rates.num_rates = n; /*
arg->peer_num_spatial_streams = max((n+7) / 8, 1); * This is a workaround for HT-enabled STAs which break the spec
* and have no HT capabilities RX mask (no HT RX MCS map).
*
* As per spec, in section 20.3.5 Modulation and coding scheme (MCS),
* MCS 0 through 7 are mandatory in 20MHz with 800 ns GI at all STAs.
*
* Firmware asserts if such situation occurs.
*/
if (n == 0) {
arg->peer_ht_rates.num_rates = 8;
for (i = 0; i < arg->peer_ht_rates.num_rates; i++)
arg->peer_ht_rates.rates[i] = i;
} else {
arg->peer_ht_rates.num_rates = n;
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(ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
arg->addr, arg->addr,
...@@ -1092,27 +1160,20 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, ...@@ -1092,27 +1160,20 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
arg->peer_num_spatial_streams); arg->peer_num_spatial_streams);
} }
static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar, static int ath10k_peer_assoc_qos_ap(struct ath10k *ar,
struct ath10k_vif *arvif, struct ath10k_vif *arvif,
struct ieee80211_sta *sta, struct ieee80211_sta *sta)
struct ieee80211_bss_conf *bss_conf,
struct wmi_peer_assoc_complete_arg *arg)
{ {
u32 uapsd = 0; u32 uapsd = 0;
u32 max_sp = 0; u32 max_sp = 0;
int ret = 0;
lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->conf_mutex);
if (sta->wme)
arg->peer_flags |= WMI_PEER_QOS;
if (sta->wme && sta->uapsd_queues) { if (sta->wme && sta->uapsd_queues) {
ath10k_dbg(ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n", ath10k_dbg(ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n",
sta->uapsd_queues, sta->max_sp); sta->uapsd_queues, sta->max_sp);
arg->peer_flags |= WMI_PEER_APSD;
arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG;
if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN | uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN |
WMI_AP_PS_UAPSD_AC3_TRIGGER_EN; WMI_AP_PS_UAPSD_AC3_TRIGGER_EN;
...@@ -1130,35 +1191,40 @@ static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar, ...@@ -1130,35 +1191,40 @@ static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar,
if (sta->max_sp < MAX_WMI_AP_PS_PEER_PARAM_MAX_SP) if (sta->max_sp < MAX_WMI_AP_PS_PEER_PARAM_MAX_SP)
max_sp = sta->max_sp; max_sp = sta->max_sp;
ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id,
sta->addr, sta->addr,
WMI_AP_PS_PEER_PARAM_UAPSD, WMI_AP_PS_PEER_PARAM_UAPSD,
uapsd); uapsd);
if (ret) {
ath10k_warn("failed to set ap ps peer param uapsd: %d\n",
ret);
return ret;
}
ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id,
sta->addr, sta->addr,
WMI_AP_PS_PEER_PARAM_MAX_SP, WMI_AP_PS_PEER_PARAM_MAX_SP,
max_sp); max_sp);
if (ret) {
ath10k_warn("failed to set ap ps peer param max sp: %d\n",
ret);
return ret;
}
/* TODO setup this based on STA listen interval and /* TODO setup this based on STA listen interval and
beacon interval. Currently we don't know beacon interval. Currently we don't know
sta->listen_interval - mac80211 patch required. sta->listen_interval - mac80211 patch required.
Currently use 10 seconds */ Currently use 10 seconds */
ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, sta->addr,
sta->addr, WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, 10);
WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, if (ret) {
10); ath10k_warn("failed to set ap ps peer param ageout time: %d\n",
ret);
return ret;
}
} }
}
static void ath10k_peer_assoc_h_qos_sta(struct ath10k *ar, return 0;
struct ath10k_vif *arvif,
struct ieee80211_sta *sta,
struct ieee80211_bss_conf *bss_conf,
struct wmi_peer_assoc_complete_arg *arg)
{
if (bss_conf->qos)
arg->peer_flags |= WMI_PEER_QOS;
} }
static void ath10k_peer_assoc_h_vht(struct ath10k *ar, static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
...@@ -1211,10 +1277,17 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar, ...@@ -1211,10 +1277,17 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
{ {
switch (arvif->vdev_type) { switch (arvif->vdev_type) {
case WMI_VDEV_TYPE_AP: case WMI_VDEV_TYPE_AP:
ath10k_peer_assoc_h_qos_ap(ar, arvif, sta, bss_conf, arg); if (sta->wme)
arg->peer_flags |= WMI_PEER_QOS;
if (sta->wme && sta->uapsd_queues) {
arg->peer_flags |= WMI_PEER_APSD;
arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG;
}
break; break;
case WMI_VDEV_TYPE_STA: case WMI_VDEV_TYPE_STA:
ath10k_peer_assoc_h_qos_sta(ar, arvif, sta, bss_conf, arg); if (bss_conf->qos)
arg->peer_flags |= WMI_PEER_QOS;
break; break;
default: default:
break; break;
...@@ -1293,6 +1366,33 @@ static int ath10k_peer_assoc_prepare(struct ath10k *ar, ...@@ -1293,6 +1366,33 @@ static int ath10k_peer_assoc_prepare(struct ath10k *ar,
return 0; return 0;
} }
static const u32 ath10k_smps_map[] = {
[WLAN_HT_CAP_SM_PS_STATIC] = WMI_PEER_SMPS_STATIC,
[WLAN_HT_CAP_SM_PS_DYNAMIC] = WMI_PEER_SMPS_DYNAMIC,
[WLAN_HT_CAP_SM_PS_INVALID] = WMI_PEER_SMPS_PS_NONE,
[WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE,
};
static int ath10k_setup_peer_smps(struct ath10k *ar, struct ath10k_vif *arvif,
const u8 *addr,
const struct ieee80211_sta_ht_cap *ht_cap)
{
int smps;
if (!ht_cap->ht_supported)
return 0;
smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS;
smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT;
if (smps >= ARRAY_SIZE(ath10k_smps_map))
return -EINVAL;
return ath10k_wmi_peer_set_param(ar, arvif->vdev_id, addr,
WMI_PEER_SMPS_STATE,
ath10k_smps_map[smps]);
}
/* can be called only in mac80211 callbacks due to `key_count` usage */ /* can be called only in mac80211 callbacks due to `key_count` usage */
static void ath10k_bss_assoc(struct ieee80211_hw *hw, static void ath10k_bss_assoc(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
...@@ -1300,6 +1400,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ...@@ -1300,6 +1400,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
{ {
struct ath10k *ar = hw->priv; struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
struct ieee80211_sta_ht_cap ht_cap;
struct wmi_peer_assoc_complete_arg peer_arg; struct wmi_peer_assoc_complete_arg peer_arg;
struct ieee80211_sta *ap_sta; struct ieee80211_sta *ap_sta;
int ret; int ret;
...@@ -1316,6 +1417,10 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ...@@ -1316,6 +1417,10 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
return; return;
} }
/* 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;
ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta, ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta,
bss_conf, &peer_arg); bss_conf, &peer_arg);
if (ret) { if (ret) {
...@@ -1334,15 +1439,27 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ...@@ -1334,15 +1439,27 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
return; return;
} }
ret = ath10k_setup_peer_smps(ar, arvif, bss_conf->bssid, &ht_cap);
if (ret) {
ath10k_warn("failed to setup peer SMPS: %d\n", ret);
return;
}
ath10k_dbg(ATH10K_DBG_MAC, ath10k_dbg(ATH10K_DBG_MAC,
"mac vdev %d up (associated) bssid %pM aid %d\n", "mac vdev %d up (associated) bssid %pM aid %d\n",
arvif->vdev_id, bss_conf->bssid, bss_conf->aid); arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, bss_conf->aid, arvif->aid = bss_conf->aid;
bss_conf->bssid); memcpy(arvif->bssid, bss_conf->bssid, ETH_ALEN);
if (ret)
ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid);
if (ret) {
ath10k_warn("VDEV: %d up failed: ret %d\n", ath10k_warn("VDEV: %d up failed: ret %d\n",
arvif->vdev_id, ret); arvif->vdev_id, ret);
return;
}
arvif->is_up = true;
} }
/* /*
...@@ -1382,6 +1499,9 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw, ...@@ -1382,6 +1499,9 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
arvif->def_wep_key_idx = 0; arvif->def_wep_key_idx = 0;
arvif->is_started = false;
arvif->is_up = false;
} }
static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
...@@ -1406,12 +1526,25 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, ...@@ -1406,12 +1526,25 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
return ret; return ret;
} }
ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap);
if (ret) {
ath10k_warn("failed to setup peer SMPS: %d\n", ret);
return ret;
}
ret = ath10k_install_peer_wep_keys(arvif, sta->addr); ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
if (ret) { if (ret) {
ath10k_warn("could not install peer wep keys (%d)\n", ret); ath10k_warn("could not install peer wep keys (%d)\n", ret);
return ret; return ret;
} }
ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta);
if (ret) {
ath10k_warn("could not set qos params for STA %pM, %d\n",
sta->addr, ret);
return ret;
}
return ret; return ret;
} }
...@@ -1547,9 +1680,9 @@ static void ath10k_regd_update(struct ath10k *ar) ...@@ -1547,9 +1680,9 @@ static void ath10k_regd_update(struct ath10k *ar)
/* Target allows setting up per-band regdomain but ath_common provides /* Target allows setting up per-band regdomain but ath_common provides
* a combined one only */ * a combined one only */
ret = ath10k_wmi_pdev_set_regdomain(ar, ret = ath10k_wmi_pdev_set_regdomain(ar,
regpair->regDmnEnum, regpair->reg_domain,
regpair->regDmnEnum, /* 2ghz */ regpair->reg_domain, /* 2ghz */
regpair->regDmnEnum, /* 5ghz */ regpair->reg_domain, /* 5ghz */
regpair->reg_2ghz_ctl, regpair->reg_2ghz_ctl,
regpair->reg_5ghz_ctl); regpair->reg_5ghz_ctl);
if (ret) if (ret)
...@@ -2100,11 +2233,29 @@ static int ath10k_start(struct ieee80211_hw *hw) ...@@ -2100,11 +2233,29 @@ static int ath10k_start(struct ieee80211_hw *hw)
ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n", ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n",
ret); ret);
/*
* By default FW set ARP frames ac to voice (6). In that case ARP
* exchange is not working properly for UAPSD enabled AP. ARP requests
* which arrives with access category 0 are processed by network stack
* and send back with access category 0, but FW changes access category
* to 6. Set ARP frames access category to best effort (0) solves
* this problem.
*/
ret = ath10k_wmi_pdev_set_param(ar,
ar->wmi.pdev_param->arp_ac_override, 0);
if (ret) {
ath10k_warn("could not set arp ac override parameter: %d\n",
ret);
goto exit;
}
ath10k_regd_update(ar); ath10k_regd_update(ar);
ret = 0;
exit: exit:
mutex_unlock(&ar->conf_mutex); mutex_unlock(&ar->conf_mutex);
return 0; return ret;
} }
static void ath10k_stop(struct ieee80211_hw *hw) static void ath10k_stop(struct ieee80211_hw *hw)
...@@ -2145,6 +2296,98 @@ static int ath10k_config_ps(struct ath10k *ar) ...@@ -2145,6 +2296,98 @@ static int ath10k_config_ps(struct ath10k *ar)
return ret; return ret;
} }
static const char *chandef_get_width(enum nl80211_chan_width width)
{
switch (width) {
case NL80211_CHAN_WIDTH_20_NOHT:
return "20 (noht)";
case NL80211_CHAN_WIDTH_20:
return "20";
case NL80211_CHAN_WIDTH_40:
return "40";
case NL80211_CHAN_WIDTH_80:
return "80";
case NL80211_CHAN_WIDTH_80P80:
return "80+80";
case NL80211_CHAN_WIDTH_160:
return "160";
case NL80211_CHAN_WIDTH_5:
return "5";
case NL80211_CHAN_WIDTH_10:
return "10";
}
return "?";
}
static void ath10k_config_chan(struct ath10k *ar)
{
struct ath10k_vif *arvif;
bool monitor_was_enabled;
int ret;
lockdep_assert_held(&ar->conf_mutex);
ath10k_dbg(ATH10K_DBG_MAC,
"mac config channel to %dMHz (cf1 %dMHz cf2 %dMHz width %s)\n",
ar->chandef.chan->center_freq,
ar->chandef.center_freq1,
ar->chandef.center_freq2,
chandef_get_width(ar->chandef.width));
/* First stop monitor interface. Some FW versions crash if there's a
* lone monitor interface. */
monitor_was_enabled = ar->monitor_enabled;
if (ar->monitor_enabled)
ath10k_monitor_stop(ar);
list_for_each_entry(arvif, &ar->arvifs, list) {
if (!arvif->is_started)
continue;
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
continue;
ret = ath10k_vdev_stop(arvif);
if (ret) {
ath10k_warn("could not stop vdev %d (%d)\n",
arvif->vdev_id, ret);
continue;
}
}
/* all vdevs are now stopped - now attempt to restart them */
list_for_each_entry(arvif, &ar->arvifs, list) {
if (!arvif->is_started)
continue;
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
continue;
ret = ath10k_vdev_start(arvif);
if (ret) {
ath10k_warn("could not start vdev %d (%d)\n",
arvif->vdev_id, ret);
continue;
}
if (!arvif->is_up)
continue;
ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
arvif->bssid);
if (ret) {
ath10k_warn("could not bring vdev up %d (%d)\n",
arvif->vdev_id, ret);
continue;
}
}
if (monitor_was_enabled)
ath10k_monitor_start(ar, ar->monitor_vdev_id);
}
static int ath10k_config(struct ieee80211_hw *hw, u32 changed) static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
{ {
struct ath10k *ar = hw->priv; struct ath10k *ar = hw->priv;
...@@ -2165,6 +2408,11 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) ...@@ -2165,6 +2408,11 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
spin_unlock_bh(&ar->data_lock); spin_unlock_bh(&ar->data_lock);
ath10k_config_radar_detection(ar); ath10k_config_radar_detection(ar);
if (!cfg80211_chandef_identical(&ar->chandef, &conf->chandef)) {
ar->chandef = conf->chandef;
ath10k_config_chan(ar);
}
} }
if (changed & IEEE80211_CONF_CHANGE_POWER) { if (changed & IEEE80211_CONF_CHANGE_POWER) {
...@@ -2214,7 +2462,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ...@@ -2214,7 +2462,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
enum wmi_sta_powersave_param param; enum wmi_sta_powersave_param param;
int ret = 0; int ret = 0;
u32 value, param_id; u32 value;
int bit; int bit;
u32 vdev_param; u32 vdev_param;
...@@ -2307,12 +2555,12 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ...@@ -2307,12 +2555,12 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
goto err_vdev_delete; goto err_vdev_delete;
} }
param_id = ar->wmi.pdev_param->sta_kickout_th; ret = ath10k_mac_set_kickout(arvif);
if (ret) {
/* Disable STA KICKOUT functionality in FW */ ath10k_warn("Failed to set kickout parameters: %d\n",
ret = ath10k_wmi_pdev_set_param(ar, param_id, 0); ret);
if (ret) goto err_peer_delete;
ath10k_warn("Failed to disable STA KICKOUT\n"); }
} }
if (arvif->vdev_type == WMI_VDEV_TYPE_STA) { if (arvif->vdev_type == WMI_VDEV_TYPE_STA) {
...@@ -2559,15 +2807,20 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ...@@ -2559,15 +2807,20 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
* this is never erased as we it for crypto key * this is never erased as we it for crypto key
* clearing; this is FW requirement * clearing; this is FW requirement
*/ */
memcpy(arvif->u.sta.bssid, info->bssid, memcpy(arvif->bssid, info->bssid, ETH_ALEN);
ETH_ALEN);
ath10k_dbg(ATH10K_DBG_MAC, ath10k_dbg(ATH10K_DBG_MAC,
"mac vdev %d start %pM\n", "mac vdev %d start %pM\n",
arvif->vdev_id, info->bssid); arvif->vdev_id, info->bssid);
/* FIXME: check return value */
ret = ath10k_vdev_start(arvif); ret = ath10k_vdev_start(arvif);
if (ret) {
ath10k_warn("failed to start vdev: %d\n",
ret);
goto exit;
}
arvif->is_started = true;
} }
/* /*
...@@ -2576,7 +2829,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ...@@ -2576,7 +2829,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
* IBSS in order to remove BSSID peer. * IBSS in order to remove BSSID peer.
*/ */
if (vif->type == NL80211_IFTYPE_ADHOC) if (vif->type == NL80211_IFTYPE_ADHOC)
memcpy(arvif->u.ibss.bssid, info->bssid, memcpy(arvif->bssid, info->bssid,
ETH_ALEN); ETH_ALEN);
} }
} }
...@@ -2645,6 +2898,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ...@@ -2645,6 +2898,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
ath10k_bss_assoc(hw, vif, info); ath10k_bss_assoc(hw, vif, info);
} }
exit:
mutex_unlock(&ar->conf_mutex); mutex_unlock(&ar->conf_mutex);
} }
...@@ -2850,6 +3104,69 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ...@@ -2850,6 +3104,69 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return ret; return ret;
} }
static void ath10k_sta_rc_update_wk(struct work_struct *wk)
{
struct ath10k *ar;
struct ath10k_vif *arvif;
struct ath10k_sta *arsta;
struct ieee80211_sta *sta;
u32 changed, bw, nss, smps;
int err;
arsta = container_of(wk, struct ath10k_sta, update_wk);
sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv);
arvif = arsta->arvif;
ar = arvif->ar;
spin_lock_bh(&ar->data_lock);
changed = arsta->changed;
arsta->changed = 0;
bw = arsta->bw;
nss = arsta->nss;
smps = arsta->smps;
spin_unlock_bh(&ar->data_lock);
mutex_lock(&ar->conf_mutex);
if (changed & IEEE80211_RC_BW_CHANGED) {
ath10k_dbg(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",
sta->addr, bw, err);
}
if (changed & IEEE80211_RC_NSS_CHANGED) {
ath10k_dbg(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",
sta->addr, nss, err);
}
if (changed & IEEE80211_RC_SMPS_CHANGED) {
ath10k_dbg(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",
sta->addr, smps, err);
}
mutex_unlock(&ar->conf_mutex);
}
static int ath10k_sta_state(struct ieee80211_hw *hw, static int ath10k_sta_state(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
...@@ -2858,9 +3175,15 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ...@@ -2858,9 +3175,15 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
{ {
struct ath10k *ar = hw->priv; struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
int max_num_peers; int max_num_peers;
int ret = 0; int ret = 0;
/* cancel must be done outside the mutex to avoid deadlock */
if ((old_state == IEEE80211_STA_NONE &&
new_state == IEEE80211_STA_NOTEXIST))
cancel_work_sync(&arsta->update_wk);
mutex_lock(&ar->conf_mutex); mutex_lock(&ar->conf_mutex);
if (old_state == IEEE80211_STA_NOTEXIST && if (old_state == IEEE80211_STA_NOTEXIST &&
...@@ -2885,6 +3208,10 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ...@@ -2885,6 +3208,10 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
"mac vdev %d peer create %pM (new sta) num_peers %d\n", "mac vdev %d peer create %pM (new sta) num_peers %d\n",
arvif->vdev_id, sta->addr, ar->num_peers); arvif->vdev_id, sta->addr, ar->num_peers);
memset(arsta, 0, sizeof(*arsta));
arsta->arvif = arvif;
INIT_WORK(&arsta->update_wk, ath10k_sta_rc_update_wk);
ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr); ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
if (ret) if (ret)
ath10k_warn("Failed to add peer %pM for vdev %d when adding a new sta: %i\n", ath10k_warn("Failed to add peer %pM for vdev %d when adding a new sta: %i\n",
...@@ -3234,23 +3561,14 @@ static int ath10k_suspend(struct ieee80211_hw *hw, ...@@ -3234,23 +3561,14 @@ static int ath10k_suspend(struct ieee80211_hw *hw,
struct ath10k *ar = hw->priv; struct ath10k *ar = hw->priv;
int ret; int ret;
ar->is_target_paused = false; mutex_lock(&ar->conf_mutex);
ret = ath10k_wmi_pdev_suspend_target(ar); ret = ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND);
if (ret) { if (ret) {
ath10k_warn("could not suspend target (%d)\n", ret); if (ret == -ETIMEDOUT)
return 1; goto resume;
} ret = 1;
goto exit;
ret = wait_event_interruptible_timeout(ar->event_queue,
ar->is_target_paused == true,
1 * HZ);
if (ret < 0) {
ath10k_warn("suspend interrupted (%d)\n", ret);
goto resume;
} else if (ret == 0) {
ath10k_warn("suspend timed out - target pause event never came\n");
goto resume;
} }
ret = ath10k_hif_suspend(ar); ret = ath10k_hif_suspend(ar);
...@@ -3259,12 +3577,17 @@ static int ath10k_suspend(struct ieee80211_hw *hw, ...@@ -3259,12 +3577,17 @@ static int ath10k_suspend(struct ieee80211_hw *hw,
goto resume; goto resume;
} }
return 0; ret = 0;
goto exit;
resume: resume:
ret = ath10k_wmi_pdev_resume_target(ar); ret = ath10k_wmi_pdev_resume_target(ar);
if (ret) if (ret)
ath10k_warn("could not resume target (%d)\n", ret); ath10k_warn("could not resume target (%d)\n", ret);
return 1;
ret = 1;
exit:
mutex_unlock(&ar->conf_mutex);
return ret;
} }
static int ath10k_resume(struct ieee80211_hw *hw) static int ath10k_resume(struct ieee80211_hw *hw)
...@@ -3272,19 +3595,26 @@ static int ath10k_resume(struct ieee80211_hw *hw) ...@@ -3272,19 +3595,26 @@ static int ath10k_resume(struct ieee80211_hw *hw)
struct ath10k *ar = hw->priv; struct ath10k *ar = hw->priv;
int ret; int ret;
mutex_lock(&ar->conf_mutex);
ret = ath10k_hif_resume(ar); ret = ath10k_hif_resume(ar);
if (ret) { if (ret) {
ath10k_warn("could not resume hif (%d)\n", ret); ath10k_warn("could not resume hif (%d)\n", ret);
return 1; ret = 1;
goto exit;
} }
ret = ath10k_wmi_pdev_resume_target(ar); ret = ath10k_wmi_pdev_resume_target(ar);
if (ret) { if (ret) {
ath10k_warn("could not resume target (%d)\n", ret); ath10k_warn("could not resume target (%d)\n", ret);
return 1; ret = 1;
goto exit;
} }
return 0; ret = 0;
exit:
mutex_unlock(&ar->conf_mutex);
return ret;
} }
#endif #endif
...@@ -3640,6 +3970,96 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw, ...@@ -3640,6 +3970,96 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw,
return ath10k_set_fixed_rate_param(arvif, fixed_rate, fixed_nss); return ath10k_set_fixed_rate_param(arvif, fixed_rate, fixed_nss);
} }
static void ath10k_channel_switch_beacon(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_chan_def *chandef)
{
/* there's no need to do anything here. vif->csa_active is enough */
return;
}
static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
u32 changed)
{
struct ath10k *ar = hw->priv;
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
u32 bw, smps;
spin_lock_bh(&ar->data_lock);
ath10k_dbg(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);
if (changed & IEEE80211_RC_BW_CHANGED) {
bw = WMI_PEER_CHWIDTH_20MHZ;
switch (sta->bandwidth) {
case IEEE80211_STA_RX_BW_20:
bw = WMI_PEER_CHWIDTH_20MHZ;
break;
case IEEE80211_STA_RX_BW_40:
bw = WMI_PEER_CHWIDTH_40MHZ;
break;
case IEEE80211_STA_RX_BW_80:
bw = WMI_PEER_CHWIDTH_80MHZ;
break;
case IEEE80211_STA_RX_BW_160:
ath10k_warn("mac sta rc update for %pM: invalid bw %d\n",
sta->addr, sta->bandwidth);
bw = WMI_PEER_CHWIDTH_20MHZ;
break;
}
arsta->bw = bw;
}
if (changed & IEEE80211_RC_NSS_CHANGED)
arsta->nss = sta->rx_nss;
if (changed & IEEE80211_RC_SMPS_CHANGED) {
smps = WMI_PEER_SMPS_PS_NONE;
switch (sta->smps_mode) {
case IEEE80211_SMPS_AUTOMATIC:
case IEEE80211_SMPS_OFF:
smps = WMI_PEER_SMPS_PS_NONE;
break;
case IEEE80211_SMPS_STATIC:
smps = WMI_PEER_SMPS_STATIC;
break;
case IEEE80211_SMPS_DYNAMIC:
smps = WMI_PEER_SMPS_DYNAMIC;
break;
case IEEE80211_SMPS_NUM_MODES:
ath10k_warn("mac sta rc update for %pM: invalid smps: %d\n",
sta->addr, sta->smps_mode);
smps = WMI_PEER_SMPS_PS_NONE;
break;
}
arsta->smps = smps;
}
if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
/* FIXME: Not implemented. Probably the only way to do it would
* be to re-assoc the peer. */
changed &= ~IEEE80211_RC_SUPP_RATES_CHANGED;
ath10k_dbg(ATH10K_DBG_MAC,
"mac sta rc update for %pM: changing supported rates not implemented\n",
sta->addr);
}
arsta->changed |= changed;
spin_unlock_bh(&ar->data_lock);
ieee80211_queue_work(hw, &arsta->update_wk);
}
static const struct ieee80211_ops ath10k_ops = { static const struct ieee80211_ops ath10k_ops = {
.tx = ath10k_tx, .tx = ath10k_tx,
.start = ath10k_start, .start = ath10k_start,
...@@ -3663,6 +4083,8 @@ static const struct ieee80211_ops ath10k_ops = { ...@@ -3663,6 +4083,8 @@ static const struct ieee80211_ops ath10k_ops = {
.restart_complete = ath10k_restart_complete, .restart_complete = ath10k_restart_complete,
.get_survey = ath10k_get_survey, .get_survey = ath10k_get_survey,
.set_bitrate_mask = ath10k_set_bitrate_mask, .set_bitrate_mask = ath10k_set_bitrate_mask,
.channel_switch_beacon = ath10k_channel_switch_beacon,
.sta_rc_update = ath10k_sta_rc_update,
#ifdef CONFIG_PM #ifdef CONFIG_PM
.suspend = ath10k_suspend, .suspend = ath10k_suspend,
.resume = ath10k_resume, .resume = ath10k_resume,
...@@ -4038,10 +4460,12 @@ int ath10k_mac_register(struct ath10k *ar) ...@@ -4038,10 +4460,12 @@ int ath10k_mac_register(struct ath10k *ar)
ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN; ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN;
ar->hw->vif_data_size = sizeof(struct ath10k_vif); ar->hw->vif_data_size = sizeof(struct ath10k_vif);
ar->hw->sta_data_size = sizeof(struct ath10k_sta);
ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL; ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL;
ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; 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->max_remain_on_channel_duration = 5000;
ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
......
...@@ -64,7 +64,8 @@ static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info, ...@@ -64,7 +64,8 @@ static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
int num); int num);
static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info); static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info);
static void ath10k_pci_stop_ce(struct ath10k *ar); static void ath10k_pci_stop_ce(struct ath10k *ar);
static int ath10k_pci_device_reset(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); static int ath10k_pci_wait_for_target_init(struct ath10k *ar);
static int ath10k_pci_init_irq(struct ath10k *ar); static int ath10k_pci_init_irq(struct ath10k *ar);
static int ath10k_pci_deinit_irq(struct ath10k *ar); static int ath10k_pci_deinit_irq(struct ath10k *ar);
...@@ -833,9 +834,7 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar) ...@@ -833,9 +834,7 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar)
ath10k_err("firmware crashed!\n"); ath10k_err("firmware crashed!\n");
ath10k_err("hardware name %s version 0x%x\n", ath10k_err("hardware name %s version 0x%x\n",
ar->hw_params.name, ar->target_version); ar->hw_params.name, ar->target_version);
ath10k_err("firmware version: %u.%u.%u.%u\n", ar->fw_version_major, ath10k_err("firmware version: %s\n", ar->hw->wiphy->fw_version);
ar->fw_version_minor, ar->fw_version_release,
ar->fw_version_build);
host_addr = host_interest_item_address(HI_ITEM(hi_failure_state)); host_addr = host_interest_item_address(HI_ITEM(hi_failure_state));
ret = ath10k_pci_diag_read_mem(ar, host_addr, ret = ath10k_pci_diag_read_mem(ar, host_addr,
...@@ -1502,7 +1501,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) ...@@ -1502,7 +1501,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
* configuration during init. If ringbuffers are freed and the device * configuration during init. If ringbuffers are freed and the device
* were to access them this could lead to memory corruption on the * were to access them this could lead to memory corruption on the
* host. */ * host. */
ath10k_pci_device_reset(ar); ath10k_pci_warm_reset(ar);
ar_pci->started = 0; ar_pci->started = 0;
} }
...@@ -1993,7 +1992,94 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar) ...@@ -1993,7 +1992,94 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)
ath10k_pci_sleep(ar); ath10k_pci_sleep(ar);
} }
static int ath10k_pci_hif_power_up(struct ath10k *ar) static int ath10k_pci_warm_reset(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
int ret = 0;
u32 val;
ath10k_dbg(ATH10K_DBG_BOOT, "boot performing warm chip reset\n");
ret = ath10k_do_pci_wake(ar);
if (ret) {
ath10k_err("failed to wake up target: %d\n", ret);
return ret;
}
/* 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);
/* disable pending irqs */
ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
PCIE_INTR_ENABLE_ADDRESS, 0);
ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
PCIE_INTR_CLR_ADDRESS, ~0);
msleep(100);
/* clear fw indicator */
ath10k_pci_write32(ar, ar_pci->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);
/* 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);
/* 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);
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);
msleep(100);
ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset complete\n");
ath10k_do_pci_sleep(ar);
return ret;
}
static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset)
{ {
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
const char *irq_mode; const char *irq_mode;
...@@ -2009,7 +2095,11 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) ...@@ -2009,7 +2095,11 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
* is in an unexpected state. We try to catch that here in order to * is in an unexpected state. We try to catch that here in order to
* reset the Target and retry the probe. * reset the Target and retry the probe.
*/ */
ret = ath10k_pci_device_reset(ar); if (cold_reset)
ret = ath10k_pci_cold_reset(ar);
else
ret = ath10k_pci_warm_reset(ar);
if (ret) { if (ret) {
ath10k_err("failed to reset target: %d\n", ret); ath10k_err("failed to reset target: %d\n", ret);
goto err; goto err;
...@@ -2079,7 +2169,7 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) ...@@ -2079,7 +2169,7 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
ath10k_pci_deinit_irq(ar); ath10k_pci_deinit_irq(ar);
err_ce: err_ce:
ath10k_pci_ce_deinit(ar); ath10k_pci_ce_deinit(ar);
ath10k_pci_device_reset(ar); ath10k_pci_warm_reset(ar);
err_ps: err_ps:
if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
ath10k_do_pci_sleep(ar); ath10k_do_pci_sleep(ar);
...@@ -2087,6 +2177,34 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) ...@@ -2087,6 +2177,34 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
return ret; return ret;
} }
static int ath10k_pci_hif_power_up(struct ath10k *ar)
{
int ret;
/*
* 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), trying cold reset\n",
ret);
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;
}
static void ath10k_pci_hif_power_down(struct ath10k *ar) static void ath10k_pci_hif_power_down(struct ath10k *ar)
{ {
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
...@@ -2094,7 +2212,7 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar) ...@@ -2094,7 +2212,7 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar)
ath10k_pci_free_early_irq(ar); ath10k_pci_free_early_irq(ar);
ath10k_pci_kill_tasklet(ar); ath10k_pci_kill_tasklet(ar);
ath10k_pci_deinit_irq(ar); ath10k_pci_deinit_irq(ar);
ath10k_pci_device_reset(ar); ath10k_pci_warm_reset(ar);
ath10k_pci_ce_deinit(ar); ath10k_pci_ce_deinit(ar);
if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
...@@ -2411,11 +2529,10 @@ static int ath10k_pci_init_irq(struct ath10k *ar) ...@@ -2411,11 +2529,10 @@ static int ath10k_pci_init_irq(struct ath10k *ar)
/* Try MSI-X */ /* Try MSI-X */
if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO && msix_supported) { if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO && msix_supported) {
ar_pci->num_msi_intrs = MSI_NUM_REQUEST; ar_pci->num_msi_intrs = MSI_NUM_REQUEST;
ret = pci_enable_msi_block(ar_pci->pdev, ar_pci->num_msi_intrs); ret = pci_enable_msi_range(ar_pci->pdev, ar_pci->num_msi_intrs,
if (ret == 0) ar_pci->num_msi_intrs);
return 0;
if (ret > 0) if (ret > 0)
pci_disable_msi(ar_pci->pdev); return 0;
/* fall-through */ /* fall-through */
} }
...@@ -2482,6 +2599,8 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar) ...@@ -2482,6 +2599,8 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar)
case MSI_NUM_REQUEST: case MSI_NUM_REQUEST:
pci_disable_msi(ar_pci->pdev); pci_disable_msi(ar_pci->pdev);
return 0; return 0;
default:
pci_disable_msi(ar_pci->pdev);
} }
ath10k_warn("unknown irq configuration upon deinit\n"); ath10k_warn("unknown irq configuration upon deinit\n");
...@@ -2523,7 +2642,7 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) ...@@ -2523,7 +2642,7 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
return ret; return ret;
} }
static int ath10k_pci_device_reset(struct ath10k *ar) static int ath10k_pci_cold_reset(struct ath10k *ar)
{ {
int i, ret; int i, ret;
u32 val; u32 val;
......
...@@ -259,7 +259,7 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info) ...@@ -259,7 +259,7 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info)
status->freq = ch->center_freq; status->freq = ch->center_freq;
ath10k_dbg(ATH10K_DBG_DATA, 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\n", "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 %i\n",
info->skb, info->skb,
info->skb->len, info->skb->len,
status->flag == 0 ? "legacy" : "", status->flag == 0 ? "legacy" : "",
...@@ -271,7 +271,7 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info) ...@@ -271,7 +271,7 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info)
status->rate_idx, status->rate_idx,
status->vht_nss, status->vht_nss,
status->freq, status->freq,
status->band); status->band, status->flag, info->fcs_err);
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ", ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ",
info->skb->data, info->skb->len); info->skb->data, info->skb->len);
......
...@@ -213,7 +213,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = { ...@@ -213,7 +213,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = {
.p2p_go_set_beacon_ie = WMI_10X_P2P_GO_SET_BEACON_IE, .p2p_go_set_beacon_ie = WMI_10X_P2P_GO_SET_BEACON_IE,
.p2p_go_set_probe_resp_ie = WMI_10X_P2P_GO_SET_PROBE_RESP_IE, .p2p_go_set_probe_resp_ie = WMI_10X_P2P_GO_SET_PROBE_RESP_IE,
.p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED, .p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED,
.ap_ps_peer_param_cmdid = WMI_CMD_UNSUPPORTED, .ap_ps_peer_param_cmdid = WMI_10X_AP_PS_PEER_PARAM_CMDID,
.ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED, .ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED,
.peer_rate_retry_sched_cmdid = WMI_10X_PEER_RATE_RETRY_SCHED_CMDID, .peer_rate_retry_sched_cmdid = WMI_10X_PEER_RATE_RETRY_SCHED_CMDID,
.wlan_profile_trigger_cmdid = WMI_10X_WLAN_PROFILE_TRIGGER_CMDID, .wlan_profile_trigger_cmdid = WMI_10X_WLAN_PROFILE_TRIGGER_CMDID,
...@@ -420,7 +420,6 @@ static struct wmi_pdev_param_map wmi_pdev_param_map = { ...@@ -420,7 +420,6 @@ static struct wmi_pdev_param_map wmi_pdev_param_map = {
.bcnflt_stats_update_period = WMI_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, .bcnflt_stats_update_period = WMI_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD,
.pmf_qos = WMI_PDEV_PARAM_PMF_QOS, .pmf_qos = WMI_PDEV_PARAM_PMF_QOS,
.arp_ac_override = WMI_PDEV_PARAM_ARP_AC_OVERRIDE, .arp_ac_override = WMI_PDEV_PARAM_ARP_AC_OVERRIDE,
.arpdhcp_ac_override = WMI_PDEV_PARAM_UNSUPPORTED,
.dcs = WMI_PDEV_PARAM_DCS, .dcs = WMI_PDEV_PARAM_DCS,
.ani_enable = WMI_PDEV_PARAM_ANI_ENABLE, .ani_enable = WMI_PDEV_PARAM_ANI_ENABLE,
.ani_poll_period = WMI_PDEV_PARAM_ANI_POLL_PERIOD, .ani_poll_period = WMI_PDEV_PARAM_ANI_POLL_PERIOD,
...@@ -472,8 +471,7 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { ...@@ -472,8 +471,7 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = {
.bcnflt_stats_update_period = .bcnflt_stats_update_period =
WMI_10X_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, WMI_10X_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD,
.pmf_qos = WMI_10X_PDEV_PARAM_PMF_QOS, .pmf_qos = WMI_10X_PDEV_PARAM_PMF_QOS,
.arp_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, .arp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE,
.arpdhcp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE,
.dcs = WMI_10X_PDEV_PARAM_DCS, .dcs = WMI_10X_PDEV_PARAM_DCS,
.ani_enable = WMI_10X_PDEV_PARAM_ANI_ENABLE, .ani_enable = WMI_10X_PDEV_PARAM_ANI_ENABLE,
.ani_poll_period = WMI_10X_PDEV_PARAM_ANI_POLL_PERIOD, .ani_poll_period = WMI_10X_PDEV_PARAM_ANI_POLL_PERIOD,
...@@ -561,7 +559,6 @@ static int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb, ...@@ -561,7 +559,6 @@ static int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb,
static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif)
{ {
struct wmi_bcn_tx_arg arg = {0};
int ret; int ret;
lockdep_assert_held(&arvif->ar->data_lock); lockdep_assert_held(&arvif->ar->data_lock);
...@@ -569,18 +566,16 @@ static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) ...@@ -569,18 +566,16 @@ static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif)
if (arvif->beacon == NULL) if (arvif->beacon == NULL)
return; return;
arg.vdev_id = arvif->vdev_id; if (arvif->beacon_sent)
arg.tx_rate = 0; return;
arg.tx_power = 0;
arg.bcn = arvif->beacon->data;
arg.bcn_len = arvif->beacon->len;
ret = ath10k_wmi_beacon_send_nowait(arvif->ar, &arg); ret = ath10k_wmi_beacon_send_ref_nowait(arvif);
if (ret) if (ret)
return; return;
dev_kfree_skb_any(arvif->beacon); /* We need to retain the arvif->beacon reference for DMA unmapping and
arvif->beacon = NULL; * freeing the skbuff later. */
arvif->beacon_sent = true;
} }
static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac, static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac,
...@@ -1116,7 +1111,27 @@ static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, ...@@ -1116,7 +1111,27 @@ static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar,
static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar,
struct sk_buff *skb) struct sk_buff *skb)
{ {
ath10k_dbg(ATH10K_DBG_WMI, "WMI_PEER_STA_KICKOUT_EVENTID\n"); struct wmi_peer_sta_kickout_event *ev;
struct ieee80211_sta *sta;
ev = (struct wmi_peer_sta_kickout_event *)skb->data;
ath10k_dbg(ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n",
ev->peer_macaddr.addr);
rcu_read_lock();
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;
}
ieee80211_report_low_ack(sta, 10);
exit:
rcu_read_unlock();
} }
/* /*
...@@ -1217,6 +1232,13 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, ...@@ -1217,6 +1232,13 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
tim->bitmap_ctrl = !!__le32_to_cpu(bcn_info->tim_info.tim_mcast); tim->bitmap_ctrl = !!__le32_to_cpu(bcn_info->tim_info.tim_mcast);
memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len); 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(bcn_info->tim_info.tim_mcast) == 1)
ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true;
}
ath10k_dbg(ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n", ath10k_dbg(ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n",
tim->dtim_count, tim->dtim_period, tim->dtim_count, tim->dtim_period,
tim->bitmap_ctrl, pvm_len); tim->bitmap_ctrl, pvm_len);
...@@ -1385,6 +1407,17 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) ...@@ -1385,6 +1407,17 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
continue; continue;
} }
/* There are no completions for beacons so wait for next SWBA
* before telling mac80211 to decrement CSA counter
*
* Once CSA counter is completed stop sending beacons until
* actual channel switch is done */
if (arvif->vif->csa_active &&
ieee80211_csa_is_complete(arvif->vif)) {
ieee80211_csa_finish(arvif->vif);
continue;
}
bcn = ieee80211_beacon_get(ar->hw, arvif->vif); bcn = ieee80211_beacon_get(ar->hw, arvif->vif);
if (!bcn) { if (!bcn) {
ath10k_warn("could not get mac80211 beacon\n"); ath10k_warn("could not get mac80211 beacon\n");
...@@ -1396,13 +1429,20 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) ...@@ -1396,13 +1429,20 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info); ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info);
spin_lock_bh(&ar->data_lock); spin_lock_bh(&ar->data_lock);
if (arvif->beacon) { if (arvif->beacon) {
ath10k_warn("SWBA overrun on vdev %d\n", if (!arvif->beacon_sent)
arvif->vdev_id); ath10k_warn("SWBA overrun on vdev %d\n",
arvif->vdev_id);
ath10k_skb_unmap(ar->dev, arvif->beacon);
dev_kfree_skb_any(arvif->beacon); dev_kfree_skb_any(arvif->beacon);
} }
ath10k_skb_map(ar->dev, bcn);
arvif->beacon = bcn; arvif->beacon = bcn;
arvif->beacon_sent = false;
ath10k_wmi_tx_beacon_nowait(arvif); ath10k_wmi_tx_beacon_nowait(arvif);
spin_unlock_bh(&ar->data_lock); spin_unlock_bh(&ar->data_lock);
...@@ -2031,11 +2071,11 @@ static int ath10k_wmi_ready_event_rx(struct ath10k *ar, struct sk_buff *skb) ...@@ -2031,11 +2071,11 @@ static int ath10k_wmi_ready_event_rx(struct ath10k *ar, struct sk_buff *skb)
memcpy(ar->mac_addr, ev->mac_addr.addr, ETH_ALEN); memcpy(ar->mac_addr, ev->mac_addr.addr, ETH_ALEN);
ath10k_dbg(ATH10K_DBG_WMI, ath10k_dbg(ATH10K_DBG_WMI,
"wmi event ready sw_version %u abi_version %u mac_addr %pM status %d\n", "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->sw_version),
__le32_to_cpu(ev->abi_version), __le32_to_cpu(ev->abi_version),
ev->mac_addr.addr, ev->mac_addr.addr,
__le32_to_cpu(ev->status)); __le32_to_cpu(ev->status), skb->len, sizeof(*ev));
complete(&ar->wmi.unified_ready); complete(&ar->wmi.unified_ready);
return 0; return 0;
...@@ -2403,7 +2443,7 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar, ...@@ -2403,7 +2443,7 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
ar->wmi.cmd->pdev_set_channel_cmdid); ar->wmi.cmd->pdev_set_channel_cmdid);
} }
int ath10k_wmi_pdev_suspend_target(struct ath10k *ar) int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt)
{ {
struct wmi_pdev_suspend_cmd *cmd; struct wmi_pdev_suspend_cmd *cmd;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -2413,7 +2453,7 @@ int ath10k_wmi_pdev_suspend_target(struct ath10k *ar) ...@@ -2413,7 +2453,7 @@ int ath10k_wmi_pdev_suspend_target(struct ath10k *ar)
return -ENOMEM; return -ENOMEM;
cmd = (struct wmi_pdev_suspend_cmd *)skb->data; cmd = (struct wmi_pdev_suspend_cmd *)skb->data;
cmd->suspend_opt = WMI_PDEV_SUSPEND; cmd->suspend_opt = __cpu_to_le32(suspend_opt);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_suspend_cmdid); return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_suspend_cmdid);
} }
...@@ -3411,25 +3451,41 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar, ...@@ -3411,25 +3451,41 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar,
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid); return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid);
} }
int ath10k_wmi_beacon_send_nowait(struct ath10k *ar, /* This function assumes the beacon is already DMA mapped */
const struct wmi_bcn_tx_arg *arg) int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif)
{ {
struct wmi_bcn_tx_cmd *cmd; struct wmi_bcn_tx_ref_cmd *cmd;
struct sk_buff *skb; struct sk_buff *skb;
struct sk_buff *beacon = arvif->beacon;
struct ath10k *ar = arvif->ar;
struct ieee80211_hdr *hdr;
int ret; int ret;
u16 fc;
skb = ath10k_wmi_alloc_skb(sizeof(*cmd) + arg->bcn_len); skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
if (!skb) if (!skb)
return -ENOMEM; return -ENOMEM;
cmd = (struct wmi_bcn_tx_cmd *)skb->data; hdr = (struct ieee80211_hdr *)beacon->data;
cmd->hdr.vdev_id = __cpu_to_le32(arg->vdev_id); fc = le16_to_cpu(hdr->frame_control);
cmd->hdr.tx_rate = __cpu_to_le32(arg->tx_rate);
cmd->hdr.tx_power = __cpu_to_le32(arg->tx_power); cmd = (struct wmi_bcn_tx_ref_cmd *)skb->data;
cmd->hdr.bcn_len = __cpu_to_le32(arg->bcn_len); cmd->vdev_id = __cpu_to_le32(arvif->vdev_id);
memcpy(cmd->bcn, arg->bcn, arg->bcn_len); cmd->data_len = __cpu_to_le32(beacon->len);
cmd->data_ptr = __cpu_to_le32(ATH10K_SKB_CB(beacon)->paddr);
cmd->msdu_id = 0;
cmd->frame_control = __cpu_to_le32(fc);
cmd->flags = 0;
if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero)
cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO);
if (ATH10K_SKB_CB(beacon)->bcn.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);
ret = ath10k_wmi_cmd_send_nowait(ar, skb, ar->wmi.cmd->bcn_tx_cmdid);
if (ret) if (ret)
dev_kfree_skb(skb); dev_kfree_skb(skb);
......
...@@ -2277,7 +2277,6 @@ struct wmi_pdev_param_map { ...@@ -2277,7 +2277,6 @@ struct wmi_pdev_param_map {
u32 bcnflt_stats_update_period; u32 bcnflt_stats_update_period;
u32 pmf_qos; u32 pmf_qos;
u32 arp_ac_override; u32 arp_ac_override;
u32 arpdhcp_ac_override;
u32 dcs; u32 dcs;
u32 ani_enable; u32 ani_enable;
u32 ani_poll_period; u32 ani_poll_period;
...@@ -3403,6 +3402,24 @@ struct wmi_bcn_tx_arg { ...@@ -3403,6 +3402,24 @@ struct wmi_bcn_tx_arg {
const void *bcn; const void *bcn;
}; };
enum wmi_bcn_tx_ref_flags {
WMI_BCN_TX_REF_FLAG_DTIM_ZERO = 0x1,
WMI_BCN_TX_REF_FLAG_DELIVER_CAB = 0x2,
};
struct wmi_bcn_tx_ref_cmd {
__le32 vdev_id;
__le32 data_len;
/* physical address of the frame - dma pointer */
__le32 data_ptr;
/* id for host to track */
__le32 msdu_id;
/* frame ctrl to setup PPDU desc */
__le32 frame_control;
/* to control CABQ traffic: WMI_BCN_TX_REF_FLAG_ */
__le32 flags;
} __packed;
/* Beacon filter */ /* Beacon filter */
#define WMI_BCN_FILTER_ALL 0 /* Filter all beacons */ #define WMI_BCN_FILTER_ALL 0 /* Filter all beacons */
#define WMI_BCN_FILTER_NONE 1 /* Pass all beacons */ #define WMI_BCN_FILTER_NONE 1 /* Pass all beacons */
...@@ -3859,6 +3876,12 @@ enum wmi_peer_smps_state { ...@@ -3859,6 +3876,12 @@ enum wmi_peer_smps_state {
WMI_PEER_SMPS_DYNAMIC = 0x2 WMI_PEER_SMPS_DYNAMIC = 0x2
}; };
enum wmi_peer_chwidth {
WMI_PEER_CHWIDTH_20MHZ = 0,
WMI_PEER_CHWIDTH_40MHZ = 1,
WMI_PEER_CHWIDTH_80MHZ = 2,
};
enum wmi_peer_param { enum wmi_peer_param {
WMI_PEER_SMPS_STATE = 0x1, /* see %wmi_peer_smps_state */ WMI_PEER_SMPS_STATE = 0x1, /* see %wmi_peer_smps_state */
WMI_PEER_AMPDU = 0x2, WMI_PEER_AMPDU = 0x2,
...@@ -4039,6 +4062,10 @@ struct wmi_chan_info_event { ...@@ -4039,6 +4062,10 @@ struct wmi_chan_info_event {
__le32 cycle_count; __le32 cycle_count;
} __packed; } __packed;
struct wmi_peer_sta_kickout_event {
struct wmi_mac_addr peer_macaddr;
} __packed;
#define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0) #define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0)
/* FIXME: empirically extrapolated */ /* FIXME: empirically extrapolated */
...@@ -4172,7 +4199,7 @@ int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar); ...@@ -4172,7 +4199,7 @@ int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar);
int ath10k_wmi_connect_htc_service(struct ath10k *ar); int ath10k_wmi_connect_htc_service(struct ath10k *ar);
int ath10k_wmi_pdev_set_channel(struct ath10k *ar, int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
const struct wmi_channel_arg *); const struct wmi_channel_arg *);
int ath10k_wmi_pdev_suspend_target(struct ath10k *ar); 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_resume_target(struct ath10k *ar);
int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
u16 rd5g, u16 ctl2g, u16 ctl5g); u16 rd5g, u16 ctl2g, u16 ctl5g);
...@@ -4219,8 +4246,7 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac, ...@@ -4219,8 +4246,7 @@ 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); enum wmi_ap_ps_peer_param param_id, u32 value);
int ath10k_wmi_scan_chan_list(struct ath10k *ar, int ath10k_wmi_scan_chan_list(struct ath10k *ar,
const struct wmi_scan_chan_list_arg *arg); const struct wmi_scan_chan_list_arg *arg);
int ath10k_wmi_beacon_send_nowait(struct ath10k *ar, int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif);
const struct wmi_bcn_tx_arg *arg);
int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
const struct wmi_pdev_set_wmm_params_arg *arg); 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_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id);
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
/* constants */ /* constants */
#define TX_URB_COUNT 32 #define TX_URB_COUNT 32
#define RX_URB_COUNT 32 #define RX_URB_COUNT 32
#define ATH6KL_USB_RX_BUFFER_SIZE 1700 #define ATH6KL_USB_RX_BUFFER_SIZE 4096
/* tx/rx pipes for usb */ /* tx/rx pipes for usb */
enum ATH6KL_USB_PIPE_ID { enum ATH6KL_USB_PIPE_ID {
...@@ -481,8 +481,8 @@ static void ath6kl_usb_start_recv_pipes(struct ath6kl_usb *ar_usb) ...@@ -481,8 +481,8 @@ static void ath6kl_usb_start_recv_pipes(struct ath6kl_usb *ar_usb)
* ATH6KL_USB_RX_BUFFER_SIZE); * ATH6KL_USB_RX_BUFFER_SIZE);
*/ */
ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_cnt_thresh = ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_cnt_thresh = 1;
ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_alloc / 2;
ath6kl_usb_post_recv_transfers(&ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA], ath6kl_usb_post_recv_transfers(&ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA],
ATH6KL_USB_RX_BUFFER_SIZE); ATH6KL_USB_RX_BUFFER_SIZE);
} }
......
...@@ -914,7 +914,7 @@ ath6kl_get_regpair(u16 regdmn) ...@@ -914,7 +914,7 @@ ath6kl_get_regpair(u16 regdmn)
return NULL; return NULL;
for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
if (regDomainPairs[i].regDmnEnum == regdmn) if (regDomainPairs[i].reg_domain == regdmn)
return &regDomainPairs[i]; return &regDomainPairs[i];
} }
...@@ -954,7 +954,7 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len) ...@@ -954,7 +954,7 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len)
country = ath6kl_regd_find_country_by_rd((u16) reg_code); country = ath6kl_regd_find_country_by_rd((u16) reg_code);
if (regpair) if (regpair)
ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n", ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n",
regpair->regDmnEnum); regpair->reg_domain);
else else
ath6kl_warn("Regpair not found reg_code 0x%0x\n", ath6kl_warn("Regpair not found reg_code 0x%0x\n",
reg_code); reg_code);
......
...@@ -222,7 +222,7 @@ static const struct ieee80211_regdomain *ath_default_world_regdomain(void) ...@@ -222,7 +222,7 @@ static const struct ieee80211_regdomain *ath_default_world_regdomain(void)
static const struct static const struct
ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg) ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg)
{ {
switch (reg->regpair->regDmnEnum) { switch (reg->regpair->reg_domain) {
case 0x60: case 0x60:
case 0x61: case 0x61:
case 0x62: case 0x62:
...@@ -431,7 +431,7 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy, ...@@ -431,7 +431,7 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy,
enum nl80211_reg_initiator initiator, enum nl80211_reg_initiator initiator,
struct ath_regulatory *reg) struct ath_regulatory *reg)
{ {
switch (reg->regpair->regDmnEnum) { switch (reg->regpair->reg_domain) {
case 0x60: case 0x60:
case 0x63: case 0x63:
case 0x66: case 0x66:
...@@ -560,7 +560,7 @@ static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg) ...@@ -560,7 +560,7 @@ static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg)
printk(KERN_DEBUG "ath: EEPROM indicates we " printk(KERN_DEBUG "ath: EEPROM indicates we "
"should expect a direct regpair map\n"); "should expect a direct regpair map\n");
for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
if (regDomainPairs[i].regDmnEnum == rd) if (regDomainPairs[i].reg_domain == rd)
return true; return true;
} }
printk(KERN_DEBUG printk(KERN_DEBUG
...@@ -617,7 +617,7 @@ ath_get_regpair(int regdmn) ...@@ -617,7 +617,7 @@ ath_get_regpair(int regdmn)
if (regdmn == NO_ENUMRD) if (regdmn == NO_ENUMRD)
return NULL; return NULL;
for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
if (regDomainPairs[i].regDmnEnum == regdmn) if (regDomainPairs[i].reg_domain == regdmn)
return &regDomainPairs[i]; return &regDomainPairs[i];
} }
return NULL; return NULL;
...@@ -741,7 +741,7 @@ static int __ath_regd_init(struct ath_regulatory *reg) ...@@ -741,7 +741,7 @@ static int __ath_regd_init(struct ath_regulatory *reg)
printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n", printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n",
reg->alpha2[0], reg->alpha2[1]); reg->alpha2[0], reg->alpha2[1]);
printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n", printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n",
reg->regpair->regDmnEnum); reg->regpair->reg_domain);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment