diff options
author | Ingo Molnar <mingo@kernel.org> | 2014-05-07 13:15:46 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-05-07 13:15:46 +0200 |
commit | 2fe5de9ce7d57498abc14b375cad2fcf8c3ee6cc (patch) | |
tree | 9478e8cf470c1d5bdb2d89b57a7e35919ab95e72 /drivers/net/wireless/ath | |
parent | sched: Remove set_need_resched() (diff) | |
parent | sched/numa: Initialize newidle balance stats in sd_numa_init() (diff) | |
download | linux-2fe5de9ce7d57498abc14b375cad2fcf8c3ee6cc.tar.xz linux-2fe5de9ce7d57498abc14b375cad2fcf8c3ee6cc.zip |
Merge branch 'sched/urgent' into sched/core, to avoid conflicts
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'drivers/net/wireless/ath')
87 files changed, 4450 insertions, 4402 deletions
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index b59cfbe0276b..a889fd66fc63 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -56,6 +56,15 @@ enum ath_device_state { ATH_HW_INITIALIZED, }; +enum ath_op_flags { + ATH_OP_INVALID, + ATH_OP_BEACONS, + ATH_OP_ANI_RUN, + ATH_OP_PRIM_STA_VIF, + ATH_OP_HW_RESET, + ATH_OP_SCANNING, +}; + enum ath_bus_type { ATH_PCI, ATH_AHB, @@ -63,7 +72,7 @@ enum ath_bus_type { }; struct reg_dmn_pair_mapping { - u16 regDmnEnum; + u16 reg_domain; u16 reg_5ghz_ctl; u16 reg_2ghz_ctl; }; @@ -130,6 +139,7 @@ struct ath_common { struct ieee80211_hw *hw; int debug_mask; enum ath_device_state state; + unsigned long op_flags; struct ath_ani ani; @@ -161,6 +171,9 @@ struct ath_common { bool btcoex_enabled; bool disable_ani; bool bt_ant_diversity; + + int last_rssi; + struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; }; struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index d44d618b05f9..a79499c82350 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -266,12 +266,12 @@ static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar, * ath10k_ce_sendlist_send. * The caller takes responsibility for any needed locking. */ -static int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, - void *per_transfer_context, - u32 buffer, - unsigned int nbytes, - unsigned int transfer_id, - unsigned int flags) +int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, + void *per_transfer_context, + u32 buffer, + unsigned int nbytes, + unsigned int transfer_id, + unsigned int flags) { struct ath10k *ar = ce_state->ar; struct ath10k_ce_ring *src_ring = ce_state->src_ring; @@ -1067,9 +1067,9 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar, * * For the lack of a better place do the check here. */ - BUILD_BUG_ON(TARGET_NUM_MSDU_DESC > + BUILD_BUG_ON(2*TARGET_NUM_MSDU_DESC > (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); - BUILD_BUG_ON(TARGET_10X_NUM_MSDU_DESC > + BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC > (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); ret = ath10k_pci_wake(ar); diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 67dbde6a5c74..8eb7f99ed992 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -23,7 +23,7 @@ /* Maximum number of Copy Engine's supported */ #define CE_COUNT_MAX 8 -#define CE_HTT_H2T_MSG_SRC_NENTRIES 2048 +#define CE_HTT_H2T_MSG_SRC_NENTRIES 4096 /* Descriptor rings must be aligned to this boundary */ #define CE_DESC_RING_ALIGN 8 @@ -152,6 +152,13 @@ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state, unsigned int transfer_id, unsigned int flags); +int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, + void *per_transfer_context, + u32 buffer, + unsigned int nbytes, + 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); diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 3b59af3bddf4..ebc5fc2ede75 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -55,8 +55,7 @@ static void ath10k_send_suspend_complete(struct ath10k *ar) { ath10k_dbg(ATH10K_DBG_BOOT, "boot suspend complete\n"); - ar->is_target_paused = true; - wake_up(&ar->event_queue); + complete(&ar->target_suspend); } 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) if (index == ie_len) 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); + } } ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "", @@ -699,6 +702,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, 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); @@ -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); skb_queue_head_init(&ar->wmi_mgmt_tx_queue); - init_waitqueue_head(&ar->event_queue); - INIT_WORK(&ar->restart_work, ath10k_core_restart); return ar; @@ -856,10 +858,34 @@ err: } 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) { 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_htc_stop(&ar->htc); ath10k_htt_detach(&ar->htt); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index ade1781c7186..0e71979d837c 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -46,21 +46,35 @@ #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_skb_cb { dma_addr_t paddr; - bool is_mapped; - bool is_aborted; u8 vdev_id; struct { u8 tid; bool is_offchan; - - u8 frag_len; - u8 pad_len; + struct ath10k_htt_txbuf *txbuf; + u32 txbuf_paddr; } __packed htt; + + struct { + bool dtim_zero; + bool deliver_cab; + } bcn; } __packed; static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb) @@ -70,32 +84,6 @@ static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb) return (struct ath10k_skb_cb *)&IEEE80211_SKB_CB(skb)->driver_data; } -static inline int ath10k_skb_map(struct device *dev, struct sk_buff *skb) -{ - if (ATH10K_SKB_CB(skb)->is_mapped) - return -EINVAL; - - ATH10K_SKB_CB(skb)->paddr = dma_map_single(dev, skb->data, skb->len, - DMA_TO_DEVICE); - - if (unlikely(dma_mapping_error(dev, ATH10K_SKB_CB(skb)->paddr))) - return -EIO; - - ATH10K_SKB_CB(skb)->is_mapped = true; - return 0; -} - -static inline int ath10k_skb_unmap(struct device *dev, struct sk_buff *skb) -{ - if (!ATH10K_SKB_CB(skb)->is_mapped) - return -EINVAL; - - dma_unmap_single(dev, ATH10K_SKB_CB(skb)->paddr, skb->len, - DMA_TO_DEVICE); - ATH10K_SKB_CB(skb)->is_mapped = false; - return 0; -} - static inline u32 host_interest_item_address(u32 item_offset) { return QCA988X_HOST_INTEREST_ADDRESS + item_offset; @@ -211,6 +199,18 @@ struct ath10k_peer { 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) struct ath10k_vif { @@ -222,10 +222,17 @@ struct ath10k_vif { u32 beacon_interval; u32 dtim_period; struct sk_buff *beacon; + /* protected by data_lock */ + bool beacon_sent; struct ath10k *ar; struct ieee80211_vif *vif; + bool is_started; + bool is_up; + 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; @@ -235,7 +242,6 @@ struct ath10k_vif { union { struct { - u8 bssid[ETH_ALEN]; u32 uapsd; } sta; struct { @@ -249,13 +255,11 @@ struct ath10k_vif { u32 noa_len; u8 *noa_data; } ap; - struct { - u8 bssid[ETH_ALEN]; - } ibss; } u; u8 fixed_rate; u8 fixed_nss; + u8 force_sgi; }; struct ath10k_vif_iter { @@ -355,8 +359,7 @@ struct ath10k { const struct ath10k_hif_ops *ops; } hif; - wait_queue_head_t event_queue; - bool is_target_paused; + struct completion target_suspend; struct ath10k_bmi bmi; struct ath10k_wmi wmi; @@ -412,6 +415,9 @@ struct ath10k { /* valid during scan; needed for mgmt rx during scan */ struct ieee80211_channel *scan_channel; + /* current operating channel definition */ + struct cfg80211_chan_def chandef; + int free_vdev_map; int monitor_vdev_id; bool monitor_enabled; @@ -470,6 +476,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, void ath10k_core_destroy(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); int ath10k_core_register(struct ath10k *ar, u32 chip_id); void ath10k_core_unregister(struct ath10k *ar); diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 1773c36c71a0..a5824990bd2a 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -92,7 +92,7 @@ static inline void ath10k_debug_read_target_stats(struct ath10k *ar, #ifdef CONFIG_ATH10K_DEBUG __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, const char *msg, const char *prefix, const void *buf, size_t len); diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index dcdea68bcc0a..2ac7beacddca 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h @@ -21,6 +21,14 @@ #include <linux/kernel.h> #include "core.h" +struct ath10k_hif_sg_item { + u16 transfer_id; + void *transfer_context; /* NULL = tx completion callback not called */ + void *vaddr; /* for debugging mostly */ + u32 paddr; + u16 len; +}; + struct ath10k_hif_cb { int (*tx_completion)(struct ath10k *ar, struct sk_buff *wbuf, @@ -31,11 +39,9 @@ struct ath10k_hif_cb { }; struct ath10k_hif_ops { - /* Send the head of a buffer to HIF for transmission to the target. */ - int (*send_head)(struct ath10k *ar, u8 pipe_id, - unsigned int transfer_id, - unsigned int nbytes, - struct sk_buff *buf); + /* send a scatter-gather list to the target */ + int (*tx_sg)(struct ath10k *ar, u8 pipe_id, + struct ath10k_hif_sg_item *items, int n_items); /* * API to handle HIF-specific BMI message exchanges, this API is @@ -86,12 +92,11 @@ struct ath10k_hif_ops { }; -static inline int ath10k_hif_send_head(struct ath10k *ar, u8 pipe_id, - unsigned int transfer_id, - unsigned int nbytes, - struct sk_buff *buf) +static inline int ath10k_hif_tx_sg(struct ath10k *ar, u8 pipe_id, + struct ath10k_hif_sg_item *items, + int n_items) { - return ar->hif.ops->send_head(ar, pipe_id, transfer_id, nbytes, buf); + return ar->hif.ops->tx_sg(ar, pipe_id, items, n_items); } static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar, diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index edc57ab505c8..7f1bccd3597f 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -63,7 +63,9 @@ static struct sk_buff *ath10k_htc_build_tx_ctrl_skb(void *ar) static inline void ath10k_htc_restore_tx_skb(struct ath10k_htc *htc, struct sk_buff *skb) { - ath10k_skb_unmap(htc->ar->dev, skb); + struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb); + + dma_unmap_single(htc->ar->dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE); skb_pull(skb, sizeof(struct ath10k_htc_hdr)); } @@ -122,6 +124,9 @@ int ath10k_htc_send(struct ath10k_htc *htc, struct sk_buff *skb) { 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; + struct device *dev = htc->ar->dev; int credits = 0; int ret; @@ -157,19 +162,25 @@ int ath10k_htc_send(struct ath10k_htc *htc, ath10k_htc_prepare_tx_skb(ep, skb); - ret = ath10k_skb_map(htc->ar->dev, skb); + skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE); + ret = dma_mapping_error(dev, skb_cb->paddr); if (ret) goto err_credits; - ret = ath10k_hif_send_head(htc->ar, ep->ul_pipe_id, ep->eid, - skb->len, skb); + sg_item.transfer_id = ep->eid; + sg_item.transfer_context = skb; + sg_item.vaddr = skb->data; + sg_item.paddr = skb_cb->paddr; + sg_item.len = skb->len; + + ret = ath10k_hif_tx_sg(htc->ar, ep->ul_pipe_id, &sg_item, 1); if (ret) goto err_unmap; return 0; err_unmap: - ath10k_skb_unmap(htc->ar->dev, skb); + dma_unmap_single(dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE); err_credits: if (ep->tx_credit_flow_enabled) { spin_lock_bh(&htc->tx_lock); @@ -191,10 +202,8 @@ static int ath10k_htc_tx_completion_handler(struct ath10k *ar, struct ath10k_htc *htc = &ar->htc; struct ath10k_htc_ep *ep = &htc->endpoint[eid]; - if (!skb) { - ath10k_warn("invalid sk_buff completion - NULL pointer. firmware crashed?\n"); + if (WARN_ON_ONCE(!skb)) return 0; - } ath10k_htc_notify_tx_completion(ep, skb); /* the skb now belongs to the completion handler */ diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index b93ae355bc08..654867fc1ae7 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -20,6 +20,7 @@ #include <linux/bug.h> #include <linux/interrupt.h> +#include <linux/dmapool.h> #include "htc.h" #include "rx_desc.h" @@ -1181,11 +1182,20 @@ struct htt_rx_info { u32 info1; u32 info2; } rate; + + u32 tsf; bool fcs_err; bool amsdu_more; bool mic_err; }; +struct ath10k_htt_txbuf { + struct htt_data_tx_desc_frag frags[2]; + struct ath10k_htc_hdr htc_hdr; + struct htt_cmd_hdr cmd_hdr; + struct htt_data_tx_desc cmd_tx; +} __packed; + struct ath10k_htt { struct ath10k *ar; enum ath10k_htc_ep_id eid; @@ -1267,11 +1277,18 @@ struct ath10k_htt { struct sk_buff **pending_tx; unsigned long *used_msdu_ids; /* bitmap */ wait_queue_head_t empty_tx_wq; + struct dma_pool *tx_pool; /* set if host-fw communication goes haywire * used to avoid further failures */ bool rx_confused; struct tasklet_struct rx_replenish_task; + + /* This is used to group tx/rx completions separately and process them + * in batches to reduce cache stalls */ + struct tasklet_struct txrx_compl_task; + struct sk_buff_head tx_compl_q; + struct sk_buff_head rx_compl_q; }; #define RX_HTT_HDR_STATUS_LEN 64 @@ -1343,4 +1360,5 @@ int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt); 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 *); + #endif diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index fe8bd1b59f0e..cdcbe2de95f9 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -43,7 +43,7 @@ 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) { @@ -225,18 +225,16 @@ static void ath10k_htt_rx_ring_refill_retry(unsigned long arg) ath10k_htt_rx_msdu_buff_replenish(htt); } -static unsigned ath10k_htt_rx_ring_elems(struct ath10k_htt *htt) -{ - return (__le32_to_cpu(*htt->rx_ring.alloc_idx.vaddr) - - htt->rx_ring.sw_rd_idx.msdu_payld) & htt->rx_ring.size_mask; -} - void ath10k_htt_rx_detach(struct ath10k_htt *htt) { int sw_rd_idx = htt->rx_ring.sw_rd_idx.msdu_payld; 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); while (sw_rd_idx != __le32_to_cpu(*(htt->rx_ring.alloc_idx.vaddr))) { struct sk_buff *skb = @@ -270,10 +268,12 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt) int idx; struct sk_buff *msdu; - spin_lock_bh(&htt->rx_ring.lock); + lockdep_assert_held(&htt->rx_ring.lock); - if (ath10k_htt_rx_ring_elems(htt) == 0) - ath10k_warn("htt rx ring is empty!\n"); + if (htt->rx_ring.fill_cnt == 0) { + ath10k_warn("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]; @@ -283,7 +283,6 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt) htt->rx_ring.sw_rd_idx.msdu_payld = idx; htt->rx_ring.fill_cnt--; - spin_unlock_bh(&htt->rx_ring.lock); return msdu; } @@ -307,8 +306,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, struct sk_buff *msdu; struct htt_rx_desc *rx_desc; - if (ath10k_htt_rx_ring_elems(htt) == 0) - ath10k_warn("htt rx ring is empty!\n"); + lockdep_assert_held(&htt->rx_ring.lock); if (htt->rx_confused) { ath10k_warn("htt is confused. refusing rx\n"); @@ -324,7 +322,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, msdu->len + skb_tailroom(msdu), 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)); rx_desc = (struct htt_rx_desc *)msdu->data; @@ -400,6 +398,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, 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; @@ -417,8 +416,8 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, next->len + skb_tailroom(next), DMA_FROM_DEVICE); - ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx: ", - next->data, + ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, + "htt rx chained: ", next->data, next->len + skb_tailroom(next)); skb_trim(next, 0); @@ -427,13 +426,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, msdu->next = next; msdu = next; - 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) & @@ -535,6 +527,12 @@ int ath10k_htt_rx_attach(struct ath10k_htt *htt) 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); + + 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", htt->rx_ring.size, htt->rx_ring.fill_level); return 0; @@ -638,6 +636,12 @@ struct amsdu_subframe_hdr { __be16 len; } __packed; +static int ath10k_htt_rx_nwifi_hdrlen(struct ieee80211_hdr *hdr) +{ + /* nwifi header is padded to 4 bytes. this fixes 4addr rx */ + return round_up(ieee80211_hdrlen(hdr->frame_control), 4); +} + static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt, struct htt_rx_info *info) { @@ -687,7 +691,7 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt, case RX_MSDU_DECAP_NATIVE_WIFI: /* pull decapped header and copy DA */ hdr = (struct ieee80211_hdr *)skb->data; - hdr_len = ieee80211_hdrlen(hdr->frame_control); + hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr); memcpy(addr, ieee80211_get_DA(hdr), ETH_ALEN); skb_pull(skb, hdr_len); @@ -751,7 +755,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. */ 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); skb->next = NULL; } @@ -774,7 +778,7 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info) case RX_MSDU_DECAP_NATIVE_WIFI: /* Pull decapped header */ hdr = (struct ieee80211_hdr *)skb->data; - hdr_len = ieee80211_hdrlen(hdr->frame_control); + hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr); skb_pull(skb, hdr_len); /* Push original header */ @@ -852,6 +856,20 @@ static bool ath10k_htt_rx_has_mic_err(struct sk_buff *skb) return false; } +static bool ath10k_htt_rx_is_mgmt(struct sk_buff *skb) +{ + struct htt_rx_desc *rxd; + u32 flags; + + rxd = (void *)skb->data - sizeof(*rxd); + flags = __le32_to_cpu(rxd->attention.flags); + + if (flags & RX_ATTENTION_FLAGS_MGMT_TYPE) + return true; + + return false; +} + static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb) { struct htt_rx_desc *rxd; @@ -883,6 +901,57 @@ static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb) return CHECKSUM_UNNECESSARY; } +static int ath10k_unchain_msdu(struct sk_buff *msdu_head) +{ + struct sk_buff *next = msdu_head->next; + struct sk_buff *to_free = next; + int space; + int total_len = 0; + + /* TODO: Might could optimize this by using + * skb_try_coalesce or similar method to + * decrease copying, or maybe get mac80211 to + * provide a way to just receive a list of + * skb? + */ + + msdu_head->next = NULL; + + /* Allocate total length all at once. */ + while (next) { + total_len += next->len; + next = next->next; + } + + space = total_len - skb_tailroom(msdu_head); + if ((space > 0) && + (pskb_expand_head(msdu_head, 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; + 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; + } + + /* 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); + return 0; +} + static void ath10k_htt_rx_handler(struct ath10k_htt *htt, struct htt_rx_indication *rx) { @@ -894,6 +963,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, u8 *fw_desc; int i, j; + lockdep_assert_held(&htt->rx_ring.lock); + memset(&info, 0, sizeof(info)); fw_desc_len = __le16_to_cpu(rx->prefix.fw_rx_desc_bytes); @@ -937,6 +1008,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, } 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); continue; } @@ -944,13 +1017,16 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, status = info.status; /* 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_htt_rx_is_mgmt(msdu_head)) { + ath10k_dbg(ATH10K_DBG_HTT, "htt rx mgmt ctrl\n"); ath10k_htt_rx_free_msdu_chain(msdu_head); continue; } 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_enabled) { ath10k_dbg(ATH10K_DBG_HTT, "htt rx ignoring frame w/ status %d\n", @@ -960,14 +1036,14 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, } 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); continue; } - /* FIXME: we do not support chaining yet. - * this needs investigation */ - if (msdu_chaining) { - ath10k_warn("msdu_chaining is true\n"); + if (msdu_chaining && + (ath10k_unchain_msdu(msdu_head) < 0)) { ath10k_htt_rx_free_msdu_chain(msdu_head); continue; } @@ -975,12 +1051,22 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, info.skb = msdu_head; info.fcs_err = ath10k_htt_rx_has_fcs_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 += rx->ppdu.combined_rssi; info.rate.info0 = rx->ppdu.info0; info.rate.info1 = __le32_to_cpu(rx->ppdu.info1); info.rate.info2 = __le32_to_cpu(rx->ppdu.info2); + info.tsf = __le32_to_cpu(rx->ppdu.tsf); hdr = ath10k_htt_rx_skb_get_hdr(msdu_head); @@ -1014,8 +1100,11 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, msdu_head = NULL; msdu_tail = NULL; + + spin_lock_bh(&htt->rx_ring.lock); msdu_chaining = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len, &msdu_head, &msdu_tail); + spin_unlock_bh(&htt->rx_ring.lock); ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n"); @@ -1095,7 +1184,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, 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); ath10k_process_rx(htt->ar, &info); @@ -1107,6 +1196,45 @@ end: } } +static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar, + struct sk_buff *skb) +{ + struct ath10k_htt *htt = &ar->htt; + struct htt_resp *resp = (struct htt_resp *)skb->data; + struct htt_tx_done tx_done = {}; + int status = MS(resp->data_tx_completion.flags, HTT_DATA_TX_STATUS); + __le16 msdu_id; + int i; + + lockdep_assert_held(&htt->tx_lock); + + switch (status) { + case HTT_DATA_TX_STATUS_NO_ACK: + tx_done.no_ack = true; + break; + case HTT_DATA_TX_STATUS_OK: + break; + case HTT_DATA_TX_STATUS_DISCARD: + case HTT_DATA_TX_STATUS_POSTPONE: + case HTT_DATA_TX_STATUS_DOWNLOAD_FAIL: + tx_done.discard = true; + break; + default: + ath10k_warn("unhandled tx completion status %d\n", status); + tx_done.discard = true; + break; + } + + ath10k_dbg(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++) { + msdu_id = resp->data_tx_completion.msdus[i]; + tx_done.msdu_id = __le16_to_cpu(msdu_id); + ath10k_txrx_tx_unref(htt, &tx_done); + } +} + void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) { struct ath10k_htt *htt = &ar->htt; @@ -1116,7 +1244,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) if (!IS_ALIGNED((unsigned long)skb->data, 4)) 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); switch (resp->hdr.msg_type) { case HTT_T2H_MSG_TYPE_VERSION_CONF: { @@ -1125,10 +1253,12 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) complete(&htt->target_version_received); break; } - case HTT_T2H_MSG_TYPE_RX_IND: { - ath10k_htt_rx_handler(htt, &resp->rx_ind); - break; - } + case HTT_T2H_MSG_TYPE_RX_IND: + spin_lock_bh(&htt->rx_ring.lock); + __skb_queue_tail(&htt->rx_compl_q, skb); + spin_unlock_bh(&htt->rx_ring.lock); + tasklet_schedule(&htt->txrx_compl_task); + return; case HTT_T2H_MSG_TYPE_PEER_MAP: { struct htt_peer_map_event ev = { .vdev_id = resp->peer_map.vdev_id, @@ -1163,44 +1293,17 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) break; } + spin_lock_bh(&htt->tx_lock); ath10k_txrx_tx_unref(htt, &tx_done); + spin_unlock_bh(&htt->tx_lock); break; } - case HTT_T2H_MSG_TYPE_TX_COMPL_IND: { - struct htt_tx_done tx_done = {}; - int status = MS(resp->data_tx_completion.flags, - HTT_DATA_TX_STATUS); - __le16 msdu_id; - int i; - - switch (status) { - case HTT_DATA_TX_STATUS_NO_ACK: - tx_done.no_ack = true; - break; - case HTT_DATA_TX_STATUS_OK: - break; - case HTT_DATA_TX_STATUS_DISCARD: - case HTT_DATA_TX_STATUS_POSTPONE: - case HTT_DATA_TX_STATUS_DOWNLOAD_FAIL: - tx_done.discard = true; - break; - default: - ath10k_warn("unhandled tx completion status %d\n", - status); - tx_done.discard = true; - break; - } - - ath10k_dbg(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++) { - msdu_id = resp->data_tx_completion.msdus[i]; - tx_done.msdu_id = __le16_to_cpu(msdu_id); - ath10k_txrx_tx_unref(htt, &tx_done); - } - break; - } + case HTT_T2H_MSG_TYPE_TX_COMPL_IND: + spin_lock_bh(&htt->tx_lock); + __skb_queue_tail(&htt->tx_compl_q, skb); + spin_unlock_bh(&htt->tx_lock); + tasklet_schedule(&htt->txrx_compl_task); + return; case HTT_T2H_MSG_TYPE_SEC_IND: { struct ath10k *ar = htt->ar; struct htt_security_indication *ev = &resp->security_indication; @@ -1240,3 +1343,25 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) /* Free the indication buffer */ dev_kfree_skb_any(skb); } + +static void ath10k_htt_txrx_compl_task(unsigned long ptr) +{ + struct ath10k_htt *htt = (struct ath10k_htt *)ptr; + struct htt_resp *resp; + struct sk_buff *skb; + + spin_lock_bh(&htt->tx_lock); + while ((skb = __skb_dequeue(&htt->tx_compl_q))) { + ath10k_htt_rx_frm_tx_compl(htt->ar, skb); + dev_kfree_skb_any(skb); + } + spin_unlock_bh(&htt->tx_lock); + + spin_lock_bh(&htt->rx_ring.lock); + while ((skb = __skb_dequeue(&htt->rx_compl_q))) { + resp = (struct htt_resp *)skb->data; + ath10k_htt_rx_handler(htt, &resp->rx_ind); + dev_kfree_skb_any(skb); + } + spin_unlock_bh(&htt->rx_ring.lock); +} diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index f1d36d2d2723..7a3e2e40dd5c 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -109,6 +109,14 @@ int ath10k_htt_tx_attach(struct ath10k_htt *htt) return -ENOMEM; } + 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); + return -ENOMEM; + } + return 0; } @@ -117,9 +125,7 @@ static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt) struct htt_tx_done tx_done = {0}; int msdu_id; - /* No locks needed. Called after communication with the device has - * been stopped. */ - + 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; @@ -132,6 +138,7 @@ static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt) ath10k_txrx_tx_unref(htt, &tx_done); } + spin_unlock_bh(&htt->tx_lock); } void ath10k_htt_tx_detach(struct ath10k_htt *htt) @@ -139,6 +146,7 @@ void ath10k_htt_tx_detach(struct ath10k_htt *htt) ath10k_htt_tx_cleanup_pending(htt); kfree(htt->pending_tx); kfree(htt->used_msdu_ids); + dma_pool_destroy(htt->tx_pool); return; } @@ -334,7 +342,9 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) goto err_free_msdu_id; } - res = ath10k_skb_map(dev, msdu); + skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, + DMA_TO_DEVICE); + res = dma_mapping_error(dev, skb_cb->paddr); if (res) goto err_free_txdesc; @@ -348,8 +358,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) memcpy(cmd->mgmt_tx.hdr, msdu->data, min_t(int, msdu->len, HTT_MGMT_FRM_HDR_DOWNLOAD_LEN)); - skb_cb->htt.frag_len = 0; - skb_cb->htt.pad_len = 0; + skb_cb->htt.txbuf = NULL; res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc); if (res) @@ -358,7 +367,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) return 0; err_unmap_msdu: - ath10k_skb_unmap(dev, msdu); + dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); err_free_txdesc: dev_kfree_skb_any(txdesc); err_free_msdu_id: @@ -375,19 +384,19 @@ err: int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) { struct device *dev = htt->ar->dev; - struct htt_cmd *cmd; - struct htt_data_tx_desc_frag *tx_frags; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); - struct sk_buff *txdesc = NULL; - bool use_frags; - u8 vdev_id = ATH10K_SKB_CB(msdu)->vdev_id; - u8 tid; - int prefetch_len, desc_len; - int msdu_id = -1; + struct ath10k_hif_sg_item sg_items[2]; + struct htt_data_tx_desc_frag *frags; + u8 vdev_id = skb_cb->vdev_id; + u8 tid = skb_cb->htt.tid; + int prefetch_len; int res; - u8 flags0; - u16 flags1; + u8 flags0 = 0; + u16 msdu_id, flags1 = 0; + dma_addr_t paddr; + u32 frags_paddr; + bool use_frags; res = ath10k_htt_tx_inc_pending(htt); if (res) @@ -406,114 +415,120 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) prefetch_len = min(htt->prefetch_len, msdu->len); prefetch_len = roundup(prefetch_len, 4); - desc_len = sizeof(cmd->hdr) + sizeof(cmd->data_tx) + prefetch_len; - - txdesc = ath10k_htc_alloc_skb(desc_len); - if (!txdesc) { - res = -ENOMEM; - goto err_free_msdu_id; - } - /* Since HTT 3.0 there is no separate mgmt tx command. However in case * of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx * fragment list host driver specifies directly frame pointer. */ use_frags = htt->target_version_major < 3 || !ieee80211_is_mgmt(hdr->frame_control); - if (!IS_ALIGNED((unsigned long)txdesc->data, 4)) { - ath10k_warn("htt alignment check failed. dropping packet.\n"); - res = -EIO; - goto err_free_txdesc; - } + skb_cb->htt.txbuf = dma_pool_alloc(htt->tx_pool, GFP_ATOMIC, + &paddr); + if (!skb_cb->htt.txbuf) + goto err_free_msdu_id; + skb_cb->htt.txbuf_paddr = paddr; - if (use_frags) { - skb_cb->htt.frag_len = sizeof(*tx_frags) * 2; - skb_cb->htt.pad_len = (unsigned long)msdu->data - - round_down((unsigned long)msdu->data, 4); + skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, + DMA_TO_DEVICE); + res = dma_mapping_error(dev, skb_cb->paddr); + if (res) + goto err_free_txbuf; - skb_push(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len); - } else { - skb_cb->htt.frag_len = 0; - skb_cb->htt.pad_len = 0; - } + if (likely(use_frags)) { + frags = skb_cb->htt.txbuf->frags; - res = ath10k_skb_map(dev, msdu); - if (res) - goto err_pull_txfrag; - - if (use_frags) { - dma_sync_single_for_cpu(dev, skb_cb->paddr, msdu->len, - DMA_TO_DEVICE); - - /* tx fragment list must be terminated with zero-entry */ - tx_frags = (struct htt_data_tx_desc_frag *)msdu->data; - tx_frags[0].paddr = __cpu_to_le32(skb_cb->paddr + - skb_cb->htt.frag_len + - skb_cb->htt.pad_len); - tx_frags[0].len = __cpu_to_le32(msdu->len - - skb_cb->htt.frag_len - - skb_cb->htt.pad_len); - tx_frags[1].paddr = __cpu_to_le32(0); - tx_frags[1].len = __cpu_to_le32(0); - - dma_sync_single_for_device(dev, skb_cb->paddr, msdu->len, - DMA_TO_DEVICE); - } + frags[0].paddr = __cpu_to_le32(skb_cb->paddr); + frags[0].len = __cpu_to_le32(msdu->len); + frags[1].paddr = 0; + frags[1].len = 0; - ath10k_dbg(ATH10K_DBG_HTT, "msdu 0x%llx\n", - (unsigned long long) ATH10K_SKB_CB(msdu)->paddr); - ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "msdu: ", - msdu->data, msdu->len); + flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI, + HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); - skb_put(txdesc, desc_len); - cmd = (struct htt_cmd *)txdesc->data; + frags_paddr = skb_cb->htt.txbuf_paddr; + } else { + flags0 |= SM(ATH10K_HW_TXRX_MGMT, + HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); - tid = ATH10K_SKB_CB(msdu)->htt.tid; + frags_paddr = skb_cb->paddr; + } - ath10k_dbg(ATH10K_DBG_HTT, "htt data tx using tid %hhu\n", tid); + /* Normally all commands go through HTC which manages tx credits for + * each endpoint and notifies when tx is completed. + * + * HTT endpoint is creditless so there's no need to care about HTC + * flags. In that case it is trivial to fill the HTC header here. + * + * MSDU transmission is considered completed upon HTT event. This + * implies no relevant resources can be freed until after the event is + * received. That's why HTC tx completion handler itself is ignored by + * setting NULL to transfer_context for all sg items. + * + * There is simply no point in pushing HTT TX_FRM through HTC tx path + * as it's a waste of resources. By bypassing HTC it is possible to + * avoid extra memory allocations, compress data structures and thus + * improve performance. */ + + skb_cb->htt.txbuf->htc_hdr.eid = htt->eid; + skb_cb->htt.txbuf->htc_hdr.len = __cpu_to_le16( + sizeof(skb_cb->htt.txbuf->cmd_hdr) + + sizeof(skb_cb->htt.txbuf->cmd_tx) + + prefetch_len); + skb_cb->htt.txbuf->htc_hdr.flags = 0; - flags0 = 0; if (!ieee80211_has_protected(hdr->frame_control)) flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT; - flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; - if (use_frags) - flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI, - HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); - else - flags0 |= SM(ATH10K_HW_TXRX_MGMT, - HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); + flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; - flags1 = 0; 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; - cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM; - cmd->data_tx.flags0 = flags0; - cmd->data_tx.flags1 = __cpu_to_le16(flags1); - cmd->data_tx.len = __cpu_to_le16(msdu->len - - skb_cb->htt.frag_len - - skb_cb->htt.pad_len); - cmd->data_tx.id = __cpu_to_le16(msdu_id); - cmd->data_tx.frags_paddr = __cpu_to_le32(skb_cb->paddr); - cmd->data_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID); - - memcpy(cmd->data_tx.prefetch, hdr, prefetch_len); + skb_cb->htt.txbuf->cmd_hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM; + skb_cb->htt.txbuf->cmd_tx.flags0 = flags0; + skb_cb->htt.txbuf->cmd_tx.flags1 = __cpu_to_le16(flags1); + 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); + + 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", + 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: ", + msdu->data, msdu->len); - res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc); + sg_items[0].transfer_id = 0; + sg_items[0].transfer_context = NULL; + sg_items[0].vaddr = &skb_cb->htt.txbuf->htc_hdr; + sg_items[0].paddr = skb_cb->htt.txbuf_paddr + + sizeof(skb_cb->htt.txbuf->frags); + sg_items[0].len = sizeof(skb_cb->htt.txbuf->htc_hdr) + + sizeof(skb_cb->htt.txbuf->cmd_hdr) + + sizeof(skb_cb->htt.txbuf->cmd_tx); + + sg_items[1].transfer_id = 0; + sg_items[1].transfer_context = NULL; + sg_items[1].vaddr = msdu->data; + sg_items[1].paddr = skb_cb->paddr; + sg_items[1].len = prefetch_len; + + res = ath10k_hif_tx_sg(htt->ar, + htt->ar->htc.endpoint[htt->eid].ul_pipe_id, + sg_items, ARRAY_SIZE(sg_items)); if (res) goto err_unmap_msdu; return 0; err_unmap_msdu: - ath10k_skb_unmap(dev, msdu); -err_pull_txfrag: - skb_pull(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len); -err_free_txdesc: - dev_kfree_skb_any(txdesc); + dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); +err_free_txbuf: + dma_pool_free(htt->tx_pool, + skb_cb->htt.txbuf, + skb_cb->htt.txbuf_paddr); err_free_msdu_id: spin_lock_bh(&htt->tx_lock); htt->pending_tx[msdu_id] = NULL; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index f1505a25d810..35fc44e281f5 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -205,8 +205,11 @@ enum ath10k_mcast2ucast_mode { #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_CPU_WARM_RST_MASK 0x00000040 #define SOC_CPU_CLOCK_OFFSET 0x00000020 #define SOC_CPU_CLOCK_STANDARD_LSB 0 #define SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 @@ -216,6 +219,8 @@ enum ath10k_mcast2ucast_mode { #define SOC_LPO_CAL_OFFSET 0x000000e0 #define SOC_LPO_CAL_ENABLE_LSB 20 #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_REV_LSB 8 @@ -273,6 +278,7 @@ enum ath10k_mcast2ucast_mode { #define PCIE_INTR_CAUSE_ADDRESS 0x000c #define PCIE_INTR_CLR_ADDRESS 0x0014 #define SCRATCH_3_ADDRESS 0x0030 +#define CPU_INTR_ADDRESS 0x0010 /* Firmware indications to the Host via SCRATCH_3 register. */ #define FW_INDICATOR_ADDRESS (SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 776e364eadcd..511a2f81e7af 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -323,13 +323,15 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr) ret = ath10k_wmi_peer_create(ar, vdev_id, addr); if (ret) { - ath10k_warn("Failed to create wmi peer: %i\n", ret); + ath10k_warn("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: %i\n", ret); + ath10k_warn("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); @@ -339,6 +341,51 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr) 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 on vdev %i: %d\n", + arvif->vdev_id, 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 on vdev %i : %d\n", + arvif->vdev_id, 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 on vdev %i: %d\n", + arvif->vdev_id, 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 on vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + return 0; +} + static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value) { struct ath10k *ar = arvif->ar; @@ -444,8 +491,7 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar) static int ath10k_vdev_start(struct ath10k_vif *arvif) { struct ath10k *ar = arvif->ar; - struct ieee80211_conf *conf = &ar->hw->conf; - struct ieee80211_channel *channel = conf->chandef.chan; + struct cfg80211_chan_def *chandef = &ar->chandef; struct wmi_vdev_start_request_arg arg = {}; int ret = 0; @@ -457,16 +503,14 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif) arg.dtim_period = arvif->dtim_period; arg.bcn_intval = arvif->beacon_interval; - arg.channel.freq = channel->center_freq; - - arg.channel.band_center_freq1 = conf->chandef.center_freq1; - - arg.channel.mode = chan_to_phymode(&conf->chandef); + arg.channel.freq = chandef->chan->center_freq; + arg.channel.band_center_freq1 = chandef->center_freq1; + arg.channel.mode = chan_to_phymode(chandef); arg.channel.min_power = 0; - arg.channel.max_power = channel->max_power * 2; - arg.channel.max_reg_power = channel->max_reg_power * 2; - arg.channel.max_antenna_gain = channel->max_antenna_gain * 2; + arg.channel.max_power = chandef->chan->max_power * 2; + arg.channel.max_reg_power = chandef->chan->max_reg_power * 2; + arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2; if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { arg.ssid = arvif->u.ap.ssid; @@ -475,7 +519,7 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif) /* For now allow DFS for AP mode */ arg.channel.chan_radar = - !!(channel->flags & IEEE80211_CHAN_RADAR); + !!(chandef->chan->flags & IEEE80211_CHAN_RADAR); } else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { arg.ssid = arvif->vif->bss_conf.ssid; arg.ssid_len = arvif->vif->bss_conf.ssid_len; @@ -488,13 +532,15 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif) ret = ath10k_wmi_vdev_start(ar, &arg); if (ret) { - ath10k_warn("WMI vdev start failed: ret %d\n", ret); + ath10k_warn("WMI vdev %i start failed: ret %d\n", + arg.vdev_id, ret); return ret; } ret = ath10k_vdev_setup_sync(ar); if (ret) { - ath10k_warn("vdev setup failed %d\n", ret); + ath10k_warn("vdev %i setup failed %d\n", + arg.vdev_id, ret); return ret; } @@ -512,13 +558,15 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif) ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id); if (ret) { - ath10k_warn("WMI vdev stop failed: ret %d\n", ret); + ath10k_warn("WMI vdev %i stop failed: ret %d\n", + arvif->vdev_id, ret); return ret; } ret = ath10k_vdev_setup_sync(ar); if (ret) { - ath10k_warn("vdev setup failed %d\n", ret); + ath10k_warn("vdev %i setup sync failed %d\n", + arvif->vdev_id, ret); return ret; } @@ -527,7 +575,8 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif) 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 = {}; int ret = 0; @@ -540,11 +589,11 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) arg.vdev_id = vdev_id; 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 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 = !!(channel->flags & IEEE80211_CHAN_RADAR); @@ -555,19 +604,22 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) ret = ath10k_wmi_vdev_start(ar, &arg); if (ret) { - ath10k_warn("Monitor vdev start failed: ret %d\n", ret); + ath10k_warn("Monitor vdev %i start failed: ret %d\n", + vdev_id, ret); return ret; } ret = ath10k_vdev_setup_sync(ar); if (ret) { - ath10k_warn("Monitor vdev setup failed %d\n", ret); + ath10k_warn("Monitor vdev %i setup failed %d\n", + vdev_id, ret); return ret; } ret = ath10k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr); if (ret) { - ath10k_warn("Monitor vdev up failed: %d\n", ret); + ath10k_warn("Monitor vdev %i up failed: %d\n", + vdev_id, ret); goto vdev_stop; } @@ -579,7 +631,8 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) vdev_stop: ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id); if (ret) - ath10k_warn("Monitor vdev stop failed: %d\n", ret); + ath10k_warn("Monitor vdev %i stop failed: %d\n", + ar->monitor_vdev_id, ret); return ret; } @@ -602,15 +655,18 @@ static int ath10k_monitor_stop(struct ath10k *ar) ret = ath10k_wmi_vdev_down(ar, ar->monitor_vdev_id); if (ret) - ath10k_warn("Monitor vdev down failed: %d\n", ret); + ath10k_warn("Monitor vdev %i down failed: %d\n", + ar->monitor_vdev_id, ret); ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id); if (ret) - ath10k_warn("Monitor vdev stop failed: %d\n", ret); + ath10k_warn("Monitor vdev %i stop failed: %d\n", + ar->monitor_vdev_id, ret); ret = ath10k_vdev_setup_sync(ar); if (ret) - ath10k_warn("Monitor_down sync failed: %d\n", ret); + ath10k_warn("Monitor_down sync failed, vdev %i: %d\n", + ar->monitor_vdev_id, ret); ar->monitor_enabled = false; return ret; @@ -640,7 +696,8 @@ static int ath10k_monitor_create(struct ath10k *ar) WMI_VDEV_TYPE_MONITOR, 0, ar->mac_addr); if (ret) { - ath10k_warn("WMI vdev monitor create failed: ret %d\n", ret); + ath10k_warn("WMI vdev %i monitor create failed: ret %d\n", + ar->monitor_vdev_id, ret); goto vdev_fail; } @@ -669,7 +726,8 @@ static int ath10k_monitor_destroy(struct ath10k *ar) ret = ath10k_wmi_vdev_delete(ar, ar->monitor_vdev_id); if (ret) { - ath10k_warn("WMI vdev monitor delete failed: %d\n", ret); + ath10k_warn("WMI vdev %i monitor delete failed: %d\n", + ar->monitor_vdev_id, ret); return ret; } @@ -791,6 +849,22 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, if (!info->enable_beacon) { ath10k_vdev_stop(arvif); + + arvif->is_started = false; + 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; + } + spin_unlock_bh(&arvif->ar->data_lock); + return; } @@ -800,12 +874,21 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, if (ret) 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) { - ath10k_warn("Failed to bring up VDEV: %d\n", - arvif->vdev_id); + ath10k_warn("Failed to bring up vdev %d: %i\n", + arvif->vdev_id, ret); + ath10k_vdev_stop(arvif); return; } + + arvif->is_started = true; + arvif->is_up = true; + ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id); } @@ -824,18 +907,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", self_peer, arvif->vdev_id, ret); - if (is_zero_ether_addr(arvif->u.ibss.bssid)) + if (is_zero_ether_addr(arvif->bssid)) return; ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, - arvif->u.ibss.bssid); + arvif->bssid); if (ret) { 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; } - memset(arvif->u.ibss.bssid, 0, ETH_ALEN); + memset(arvif->bssid, 0, ETH_ALEN); return; } @@ -878,8 +961,8 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) 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\n", - arvif->vdev_id); + ath10k_warn("Failed to set inactivity time for vdev %d: %i\n", + arvif->vdev_id, ret); return ret; } } else { @@ -1017,7 +1100,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, struct wmi_peer_assoc_complete_arg *arg) { const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; - int smps; int i, n; lockdep_assert_held(&ar->conf_mutex); @@ -1063,17 +1145,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, 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]) arg->peer_rate_caps |= WMI_RC_TS_FLAG; else if (ht_cap->mcs.rx_mask[1]) @@ -1083,8 +1154,23 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, if (ht_cap->mcs.rx_mask[i/8] & (1 << i%8)) 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", arg->addr, @@ -1092,27 +1178,20 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, arg->peer_num_spatial_streams); } -static void ath10k_peer_assoc_h_qos_ap(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_peer_assoc_qos_ap(struct ath10k *ar, + struct ath10k_vif *arvif, + struct ieee80211_sta *sta) { u32 uapsd = 0; u32 max_sp = 0; + int ret = 0; lockdep_assert_held(&ar->conf_mutex); - if (sta->wme) - arg->peer_flags |= WMI_PEER_QOS; - if (sta->wme && sta->uapsd_queues) { ath10k_dbg(ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n", 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) uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN | WMI_AP_PS_UAPSD_AC3_TRIGGER_EN; @@ -1130,35 +1209,40 @@ static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar, if (sta->max_sp < MAX_WMI_AP_PS_PEER_PARAM_MAX_SP) max_sp = sta->max_sp; - ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, - sta->addr, - WMI_AP_PS_PEER_PARAM_UAPSD, - uapsd); + ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, + sta->addr, + WMI_AP_PS_PEER_PARAM_UAPSD, + uapsd); + if (ret) { + ath10k_warn("failed to set ap ps peer param uapsd for vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } - ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, - sta->addr, - WMI_AP_PS_PEER_PARAM_MAX_SP, - max_sp); + ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, + sta->addr, + 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", + arvif->vdev_id, ret); + return ret; + } /* TODO setup this based on STA listen interval and beacon interval. Currently we don't know sta->listen_interval - mac80211 patch required. Currently use 10 seconds */ - ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, - sta->addr, - WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, - 10); + ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, sta->addr, + 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", + arvif->vdev_id, ret); + return ret; + } } -} -static void ath10k_peer_assoc_h_qos_sta(struct ath10k *ar, - 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; + return 0; } static void ath10k_peer_assoc_h_vht(struct ath10k *ar, @@ -1211,10 +1295,17 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar, { switch (arvif->vdev_type) { 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; 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; default: break; @@ -1293,6 +1384,33 @@ static int ath10k_peer_assoc_prepare(struct ath10k *ar, 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 */ static void ath10k_bss_assoc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -1300,6 +1418,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, { struct ath10k *ar = hw->priv; 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 ieee80211_sta *ap_sta; int ret; @@ -1310,17 +1429,21 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ap_sta = ieee80211_find_sta(vif, bss_conf->bssid); if (!ap_sta) { - ath10k_warn("Failed to find station entry for %pM\n", - bss_conf->bssid); + ath10k_warn("Failed to find station entry for %pM, vdev %i\n", + bss_conf->bssid, arvif->vdev_id); rcu_read_unlock(); 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, bss_conf, &peer_arg); if (ret) { - ath10k_warn("Peer assoc prepare failed for %pM\n: %d", - bss_conf->bssid, ret); + ath10k_warn("Peer assoc prepare failed for %pM vdev %i\n: %d", + bss_conf->bssid, arvif->vdev_id, ret); rcu_read_unlock(); return; } @@ -1329,8 +1452,15 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ret = ath10k_wmi_peer_assoc(ar, &peer_arg); if (ret) { - ath10k_warn("Peer assoc failed for %pM\n: %d", - bss_conf->bssid, ret); + ath10k_warn("Peer assoc failed for %pM vdev %i\n: %d", + 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", + arvif->vdev_id, ret); return; } @@ -1338,11 +1468,17 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, "mac vdev %d up (associated) bssid %pM aid %d\n", arvif->vdev_id, bss_conf->bssid, bss_conf->aid); - ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, bss_conf->aid, - bss_conf->bssid); - if (ret) + arvif->aid = bss_conf->aid; + memcpy(arvif->bssid, bss_conf->bssid, ETH_ALEN); + + ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid); + if (ret) { ath10k_warn("VDEV: %d up failed: ret %d\n", arvif->vdev_id, ret); + return; + } + + arvif->is_up = true; } /* @@ -1382,6 +1518,9 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); 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, @@ -1394,21 +1533,35 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, ret = ath10k_peer_assoc_prepare(ar, arvif, sta, NULL, &peer_arg); if (ret) { - ath10k_warn("WMI peer assoc prepare failed for %pM\n", - sta->addr); + ath10k_warn("WMI peer assoc prepare failed for %pM vdev %i: %i\n", + sta->addr, arvif->vdev_id, ret); return ret; } ret = ath10k_wmi_peer_assoc(ar, &peer_arg); if (ret) { - ath10k_warn("Peer assoc failed for STA %pM\n: %d", - sta->addr, ret); + ath10k_warn("Peer assoc failed 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\n", ret); return ret; } ret = ath10k_install_peer_wep_keys(arvif, sta->addr); if (ret) { - ath10k_warn("could not install peer wep keys (%d)\n", ret); + ath10k_warn("could not 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("could not set qos params for STA %pM for vdev %i: %d\n", + sta->addr, arvif->vdev_id, ret); return ret; } @@ -1424,7 +1577,8 @@ static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif, ret = ath10k_clear_peer_keys(arvif, sta->addr); if (ret) { - ath10k_warn("could not clear all peer wep keys (%d)\n", ret); + ath10k_warn("could not clear all peer wep keys for vdev %i: %d\n", + arvif->vdev_id, ret); return ret; } @@ -1547,9 +1701,9 @@ static void ath10k_regd_update(struct ath10k *ar) /* Target allows setting up per-band regdomain but ath_common provides * a combined one only */ ret = ath10k_wmi_pdev_set_regdomain(ar, - regpair->regDmnEnum, - regpair->regDmnEnum, /* 2ghz */ - regpair->regDmnEnum, /* 5ghz */ + regpair->reg_domain, + regpair->reg_domain, /* 2ghz */ + regpair->reg_domain, /* 5ghz */ regpair->reg_2ghz_ctl, regpair->reg_5ghz_ctl); if (ret) @@ -2100,11 +2254,29 @@ static int ath10k_start(struct ieee80211_hw *hw) ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n", 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); + ret = 0; exit: mutex_unlock(&ar->conf_mutex); - return 0; + return ret; } static void ath10k_stop(struct ieee80211_hw *hw) @@ -2145,6 +2317,98 @@ static int ath10k_config_ps(struct ath10k *ar) 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) { struct ath10k *ar = hw->priv; @@ -2165,6 +2429,11 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) spin_unlock_bh(&ar->data_lock); 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) { @@ -2214,7 +2483,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); enum wmi_sta_powersave_param param; int ret = 0; - u32 value, param_id; + u32 value; int bit; u32 vdev_param; @@ -2276,7 +2545,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_create(ar, arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype, vif->addr); if (ret) { - ath10k_warn("WMI vdev create failed: ret %d\n", ret); + ath10k_warn("WMI vdev %i create failed: ret %d\n", + arvif->vdev_id, ret); goto err; } @@ -2287,7 +2557,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param, arvif->def_wep_key_idx); if (ret) { - ath10k_warn("Failed to set default keyid: %d\n", ret); + ath10k_warn("Failed to set vdev %i default keyid: %d\n", + arvif->vdev_id, ret); goto err_vdev_delete; } @@ -2296,23 +2567,25 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, 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 TX encap: %d\n", ret); + ath10k_warn("Failed to set vdev %i TX encap: %d\n", + arvif->vdev_id, 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 peer for AP: %d\n", ret); + ath10k_warn("Failed to create vdev %i peer for AP: %d\n", + arvif->vdev_id, ret); goto err_vdev_delete; } - param_id = ar->wmi.pdev_param->sta_kickout_th; - - /* Disable STA KICKOUT functionality in FW */ - ret = ath10k_wmi_pdev_set_param(ar, param_id, 0); - if (ret) - ath10k_warn("Failed to disable STA KICKOUT\n"); + ret = ath10k_mac_set_kickout(arvif); + if (ret) { + ath10k_warn("Failed to set vdev %i kickout parameters: %d\n", + arvif->vdev_id, ret); + goto err_peer_delete; + } } if (arvif->vdev_type == WMI_VDEV_TYPE_STA) { @@ -2321,7 +2594,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, value); if (ret) { - ath10k_warn("Failed to set RX wake policy: %d\n", ret); + ath10k_warn("Failed to set vdev %i RX wake policy: %d\n", + arvif->vdev_id, ret); goto err_peer_delete; } @@ -2330,7 +2604,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, value); if (ret) { - ath10k_warn("Failed to set TX wake thresh: %d\n", ret); + ath10k_warn("Failed to set vdev %i TX wake thresh: %d\n", + arvif->vdev_id, ret); goto err_peer_delete; } @@ -2339,7 +2614,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, value); if (ret) { - ath10k_warn("Failed to set PSPOLL count: %d\n", ret); + ath10k_warn("Failed to set vdev %i PSPOLL count: %d\n", + arvif->vdev_id, ret); goto err_peer_delete; } } @@ -2403,17 +2679,19 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, vif->addr); if (ret) - ath10k_warn("Failed to remove peer for AP: %d\n", ret); + ath10k_warn("Failed to remove peer for AP vdev %i: %d\n", + arvif->vdev_id, ret); kfree(arvif->u.ap.noa_data); } - ath10k_dbg(ATH10K_DBG_MAC, "mac vdev delete %d (remove interface)\n", + ath10k_dbg(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("WMI vdev delete failed: %d\n", ret); + ath10k_warn("WMI vdev %i delete failed: %d\n", + arvif->vdev_id, ret); if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) ar->monitor_present = false; @@ -2502,8 +2780,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, arvif->vdev_id, arvif->beacon_interval); if (ret) - ath10k_warn("Failed to set beacon interval for VDEV: %d\n", - arvif->vdev_id); + ath10k_warn("Failed to set beacon interval for vdev %d: %i\n", + arvif->vdev_id, ret); } if (changed & BSS_CHANGED_BEACON) { @@ -2515,8 +2793,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, 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\n", - arvif->vdev_id); + ath10k_warn("Failed to set beacon mode for vdev %d: %i\n", + arvif->vdev_id, ret); } if (changed & BSS_CHANGED_BEACON_INFO) { @@ -2530,8 +2808,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, 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\n", - arvif->vdev_id); + ath10k_warn("Failed to set dtim period for vdev %d: %i\n", + arvif->vdev_id, ret); } if (changed & BSS_CHANGED_SSID && @@ -2551,7 +2829,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ret = ath10k_peer_create(ar, arvif->vdev_id, info->bssid); if (ret) - ath10k_warn("Failed to add peer %pM for vdev %d when changin bssid: %i\n", + 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) { @@ -2559,15 +2837,20 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, * this is never erased as we it for crypto key * clearing; this is FW requirement */ - memcpy(arvif->u.sta.bssid, info->bssid, - ETH_ALEN); + memcpy(arvif->bssid, info->bssid, ETH_ALEN); ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d start %pM\n", arvif->vdev_id, info->bssid); - /* FIXME: check return value */ 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; } /* @@ -2576,7 +2859,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, * IBSS in order to remove BSSID peer. */ if (vif->type == NL80211_IFTYPE_ADHOC) - memcpy(arvif->u.ibss.bssid, info->bssid, + memcpy(arvif->bssid, info->bssid, ETH_ALEN); } } @@ -2598,8 +2881,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, cts_prot); if (ret) - ath10k_warn("Failed to set CTS prot for VDEV: %d\n", - arvif->vdev_id); + ath10k_warn("Failed to set CTS prot for vdev %d: %d\n", + arvif->vdev_id, ret); } if (changed & BSS_CHANGED_ERP_SLOT) { @@ -2617,8 +2900,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, 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\n", - arvif->vdev_id); + ath10k_warn("Failed to set erp slot for vdev %d: %i\n", + arvif->vdev_id, ret); } if (changed & BSS_CHANGED_ERP_PREAMBLE) { @@ -2636,8 +2919,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, preamble); if (ret) - ath10k_warn("Failed to set preamble for VDEV: %d\n", - arvif->vdev_id); + ath10k_warn("Failed to set preamble for vdev %d: %i\n", + arvif->vdev_id, ret); } if (changed & BSS_CHANGED_ASSOC) { @@ -2645,6 +2928,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ath10k_bss_assoc(hw, vif, info); } +exit: mutex_unlock(&ar->conf_mutex); } @@ -2767,8 +3051,8 @@ static void ath10k_set_key_h_def_keyidx(struct ath10k *ar, ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, key->keyidx); if (ret) - ath10k_warn("failed to set group key as default key: %d\n", - ret); + ath10k_warn("failed to set vdev %i group key as default key: %d\n", + arvif->vdev_id, ret); } static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, @@ -2828,7 +3112,8 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ret = ath10k_install_key(arvif, key, cmd, peer_addr); if (ret) { - ath10k_warn("ath10k_install_key failed (%d)\n", ret); + ath10k_warn("key installation failed for vdev %i peer %pM: %d\n", + arvif->vdev_id, peer_addr, ret); goto exit; } @@ -2850,6 +3135,69 @@ exit: 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, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -2858,9 +3206,22 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, { 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 && + new_state == IEEE80211_STA_NONE) { + memset(arsta, 0, sizeof(*arsta)); + arsta->arvif = arvif; + INIT_WORK(&arsta->update_wk, ath10k_sta_rc_update_wk); + } + + /* 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); if (old_state == IEEE80211_STA_NOTEXIST && @@ -2899,8 +3260,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, arvif->vdev_id, sta->addr); ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr); if (ret) - ath10k_warn("Failed to delete peer: %pM for VDEV: %d\n", - sta->addr, arvif->vdev_id); + ath10k_warn("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); @@ -2916,8 +3277,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ret = ath10k_station_assoc(ar, arvif, sta); if (ret) - ath10k_warn("Failed to associate station: %pM\n", - sta->addr); + ath10k_warn("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 && (vif->type == NL80211_IFTYPE_AP || @@ -2930,8 +3291,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ret = ath10k_station_disassoc(ar, arvif, sta); if (ret) - ath10k_warn("Failed to disassociate station: %pM\n", - sta->addr); + ath10k_warn("Failed to disassociate station: %pM vdev %i ret %i\n", + sta->addr, arvif->vdev_id, ret); } exit: mutex_unlock(&ar->conf_mutex); @@ -3212,7 +3573,8 @@ static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) }), ATH10K_FLUSH_TIMEOUT_HZ); if (ret <= 0 || skip) - ath10k_warn("tx not flushed\n"); + ath10k_warn("tx not flushed (skip %i ar-state %i): %i\n", + skip, ar->state, ret); skip: mutex_unlock(&ar->conf_mutex); @@ -3234,23 +3596,14 @@ static int ath10k_suspend(struct ieee80211_hw *hw, struct ath10k *ar = hw->priv; 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) { - ath10k_warn("could not suspend target (%d)\n", ret); - return 1; - } - - 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; + if (ret == -ETIMEDOUT) + goto resume; + ret = 1; + goto exit; } ret = ath10k_hif_suspend(ar); @@ -3259,12 +3612,17 @@ static int ath10k_suspend(struct ieee80211_hw *hw, goto resume; } - return 0; + ret = 0; + goto exit; resume: ret = ath10k_wmi_pdev_resume_target(ar); if (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) @@ -3272,19 +3630,26 @@ static int ath10k_resume(struct ieee80211_hw *hw) struct ath10k *ar = hw->priv; int ret; + mutex_lock(&ar->conf_mutex); + ret = ath10k_hif_resume(ar); if (ret) { ath10k_warn("could not resume hif (%d)\n", ret); - return 1; + ret = 1; + goto exit; } ret = ath10k_wmi_pdev_resume_target(ar); if (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 @@ -3575,7 +3940,8 @@ static bool ath10k_get_fixed_rate_nss(const struct cfg80211_bitrate_mask *mask, static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif, u8 fixed_rate, - u8 fixed_nss) + u8 fixed_nss, + u8 force_sgi) { struct ath10k *ar = arvif->ar; u32 vdev_param; @@ -3584,12 +3950,16 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif, mutex_lock(&ar->conf_mutex); if (arvif->fixed_rate == fixed_rate && - arvif->fixed_nss == fixed_nss) + arvif->fixed_nss == fixed_nss && + arvif->force_sgi == force_sgi) goto exit; if (fixed_rate == WMI_FIXED_RATE_NONE) ath10k_dbg(ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n"); + if (force_sgi) + ath10k_dbg(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); @@ -3615,6 +3985,19 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif, arvif->fixed_nss = fixed_nss; + vdev_param = ar->wmi.vdev_param->sgi; + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, + force_sgi); + + if (ret) { + ath10k_warn("Could not set sgi param %d: %d\n", + force_sgi, ret); + ret = -EINVAL; + goto exit; + } + + arvif->force_sgi = force_sgi; + exit: mutex_unlock(&ar->conf_mutex); return ret; @@ -3629,6 +4012,11 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw, enum ieee80211_band band = ar->hw->conf.chandef.chan->band; u8 fixed_rate = WMI_FIXED_RATE_NONE; u8 fixed_nss = ar->num_rf_chains; + u8 force_sgi; + + 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, @@ -3637,7 +4025,113 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw, return -EINVAL; } - return ath10k_set_fixed_rate_param(arvif, fixed_rate, fixed_nss); + if (fixed_rate == WMI_FIXED_RATE_NONE && force_sgi) { + ath10k_warn("Could not force SGI usage for default rate settings\n"); + return -EINVAL; + } + + return ath10k_set_fixed_rate_param(arvif, fixed_rate, + fixed_nss, force_sgi); +} + +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 u64 ath10k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + /* + * FIXME: Return 0 for time being. Need to figure out whether FW + * has the API to fetch 64-bit local TSF + */ + + return 0; } static const struct ieee80211_ops ath10k_ops = { @@ -3663,6 +4157,9 @@ static const struct ieee80211_ops ath10k_ops = { .restart_complete = ath10k_restart_complete, .get_survey = ath10k_get_survey, .set_bitrate_mask = ath10k_set_bitrate_mask, + .channel_switch_beacon = ath10k_channel_switch_beacon, + .sta_rc_update = ath10k_sta_rc_update, + .get_tsf = ath10k_get_tsf, #ifdef CONFIG_PM .suspend = ath10k_suspend, .resume = ath10k_resume, @@ -3939,7 +4436,7 @@ struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id) ath10k_get_arvif_iter, &arvif_iter); if (!arvif_iter.arvif) { - ath10k_warn("No VIF found for VDEV: %d\n", vdev_id); + ath10k_warn("No VIF found for vdev %d\n", vdev_id); return NULL; } @@ -4020,7 +4517,8 @@ int ath10k_mac_register(struct ath10k *ar) IEEE80211_HW_HAS_RATE_CONTROL | IEEE80211_HW_SUPPORTS_STATIC_SMPS | IEEE80211_HW_WANT_MONITOR_VIF | - IEEE80211_HW_AP_LINK_PS; + 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. */ @@ -4038,10 +4536,12 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN; 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->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; @@ -4076,7 +4576,7 @@ int ath10k_mac_register(struct ath10k *ar) ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy, ath10k_reg_notifier); if (ret) { - ath10k_err("Regulatory initialization failed\n"); + ath10k_err("Regulatory initialization failed: %i\n", ret); goto err_free; } diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 29fd197d1fd8..9d242d801d9d 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -58,13 +58,12 @@ static DEFINE_PCI_DEVICE_TABLE(ath10k_pci_id_table) = { static int ath10k_pci_diag_read_access(struct ath10k *ar, u32 address, u32 *data); -static void ath10k_pci_process_ce(struct ath10k *ar); 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_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_init_irq(struct ath10k *ar); static int ath10k_pci_deinit_irq(struct ath10k *ar); @@ -73,7 +72,6 @@ static void ath10k_pci_free_irq(struct ath10k *ar); static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, struct ath10k_ce_pipe *rx_pipe, struct bmi_xfer *xfer); -static void ath10k_pci_cleanup_ce(struct ath10k *ar); static const struct ce_attr host_ce_config_wlan[] = { /* CE0: host->target HTC control and raw streams */ @@ -678,34 +676,12 @@ void ath10k_do_pci_sleep(struct ath10k *ar) } } -/* - * FIXME: Handle OOM properly. - */ -static inline -struct ath10k_pci_compl *get_free_compl(struct ath10k_pci_pipe *pipe_info) -{ - struct ath10k_pci_compl *compl = NULL; - - spin_lock_bh(&pipe_info->pipe_lock); - if (list_empty(&pipe_info->compl_free)) { - ath10k_warn("Completion buffers are full\n"); - goto exit; - } - compl = list_first_entry(&pipe_info->compl_free, - struct ath10k_pci_compl, list); - list_del(&compl->list); -exit: - spin_unlock_bh(&pipe_info->pipe_lock); - return compl; -} - /* Called by lower (CE) layer when a send to Target completes. */ static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state) { struct ath10k *ar = ce_state->ar; struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id]; - struct ath10k_pci_compl *compl; + struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current; void *transfer_context; u32 ce_data; unsigned int nbytes; @@ -714,27 +690,12 @@ static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state) while (ath10k_ce_completed_send_next(ce_state, &transfer_context, &ce_data, &nbytes, &transfer_id) == 0) { - compl = get_free_compl(pipe_info); - if (!compl) - break; - - compl->state = ATH10K_PCI_COMPL_SEND; - compl->ce_state = ce_state; - compl->pipe_info = pipe_info; - compl->skb = transfer_context; - compl->nbytes = nbytes; - compl->transfer_id = transfer_id; - compl->flags = 0; + /* no need to call tx completion for NULL pointers */ + if (transfer_context == NULL) + continue; - /* - * Add the completion to the processing queue. - */ - spin_lock_bh(&ar_pci->compl_lock); - list_add_tail(&compl->list, &ar_pci->compl_process); - spin_unlock_bh(&ar_pci->compl_lock); + cb->tx_completion(ar, transfer_context, transfer_id); } - - ath10k_pci_process_ce(ar); } /* Called by lower (CE) layer when data is received from the Target. */ @@ -743,77 +704,100 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) struct ath10k *ar = ce_state->ar; struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id]; - struct ath10k_pci_compl *compl; + struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current; struct sk_buff *skb; void *transfer_context; u32 ce_data; - unsigned int nbytes; + unsigned int nbytes, max_nbytes; unsigned int transfer_id; unsigned int flags; + int err; while (ath10k_ce_completed_recv_next(ce_state, &transfer_context, &ce_data, &nbytes, &transfer_id, &flags) == 0) { - compl = get_free_compl(pipe_info); - if (!compl) - break; - - compl->state = ATH10K_PCI_COMPL_RECV; - compl->ce_state = ce_state; - compl->pipe_info = pipe_info; - compl->skb = transfer_context; - compl->nbytes = nbytes; - compl->transfer_id = transfer_id; - compl->flags = flags; + 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, - skb->len + skb_tailroom(skb), - DMA_FROM_DEVICE); - /* - * Add the completion to the processing queue. - */ - spin_lock_bh(&ar_pci->compl_lock); - list_add_tail(&compl->list, &ar_pci->compl_process); - spin_unlock_bh(&ar_pci->compl_lock); - } + max_nbytes, DMA_FROM_DEVICE); + + if (unlikely(max_nbytes < nbytes)) { + ath10k_warn("rxed more than expected (nbytes %d, max %d)", + nbytes, max_nbytes); + dev_kfree_skb_any(skb); + continue; + } - ath10k_pci_process_ce(ar); + skb_put(skb, nbytes); + cb->rx_completion(ar, skb, pipe_info->pipe_num); + } } -/* Send the first nbytes bytes of the buffer */ -static int ath10k_pci_hif_send_head(struct ath10k *ar, u8 pipe_id, - unsigned int transfer_id, - unsigned int bytes, struct sk_buff *nbuf) +static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, + struct ath10k_hif_sg_item *items, int n_items) { - struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(nbuf); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_pci_pipe *pipe_info = &(ar_pci->pipe_info[pipe_id]); - struct ath10k_ce_pipe *ce_hdl = pipe_info->ce_hdl; - unsigned int len; - u32 flags = 0; - int ret; + 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; - len = min(bytes, nbuf->len); - bytes -= len; + spin_lock_bh(&ar_pci->ce_lock); - if (len & 3) - ath10k_warn("skb not aligned to 4-byte boundary (%d)\n", len); + if (unlikely(CE_RING_DELTA(nentries_mask, + write_index, sw_index - 1) < n_items)) { + err = -ENOBUFS; + goto unlock; + } - ath10k_dbg(ATH10K_DBG_PCI, - "pci send data vaddr %p paddr 0x%llx len %d as %d bytes\n", - nbuf->data, (unsigned long long) skb_cb->paddr, - nbuf->len, len); - ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, - "ath10k tx: data: ", - nbuf->data, nbuf->len); - - ret = ath10k_ce_send(ce_hdl, nbuf, skb_cb->paddr, len, transfer_id, - flags); - if (ret) - ath10k_warn("failed to send sk_buff to CE: %p\n", nbuf); + for (i = 0; i < n_items - 1; i++) { + ath10k_dbg(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: ", + items[i].vaddr, items[i].len); - return ret; + err = ath10k_ce_send_nolock(ce_pipe, + items[i].transfer_context, + items[i].paddr, + items[i].len, + items[i].transfer_id, + CE_SEND_FLAG_GATHER); + if (err) + goto unlock; + } + + /* `i` is equal to `n_items -1` after for() */ + + ath10k_dbg(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: ", + items[i].vaddr, items[i].len); + + err = ath10k_ce_send_nolock(ce_pipe, + items[i].transfer_context, + items[i].paddr, + items[i].len, + items[i].transfer_id, + 0); + if (err) + goto unlock; + + err = 0; +unlock: + spin_unlock_bh(&ar_pci->ce_lock); + return err; } static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe) @@ -833,9 +817,7 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar) 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: %u.%u.%u.%u\n", ar->fw_version_major, - ar->fw_version_minor, ar->fw_version_release, - ar->fw_version_build); + 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, @@ -904,52 +886,6 @@ static void ath10k_pci_hif_set_callbacks(struct ath10k *ar, sizeof(ar_pci->msg_callbacks_current)); } -static int ath10k_pci_alloc_compl(struct ath10k *ar) -{ - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - const struct ce_attr *attr; - struct ath10k_pci_pipe *pipe_info; - struct ath10k_pci_compl *compl; - int i, pipe_num, completions; - - spin_lock_init(&ar_pci->compl_lock); - INIT_LIST_HEAD(&ar_pci->compl_process); - - for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { - pipe_info = &ar_pci->pipe_info[pipe_num]; - - spin_lock_init(&pipe_info->pipe_lock); - INIT_LIST_HEAD(&pipe_info->compl_free); - - /* Handle Diagnostic CE specially */ - if (pipe_info->ce_hdl == ar_pci->ce_diag) - continue; - - attr = &host_ce_config_wlan[pipe_num]; - completions = 0; - - if (attr->src_nentries) - completions += attr->src_nentries; - - if (attr->dest_nentries) - completions += attr->dest_nentries; - - for (i = 0; i < completions; i++) { - compl = kmalloc(sizeof(*compl), GFP_KERNEL); - if (!compl) { - ath10k_warn("No memory for completion state\n"); - ath10k_pci_cleanup_ce(ar); - return -ENOMEM; - } - - compl->state = ATH10K_PCI_COMPL_FREE; - list_add_tail(&compl->list, &pipe_info->compl_free); - } - } - - return 0; -} - static int ath10k_pci_setup_ce_irq(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); @@ -994,147 +930,6 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar) tasklet_kill(&ar_pci->pipe_info[i].intr); } -static void ath10k_pci_stop_ce(struct ath10k *ar) -{ - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_pci_compl *compl; - struct sk_buff *skb; - - /* Mark pending completions as aborted, so that upper layers free up - * their associated resources */ - spin_lock_bh(&ar_pci->compl_lock); - list_for_each_entry(compl, &ar_pci->compl_process, list) { - skb = compl->skb; - ATH10K_SKB_CB(skb)->is_aborted = true; - } - spin_unlock_bh(&ar_pci->compl_lock); -} - -static void ath10k_pci_cleanup_ce(struct ath10k *ar) -{ - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_pci_compl *compl, *tmp; - struct ath10k_pci_pipe *pipe_info; - struct sk_buff *netbuf; - int pipe_num; - - /* Free pending completions. */ - spin_lock_bh(&ar_pci->compl_lock); - if (!list_empty(&ar_pci->compl_process)) - ath10k_warn("pending completions still present! possible memory leaks.\n"); - - list_for_each_entry_safe(compl, tmp, &ar_pci->compl_process, list) { - list_del(&compl->list); - netbuf = compl->skb; - dev_kfree_skb_any(netbuf); - kfree(compl); - } - spin_unlock_bh(&ar_pci->compl_lock); - - /* Free unused completions for each pipe. */ - for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { - pipe_info = &ar_pci->pipe_info[pipe_num]; - - spin_lock_bh(&pipe_info->pipe_lock); - list_for_each_entry_safe(compl, tmp, - &pipe_info->compl_free, list) { - list_del(&compl->list); - kfree(compl); - } - spin_unlock_bh(&pipe_info->pipe_lock); - } -} - -static void ath10k_pci_process_ce(struct ath10k *ar) -{ - struct ath10k_pci *ar_pci = ar->hif.priv; - struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current; - struct ath10k_pci_compl *compl; - struct sk_buff *skb; - unsigned int nbytes; - int ret, send_done = 0; - - /* Upper layers aren't ready to handle tx/rx completions in parallel so - * we must serialize all completion processing. */ - - spin_lock_bh(&ar_pci->compl_lock); - if (ar_pci->compl_processing) { - spin_unlock_bh(&ar_pci->compl_lock); - return; - } - ar_pci->compl_processing = true; - spin_unlock_bh(&ar_pci->compl_lock); - - for (;;) { - spin_lock_bh(&ar_pci->compl_lock); - if (list_empty(&ar_pci->compl_process)) { - spin_unlock_bh(&ar_pci->compl_lock); - break; - } - compl = list_first_entry(&ar_pci->compl_process, - struct ath10k_pci_compl, list); - list_del(&compl->list); - spin_unlock_bh(&ar_pci->compl_lock); - - switch (compl->state) { - case ATH10K_PCI_COMPL_SEND: - cb->tx_completion(ar, - compl->skb, - compl->transfer_id); - send_done = 1; - break; - case ATH10K_PCI_COMPL_RECV: - ret = ath10k_pci_post_rx_pipe(compl->pipe_info, 1); - if (ret) { - ath10k_warn("failed to post RX buffer for pipe %d: %d\n", - compl->pipe_info->pipe_num, ret); - break; - } - - skb = compl->skb; - nbytes = compl->nbytes; - - ath10k_dbg(ATH10K_DBG_PCI, - "ath10k_pci_ce_recv_data netbuf=%p nbytes=%d\n", - skb, nbytes); - ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, - "ath10k rx: ", skb->data, nbytes); - - if (skb->len + skb_tailroom(skb) >= nbytes) { - skb_trim(skb, 0); - skb_put(skb, nbytes); - cb->rx_completion(ar, skb, - compl->pipe_info->pipe_num); - } else { - ath10k_warn("rxed more than expected (nbytes %d, max %d)", - nbytes, - skb->len + skb_tailroom(skb)); - } - break; - case ATH10K_PCI_COMPL_FREE: - ath10k_warn("free completion cannot be processed\n"); - break; - default: - ath10k_warn("invalid completion state (%d)\n", - compl->state); - break; - } - - compl->state = ATH10K_PCI_COMPL_FREE; - - /* - * Add completion back to the pipe's free list. - */ - spin_lock_bh(&compl->pipe_info->pipe_lock); - list_add_tail(&compl->list, &compl->pipe_info->compl_free); - spin_unlock_bh(&compl->pipe_info->pipe_lock); - } - - spin_lock_bh(&ar_pci->compl_lock); - ar_pci->compl_processing = false; - spin_unlock_bh(&ar_pci->compl_lock); -} - /* 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, @@ -1306,17 +1101,11 @@ static int ath10k_pci_hif_start(struct ath10k *ar) ath10k_pci_free_early_irq(ar); ath10k_pci_kill_tasklet(ar); - ret = ath10k_pci_alloc_compl(ar); - if (ret) { - ath10k_warn("failed to allocate CE completions: %d\n", ret); - goto err_early_irq; - } - ret = ath10k_pci_request_irq(ar); if (ret) { ath10k_warn("failed to post RX buffers for all pipes: %d\n", ret); - goto err_free_compl; + goto err_early_irq; } ret = ath10k_pci_setup_ce_irq(ar); @@ -1340,10 +1129,6 @@ err_stop: ath10k_ce_disable_interrupts(ar); ath10k_pci_free_irq(ar); ath10k_pci_kill_tasklet(ar); - ath10k_pci_stop_ce(ar); - ath10k_pci_process_ce(ar); -err_free_compl: - ath10k_pci_cleanup_ce(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 @@ -1414,18 +1199,10 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info) while (ath10k_ce_cancel_send_next(ce_hdl, (void **)&netbuf, &ce_data, &nbytes, &id) == 0) { - /* - * Indicate the completion to higer layer to free - * the buffer - */ - - if (!netbuf) { - ath10k_warn("invalid sk_buff on CE %d - NULL pointer. firmware crashed?\n", - ce_hdl->id); + /* no need to call tx completion for NULL pointers */ + if (!netbuf) continue; - } - ATH10K_SKB_CB(netbuf)->is_aborted = true; ar_pci->msg_callbacks_current.tx_completion(ar, netbuf, id); @@ -1483,7 +1260,6 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) ath10k_pci_free_irq(ar); ath10k_pci_kill_tasklet(ar); - ath10k_pci_stop_ce(ar); ret = ath10k_pci_request_early_irq(ar); if (ret) @@ -1493,8 +1269,6 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) * not DMA nor interrupt. We process the leftovers and then free * everything else up. */ - ath10k_pci_process_ce(ar); - ath10k_pci_cleanup_ce(ar); ath10k_pci_buffer_cleanup(ar); /* Make the sure the device won't access any structures on the host by @@ -1502,7 +1276,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) * configuration during init. If ringbuffers are freed and the device * were to access them this could lead to memory corruption on the * host. */ - ath10k_pci_device_reset(ar); + ath10k_pci_warm_reset(ar); ar_pci->started = 0; } @@ -1993,7 +1767,94 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *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); const char *irq_mode; @@ -2009,7 +1870,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 * 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) { ath10k_err("failed to reset target: %d\n", ret); goto err; @@ -2079,7 +1944,7 @@ err_deinit_irq: ath10k_pci_deinit_irq(ar); err_ce: ath10k_pci_ce_deinit(ar); - ath10k_pci_device_reset(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); @@ -2087,6 +1952,34 @@ err: 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) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); @@ -2094,7 +1987,7 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar) ath10k_pci_free_early_irq(ar); ath10k_pci_kill_tasklet(ar); ath10k_pci_deinit_irq(ar); - ath10k_pci_device_reset(ar); + ath10k_pci_warm_reset(ar); ath10k_pci_ce_deinit(ar); if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) @@ -2151,7 +2044,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar) #endif static const struct ath10k_hif_ops ath10k_pci_hif_ops = { - .send_head = ath10k_pci_hif_send_head, + .tx_sg = ath10k_pci_hif_tx_sg, .exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg, .start = ath10k_pci_hif_start, .stop = ath10k_pci_hif_stop, @@ -2411,11 +2304,10 @@ static int ath10k_pci_init_irq(struct ath10k *ar) /* Try MSI-X */ if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO && msix_supported) { ar_pci->num_msi_intrs = MSI_NUM_REQUEST; - ret = pci_enable_msi_block(ar_pci->pdev, ar_pci->num_msi_intrs); - if (ret == 0) - return 0; + ret = pci_enable_msi_range(ar_pci->pdev, ar_pci->num_msi_intrs, + ar_pci->num_msi_intrs); if (ret > 0) - pci_disable_msi(ar_pci->pdev); + return 0; /* fall-through */ } @@ -2482,6 +2374,8 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar) case MSI_NUM_REQUEST: pci_disable_msi(ar_pci->pdev); return 0; + default: + pci_disable_msi(ar_pci->pdev); } ath10k_warn("unknown irq configuration upon deinit\n"); @@ -2523,7 +2417,7 @@ out: return ret; } -static int ath10k_pci_device_reset(struct ath10k *ar) +static int ath10k_pci_cold_reset(struct ath10k *ar) { int i, ret; u32 val; diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index a4f32038c440..b43fdb4f7319 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -43,23 +43,6 @@ struct bmi_xfer { u32 resp_len; }; -enum ath10k_pci_compl_state { - ATH10K_PCI_COMPL_FREE = 0, - ATH10K_PCI_COMPL_SEND, - ATH10K_PCI_COMPL_RECV, -}; - -struct ath10k_pci_compl { - struct list_head list; - enum ath10k_pci_compl_state state; - struct ath10k_ce_pipe *ce_state; - struct ath10k_pci_pipe *pipe_info; - struct sk_buff *skb; - unsigned int nbytes; - unsigned int transfer_id; - unsigned int flags; -}; - /* * PCI-specific Target state * @@ -175,9 +158,6 @@ struct ath10k_pci_pipe { /* protects compl_free and num_send_allowed */ spinlock_t pipe_lock; - /* List of free CE completion slots */ - struct list_head compl_free; - struct ath10k_pci *ar_pci; struct tasklet_struct intr; }; @@ -205,14 +185,6 @@ struct ath10k_pci { atomic_t keep_awake_count; bool verified_awake; - /* List of CE completions to be processed */ - struct list_head compl_process; - - /* protects compl_processing and compl_process */ - spinlock_t compl_lock; - - bool compl_processing; - struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX]; struct ath10k_hif_cb msg_callbacks_current; diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 74f45fa6f428..0541dd939ce9 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -51,7 +51,8 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, struct ieee80211_tx_info *info; struct ath10k_skb_cb *skb_cb; struct sk_buff *msdu; - int ret; + + lockdep_assert_held(&htt->tx_lock); ath10k_dbg(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); @@ -65,12 +66,12 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, msdu = htt->pending_tx[tx_done->msdu_id]; skb_cb = ATH10K_SKB_CB(msdu); - ret = ath10k_skb_unmap(dev, msdu); - if (ret) - ath10k_warn("data skb unmap failed (%d)\n", ret); + dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); - if (skb_cb->htt.frag_len) - skb_pull(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len); + if (skb_cb->htt.txbuf) + dma_pool_free(htt->tx_pool, + skb_cb->htt.txbuf, + skb_cb->htt.txbuf_paddr); ath10k_report_offchan_tx(htt->ar, msdu); @@ -92,13 +93,11 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, /* we do not own the msdu anymore */ exit: - spin_lock_bh(&htt->tx_lock); 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) wake_up(&htt->empty_tx_wq); - spin_unlock_bh(&htt->tx_lock); } static const u8 rx_legacy_rate_idx[] = { @@ -204,7 +203,7 @@ static void process_rx_rates(struct ath10k *ar, struct htt_rx_info *info, break; /* 80MHZ */ case 2: - status->flag |= RX_FLAG_80MHZ; + status->vht_flag |= RX_VHT_FLAG_80MHZ; } status->flag |= RX_FLAG_VHT; @@ -258,20 +257,26 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info) status->band = ch->band; status->freq = ch->center_freq; + if (info->rate.info0 & HTT_RX_INDICATION_INFO0_END_VALID) { + /* TSF available only in 32-bit */ + status->mactime = info->tsf & 0xffffffff; + status->flag |= RX_FLAG_MACTIME_END; + } + 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->len, status->flag == 0 ? "legacy" : "", status->flag & RX_FLAG_HT ? "ht" : "", status->flag & RX_FLAG_VHT ? "vht" : "", status->flag & RX_FLAG_40MHZ ? "40" : "", - status->flag & RX_FLAG_80MHZ ? "80" : "", + status->vht_flag & RX_VHT_FLAG_80MHZ ? "80" : "", status->flag & RX_FLAG_SHORT_GI ? "sgi " : "", status->rate_idx, status->vht_nss, status->freq, - status->band); + status->band, status->flag, info->fcs_err); ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ", info->skb->data, info->skb->len); @@ -378,7 +383,8 @@ void ath10k_peer_unmap_event(struct ath10k_htt *htt, spin_lock_bh(&ar->data_lock); peer = ath10k_peer_find_by_id(ar, ev->peer_id); if (!peer) { - ath10k_warn("unknown peer id %d\n", ev->peer_id); + ath10k_warn("peer-unmap-event: unknown peer id %d\n", + ev->peer_id); goto exit; } diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 712a606a080a..cb1f7b5bcf4c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -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_probe_resp_ie = WMI_10X_P2P_GO_SET_PROBE_RESP_IE, .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, .peer_rate_retry_sched_cmdid = WMI_10X_PEER_RATE_RETRY_SCHED_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 = { .bcnflt_stats_update_period = WMI_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, .pmf_qos = WMI_PDEV_PARAM_PMF_QOS, .arp_ac_override = WMI_PDEV_PARAM_ARP_AC_OVERRIDE, - .arpdhcp_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, .dcs = WMI_PDEV_PARAM_DCS, .ani_enable = WMI_PDEV_PARAM_ANI_ENABLE, .ani_poll_period = WMI_PDEV_PARAM_ANI_POLL_PERIOD, @@ -472,8 +471,7 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { .bcnflt_stats_update_period = WMI_10X_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, .pmf_qos = WMI_10X_PDEV_PARAM_PMF_QOS, - .arp_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, - .arpdhcp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE, + .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, @@ -561,7 +559,6 @@ err_pull: static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) { - struct wmi_bcn_tx_arg arg = {0}; int ret; lockdep_assert_held(&arvif->ar->data_lock); @@ -569,18 +566,16 @@ static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) if (arvif->beacon == NULL) return; - arg.vdev_id = arvif->vdev_id; - arg.tx_rate = 0; - arg.tx_power = 0; - arg.bcn = arvif->beacon->data; - arg.bcn_len = arvif->beacon->len; + if (arvif->beacon_sent) + return; - ret = ath10k_wmi_beacon_send_nowait(arvif->ar, &arg); + ret = ath10k_wmi_beacon_send_ref_nowait(arvif); if (ret) return; - dev_kfree_skb_any(arvif->beacon); - arvif->beacon = NULL; + /* We need to retain the arvif->beacon reference for DMA unmapping and + * freeing the skbuff later. */ + arvif->beacon_sent = true; } 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, static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, 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, tim->bitmap_ctrl = !!__le32_to_cpu(bcn_info->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(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", tim->dtim_count, tim->dtim_period, tim->bitmap_ctrl, pvm_len); @@ -1338,7 +1360,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) struct wmi_bcn_info *bcn_info; struct ath10k_vif *arvif; struct sk_buff *bcn; - int vdev_id = 0; + int ret, vdev_id = 0; ath10k_dbg(ATH10K_DBG_MGMT, "WMI_HOST_SWBA_EVENTID\n"); @@ -1385,6 +1407,17 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) 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); if (!bcn) { ath10k_warn("could not get mac80211 beacon\n"); @@ -1396,15 +1429,33 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info); spin_lock_bh(&ar->data_lock); + if (arvif->beacon) { - ath10k_warn("SWBA overrun on vdev %d\n", - arvif->vdev_id); + if (!arvif->beacon_sent) + ath10k_warn("SWBA overrun on vdev %d\n", + arvif->vdev_id); + + dma_unmap_single(arvif->ar->dev, + ATH10K_SKB_CB(arvif->beacon)->paddr, + arvif->beacon->len, DMA_TO_DEVICE); dev_kfree_skb_any(arvif->beacon); } + 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); + goto skip; + } + arvif->beacon = bcn; + arvif->beacon_sent = false; ath10k_wmi_tx_beacon_nowait(arvif); +skip: spin_unlock_bh(&ar->data_lock); } } @@ -2031,11 +2082,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); 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->abi_version), ev->mac_addr.addr, - __le32_to_cpu(ev->status)); + __le32_to_cpu(ev->status), skb->len, sizeof(*ev)); complete(&ar->wmi.unified_ready); return 0; @@ -2403,7 +2454,7 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar, 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 sk_buff *skb; @@ -2413,7 +2464,7 @@ int ath10k_wmi_pdev_suspend_target(struct ath10k *ar) return -ENOMEM; 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); } @@ -3342,7 +3393,6 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar, ci->max_power = ch->max_power; ci->reg_power = ch->max_reg_power; ci->antenna_max = ch->max_antenna_gain; - ci->antenna_max = 0; /* mode & flags share storage */ ci->mode = ch->mode; @@ -3411,25 +3461,41 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar, return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid); } -int ath10k_wmi_beacon_send_nowait(struct ath10k *ar, - const struct wmi_bcn_tx_arg *arg) +/* This function assumes the beacon is already DMA mapped */ +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 *beacon = arvif->beacon; + struct ath10k *ar = arvif->ar; + struct ieee80211_hdr *hdr; int ret; + u16 fc; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd) + arg->bcn_len); + skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); if (!skb) return -ENOMEM; - cmd = (struct wmi_bcn_tx_cmd *)skb->data; - cmd->hdr.vdev_id = __cpu_to_le32(arg->vdev_id); - cmd->hdr.tx_rate = __cpu_to_le32(arg->tx_rate); - cmd->hdr.tx_power = __cpu_to_le32(arg->tx_power); - cmd->hdr.bcn_len = __cpu_to_le32(arg->bcn_len); - memcpy(cmd->bcn, arg->bcn, arg->bcn_len); + hdr = (struct ieee80211_hdr *)beacon->data; + 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->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) dev_kfree_skb(skb); diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 4b5e7d3d32b6..4fcc96aa9513 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2277,7 +2277,6 @@ struct wmi_pdev_param_map { u32 bcnflt_stats_update_period; u32 pmf_qos; u32 arp_ac_override; - u32 arpdhcp_ac_override; u32 dcs; u32 ani_enable; u32 ani_poll_period; @@ -3403,6 +3402,24 @@ struct wmi_bcn_tx_arg { 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 */ #define WMI_BCN_FILTER_ALL 0 /* Filter all beacons */ #define WMI_BCN_FILTER_NONE 1 /* Pass all beacons */ @@ -3859,6 +3876,12 @@ enum wmi_peer_smps_state { 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 { WMI_PEER_SMPS_STATE = 0x1, /* see %wmi_peer_smps_state */ WMI_PEER_AMPDU = 0x2, @@ -4039,6 +4062,10 @@ struct wmi_chan_info_event { __le32 cycle_count; } __packed; +struct wmi_peer_sta_kickout_event { + struct wmi_mac_addr peer_macaddr; +} __packed; + #define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0) /* FIXME: empirically extrapolated */ @@ -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_pdev_set_channel(struct ath10k *ar, 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_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, 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, 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_nowait(struct ath10k *ar, - const struct wmi_bcn_tx_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); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index ef35da84f63b..4b18434ba697 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -751,6 +751,9 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf, bf->skbaddr = dma_map_single(ah->dev, skb->data, skb->len, DMA_TO_DEVICE); + if (dma_mapping_error(ah->dev, bf->skbaddr)) + return -ENOSPC; + ieee80211_get_tx_rates(info->control.vif, (control) ? control->sta : NULL, skb, bf->rates, ARRAY_SIZE(bf->rates)); diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 4ee01f654235..afb23b3cc7be 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -681,6 +681,7 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) survey->channel = conf->chandef.chan; survey->noise = ah->ah_noise_floor; survey->filled = SURVEY_INFO_NOISE_DBM | + SURVEY_INFO_IN_USE | SURVEY_INFO_CHANNEL_TIME | SURVEY_INFO_CHANNEL_TIME_BUSY | SURVEY_INFO_CHANNEL_TIME_RX | diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index fd4c89df67e1..c2c6f4604958 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -790,7 +790,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, if (nw_type & ADHOC_NETWORK) { ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n", nw_type & ADHOC_CREATOR ? "creator" : "joiner"); - cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL); + cfg80211_ibss_joined(vif->ndev, bssid, chan, GFP_KERNEL); cfg80211_put_bss(ar->wiphy, bss); return; } @@ -861,13 +861,9 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason, } if (vif->nw_type & ADHOC_NETWORK) { - if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) { + if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: ath6k not in ibss mode\n", __func__); - return; - } - memset(bssid, 0, ETH_ALEN); - cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL); return; } @@ -3256,6 +3252,15 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, struct ath6kl_vif *vif = netdev_priv(dev); u16 interval; int ret, rssi_thold; + int n_match_sets = request->n_match_sets; + + /* + * If there's a matchset w/o an SSID, then assume it's just for + * the RSSI (nothing else is currently supported) and ignore it. + * The device only supports a global RSSI filter that we set below. + */ + if (n_match_sets == 1 && !request->match_sets[0].ssid.ssid_len) + n_match_sets = 0; if (ar->state != ATH6KL_STATE_ON) return -EIO; @@ -3268,11 +3273,11 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, ret = ath6kl_set_probed_ssids(ar, vif, request->ssids, request->n_ssids, request->match_sets, - request->n_match_sets); + n_match_sets); if (ret < 0) return ret; - if (!request->n_match_sets) { + if (!n_match_sets) { ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, ALL_BSS_FILTER, 0); if (ret < 0) @@ -3286,12 +3291,12 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD, ar->fw_capabilities)) { - if (request->rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF) + if (request->min_rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF) rssi_thold = 0; - else if (request->rssi_thold < -127) + else if (request->min_rssi_thold < -127) rssi_thold = -127; else - rssi_thold = request->rssi_thold; + rssi_thold = request->min_rssi_thold; ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx, rssi_thold); diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index f38ff6a6255e..56c3fd5cef65 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -24,7 +24,7 @@ /* constants */ #define TX_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 */ enum ATH6KL_USB_PIPE_ID { @@ -481,8 +481,8 @@ static void ath6kl_usb_start_recv_pipes(struct ath6kl_usb *ar_usb) * 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_alloc / 2; + ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_cnt_thresh = 1; + ath6kl_usb_post_recv_transfers(&ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA], ATH6KL_USB_RX_BUFFER_SIZE); } diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 4f16d79c9eb1..8b4ce28e3ce8 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -914,7 +914,7 @@ ath6kl_get_regpair(u16 regdmn) return NULL; for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { - if (regDomainPairs[i].regDmnEnum == regdmn) + if (regDomainPairs[i].reg_domain == regdmn) return ®DomainPairs[i]; } @@ -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); if (regpair) ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n", - regpair->regDmnEnum); + regpair->reg_domain); else ath6kl_warn("Regpair not found reg_code 0x%0x\n", reg_code); diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 7b96b3e5712d..8fcc029a76a6 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -120,18 +120,6 @@ config ATH9K_WOW This option enables Wake on Wireless LAN support for certain cards. Currently, AR9462 is supported. -config ATH9K_LEGACY_RATE_CONTROL - bool "Atheros ath9k rate control" - depends on ATH9K - default n - ---help--- - Say Y, if you want to use the ath9k specific rate control - module instead of minstrel_ht. Be warned that there are various - issues with the ath9k RC and minstrel is a more robust algorithm. - Note that even if this option is selected, "ath9k_rate_control" - has to be passed to mac80211 using the module parameter, - ieee80211_default_rc_algo. - config ATH9K_RFKILL bool "Atheros ath9k rfkill support" if EXPERT depends on ATH9K diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index a40e5c5d7418..8e1c7b0fe76c 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -8,7 +8,6 @@ ath9k-y += beacon.o \ antenna.o ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o -ath9k-$(CONFIG_ATH9K_LEGACY_RATE_CONTROL) += rc.o ath9k-$(CONFIG_ATH9K_PCI) += pci.o ath9k-$(CONFIG_ATH9K_AHB) += ahb.o ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o @@ -52,7 +51,9 @@ ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \ obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o -ath9k_common-y:= common.o +ath9k_common-y:= common.o \ + common-init.o \ + common-beacon.o ath9k_htc-y += htc_hst.o \ hif_usb.o \ diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 2dff2765769b..a0398fe3eb28 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -39,6 +39,10 @@ static const struct platform_device_id ath9k_platform_id_table[] = { .name = "qca955x_wmac", .driver_data = AR9300_DEVID_QCA955X, }, + { + .name = "qca953x_wmac", + .driver_data = AR9300_DEVID_AR953X, + }, {}, }; @@ -82,6 +86,7 @@ static int ath_ahb_probe(struct platform_device *pdev) int irq; int ret = 0; struct ath_hw *ah; + struct ath_common *common; char hw_name[64]; if (!dev_get_platdata(&pdev->dev)) { @@ -124,9 +129,6 @@ static int ath_ahb_probe(struct platform_device *pdev) sc->mem = mem; sc->irq = irq; - /* Will be cleared in ath9k_start() */ - set_bit(SC_OP_INVALID, &sc->sc_flags); - ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc); if (ret) { dev_err(&pdev->dev, "request_irq failed\n"); @@ -144,6 +146,9 @@ static int ath_ahb_probe(struct platform_device *pdev) wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n", hw_name, (unsigned long)mem, irq); + common = ath9k_hw_common(sc->sc_ah); + /* Will be cleared in ath9k_start() */ + set_bit(ATH_OP_INVALID, &common->op_flags); return 0; err_irq: diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index d28923b7435b..6d47783f2e5b 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -176,16 +176,26 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel, if (ah->opmode == NL80211_IFTYPE_STATION && BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_HIGH) weak_sig = true; - /* - * OFDM Weak signal detection is always enabled for AP mode. + * Newer chipsets are better at dealing with high PHY error counts - + * keep weak signal detection enabled when no RSSI threshold is + * available to determine if it is needed (mode != STA) */ - if (ah->opmode != NL80211_IFTYPE_AP && - aniState->ofdmWeakSigDetect != weak_sig) { - ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - entry_ofdm->ofdm_weak_signal_on); - } + else if (AR_SREV_9300_20_OR_LATER(ah) && + ah->opmode != NL80211_IFTYPE_STATION) + weak_sig = true; + + /* Older chipsets are more sensitive to high PHY error counts */ + else if (!AR_SREV_9300_20_OR_LATER(ah) && + aniState->ofdmNoiseImmunityLevel >= 8) + weak_sig = false; + + if (aniState->ofdmWeakSigDetect != weak_sig) + ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + weak_sig); + + if (!AR_SREV_9300_20_OR_LATER(ah)) + return; if (aniState->ofdmNoiseImmunityLevel >= ATH9K_ANI_OFDM_DEF_LEVEL) { ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; @@ -308,17 +318,6 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) BUG_ON(aniState == NULL); ah->stats.ast_ani_reset++; - /* only allow a subset of functions in AP mode */ - if (ah->opmode == NL80211_IFTYPE_AP) { - if (IS_CHAN_2GHZ(chan)) { - ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | - ATH9K_ANI_FIRSTEP_LEVEL); - if (AR_SREV_9300_20_OR_LATER(ah)) - ah->ani_function |= ATH9K_ANI_MRC_CCK; - } else - ah->ani_function = 0; - } - ofdm_nil = max_t(int, ATH9K_ANI_OFDM_DEF_LEVEL, aniState->ofdmNoiseImmunityLevel); cck_nil = max_t(int, ATH9K_ANI_CCK_DEF_LEVEL, @@ -483,10 +482,17 @@ void ath9k_hw_ani_init(struct ath_hw *ah) ath_dbg(common, ANI, "Initialize ANI\n"); - ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; - ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW; - ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH; - ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW; + if (AR_SREV_9300_20_OR_LATER(ah)) { + ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; + ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW; + ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH; + ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW; + } else { + ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD; + ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD; + ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD; + ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD; + } ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index 21e7b83c3f6a..c40965b4c1e2 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -22,12 +22,16 @@ /* units are errors per second */ #define ATH9K_ANI_OFDM_TRIG_HIGH 3500 #define ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI 1000 +#define ATH9K_ANI_OFDM_TRIG_HIGH_OLD 500 #define ATH9K_ANI_OFDM_TRIG_LOW 400 #define ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI 900 +#define ATH9K_ANI_OFDM_TRIG_LOW_OLD 200 #define ATH9K_ANI_CCK_TRIG_HIGH 600 +#define ATH9K_ANI_CCK_TRIG_HIGH_OLD 200 #define ATH9K_ANI_CCK_TRIG_LOW 300 +#define ATH9K_ANI_CCK_TRIG_LOW_OLD 100 #define ATH9K_ANI_SPUR_IMMUNE_LVL 3 #define ATH9K_ANI_FIRSTEP_LVL 2 diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index ff415e863ee9..00fb8badbacc 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -26,10 +26,6 @@ static const int firstep_table[] = /* level: 0 1 2 3 4 5 6 7 8 */ { -4, -2, 0, 2, 4, 6, 8, 10, 12 }; /* lvl 0-8, default 2 */ -static const int cycpwrThr1_table[] = -/* level: 0 1 2 3 4 5 6 7 8 */ - { -6, -4, -2, 0, 2, 4, 6, 8 }; /* lvl 0-7, default 3 */ - /* * register values to turn OFDM weak signal detection OFF */ @@ -921,7 +917,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, struct ath_common *common = ath9k_hw_common(ah); struct ath9k_channel *chan = ah->curchan; struct ar5416AniState *aniState = &ah->ani; - s32 value, value2; + s32 value; switch (cmd & ah->ani_function) { case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{ @@ -1008,42 +1004,9 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, case ATH9K_ANI_FIRSTEP_LEVEL:{ u32 level = param; - if (level >= ARRAY_SIZE(firstep_table)) { - ath_dbg(common, ANI, - "ATH9K_ANI_FIRSTEP_LEVEL: level out of range (%u > %zu)\n", - level, ARRAY_SIZE(firstep_table)); - return false; - } - - /* - * make register setting relative to default - * from INI file & cap value - */ - value = firstep_table[level] - - firstep_table[ATH9K_ANI_FIRSTEP_LVL] + - aniState->iniDef.firstep; - if (value < ATH9K_SIG_FIRSTEP_SETTING_MIN) - value = ATH9K_SIG_FIRSTEP_SETTING_MIN; - if (value > ATH9K_SIG_FIRSTEP_SETTING_MAX) - value = ATH9K_SIG_FIRSTEP_SETTING_MAX; + value = level; REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, - AR_PHY_FIND_SIG_FIRSTEP, - value); - /* - * we need to set first step low register too - * make register setting relative to default - * from INI file & cap value - */ - value2 = firstep_table[level] - - firstep_table[ATH9K_ANI_FIRSTEP_LVL] + - aniState->iniDef.firstepLow; - if (value2 < ATH9K_SIG_FIRSTEP_SETTING_MIN) - value2 = ATH9K_SIG_FIRSTEP_SETTING_MIN; - if (value2 > ATH9K_SIG_FIRSTEP_SETTING_MAX) - value2 = ATH9K_SIG_FIRSTEP_SETTING_MAX; - - REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW, - AR_PHY_FIND_SIG_FIRSTEP_LOW, value2); + AR_PHY_FIND_SIG_FIRSTEP, value); if (level != aniState->firstepLevel) { ath_dbg(common, ANI, @@ -1060,7 +1023,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, aniState->firstepLevel, level, ATH9K_ANI_FIRSTEP_LVL, - value2, + value, aniState->iniDef.firstepLow); if (level > aniState->firstepLevel) ah->stats.ast_ani_stepup++; @@ -1073,41 +1036,13 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{ u32 level = param; - if (level >= ARRAY_SIZE(cycpwrThr1_table)) { - ath_dbg(common, ANI, - "ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level out of range (%u > %zu)\n", - level, ARRAY_SIZE(cycpwrThr1_table)); - return false; - } - /* - * make register setting relative to default - * from INI file & cap value - */ - value = cycpwrThr1_table[level] - - cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] + - aniState->iniDef.cycpwrThr1; - if (value < ATH9K_SIG_SPUR_IMM_SETTING_MIN) - value = ATH9K_SIG_SPUR_IMM_SETTING_MIN; - if (value > ATH9K_SIG_SPUR_IMM_SETTING_MAX) - value = ATH9K_SIG_SPUR_IMM_SETTING_MAX; + value = (level + 1) * 2; REG_RMW_FIELD(ah, AR_PHY_TIMING5, - AR_PHY_TIMING5_CYCPWR_THR1, - value); + AR_PHY_TIMING5_CYCPWR_THR1, value); - /* - * set AR_PHY_EXT_CCA for extension channel - * make register setting relative to default - * from INI file & cap value - */ - value2 = cycpwrThr1_table[level] - - cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] + - aniState->iniDef.cycpwrThr1Ext; - if (value2 < ATH9K_SIG_SPUR_IMM_SETTING_MIN) - value2 = ATH9K_SIG_SPUR_IMM_SETTING_MIN; - if (value2 > ATH9K_SIG_SPUR_IMM_SETTING_MAX) - value2 = ATH9K_SIG_SPUR_IMM_SETTING_MAX; - REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, - AR_PHY_EXT_TIMING5_CYCPWR_THR1, value2); + if (IS_CHAN_HT40(ah->curchan)) + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, + AR_PHY_EXT_TIMING5_CYCPWR_THR1, value); if (level != aniState->spurImmunityLevel) { ath_dbg(common, ANI, @@ -1124,7 +1059,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, aniState->spurImmunityLevel, level, ATH9K_ANI_SPUR_IMMUNE_LVL, - value2, + value, aniState->iniDef.cycpwrThr1Ext); if (level > aniState->spurImmunityLevel) ah->stats.ast_ani_spurup++; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index a352128c40ad..ac8301ef5242 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -23,10 +23,11 @@ #define MAX_MEASUREMENT MAX_IQCAL_MEASUREMENT #define MAX_MAG_DELTA 11 #define MAX_PHS_DELTA 10 +#define MAXIQCAL 3 struct coeff { - int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; - int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; + int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL]; + int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL]; int iqc_coeff[2]; }; @@ -655,9 +656,6 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, if (i2_m_q2_a0_d1 > 0x800) i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1); - if (i2_p_q2_a0_d1 > 0x1000) - i2_p_q2_a0_d1 = -((0x1fff - i2_p_q2_a0_d1) + 1); - if (iq_corr_a0_d1 > 0x800) iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1); @@ -800,7 +798,7 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, if (q_q_coff > 63) q_q_coff = 63; - iqc_coeff[0] = (q_q_coff * 128) + q_i_coff; + iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff); ath_dbg(common, CALIBRATE, "tx chain %d: iq corr coeff=%x\n", chain_idx, iqc_coeff[0]); @@ -831,7 +829,7 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, if (q_q_coff > 63) q_q_coff = 63; - iqc_coeff[1] = (q_q_coff * 128) + q_i_coff; + iqc_coeff[1] = (q_q_coff * 128) + (0x7f & q_i_coff); ath_dbg(common, CALIBRATE, "rx chain %d: iq corr coeff=%x\n", chain_idx, iqc_coeff[1]); @@ -839,7 +837,8 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, return true; } -static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, +static void ar9003_hw_detect_outlier(int mp_coeff[][MAXIQCAL], + int nmeasurement, int max_delta) { int mp_max = -64, max_idx = 0; @@ -848,20 +847,20 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, /* find min/max mismatch across all calibrated gains */ for (i = 0; i < nmeasurement; i++) { - if (mp_coeff[i] > mp_max) { - mp_max = mp_coeff[i]; + if (mp_coeff[i][0] > mp_max) { + mp_max = mp_coeff[i][0]; max_idx = i; - } else if (mp_coeff[i] < mp_min) { - mp_min = mp_coeff[i]; + } else if (mp_coeff[i][0] < mp_min) { + mp_min = mp_coeff[i][0]; min_idx = i; } } /* find average (exclude max abs value) */ for (i = 0; i < nmeasurement; i++) { - if ((abs(mp_coeff[i]) < abs(mp_max)) || - (abs(mp_coeff[i]) < abs(mp_min))) { - mp_avg += mp_coeff[i]; + if ((abs(mp_coeff[i][0]) < abs(mp_max)) || + (abs(mp_coeff[i][0]) < abs(mp_min))) { + mp_avg += mp_coeff[i][0]; mp_count++; } } @@ -873,7 +872,7 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, if (mp_count) mp_avg /= mp_count; else - mp_avg = mp_coeff[nmeasurement - 1]; + mp_avg = mp_coeff[nmeasurement - 1][0]; /* detect outlier */ if (abs(mp_max - mp_min) > max_delta) { @@ -882,15 +881,16 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, else outlier_idx = min_idx; - mp_coeff[outlier_idx] = mp_avg; + mp_coeff[outlier_idx][0] = mp_avg; } } -static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, - struct coeff *coeff, - bool is_reusable) +static void ar9003_hw_tx_iq_cal_outlier_detection(struct ath_hw *ah, + struct coeff *coeff, + bool is_reusable) { int i, im, nmeasurement; + int magnitude, phase; u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS]; struct ath9k_hw_cal_data *caldata = ah->caldata; @@ -920,21 +920,30 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, if (nmeasurement > MAX_MEASUREMENT) nmeasurement = MAX_MEASUREMENT; - /* detect outlier only if nmeasurement > 1 */ - if (nmeasurement > 1) { - /* Detect magnitude outlier */ - ar9003_hw_detect_outlier(coeff->mag_coeff[i], - nmeasurement, MAX_MAG_DELTA); - - /* Detect phase outlier */ - ar9003_hw_detect_outlier(coeff->phs_coeff[i], - nmeasurement, MAX_PHS_DELTA); + /* + * Skip normal outlier detection for AR9550. + */ + if (!AR_SREV_9550(ah)) { + /* detect outlier only if nmeasurement > 1 */ + if (nmeasurement > 1) { + /* Detect magnitude outlier */ + ar9003_hw_detect_outlier(coeff->mag_coeff[i], + nmeasurement, + MAX_MAG_DELTA); + + /* Detect phase outlier */ + ar9003_hw_detect_outlier(coeff->phs_coeff[i], + nmeasurement, + MAX_PHS_DELTA); + } } for (im = 0; im < nmeasurement; im++) { + magnitude = coeff->mag_coeff[i][im][0]; + phase = coeff->phs_coeff[i][im][0]; - coeff->iqc_coeff[0] = (coeff->mag_coeff[i][im] & 0x7f) | - ((coeff->phs_coeff[i][im] & 0x7f) << 7); + coeff->iqc_coeff[0] = + (phase & 0x7f) | ((magnitude & 0x7f) << 7); if ((im % 2) == 0) REG_RMW_FIELD(ah, tx_corr_coeff[im][i], @@ -991,7 +1000,63 @@ static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah) return true; } -static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable) +static void __ar955x_tx_iq_cal_sort(struct ath_hw *ah, + struct coeff *coeff, + int i, int nmeasurement) +{ + struct ath_common *common = ath9k_hw_common(ah); + int im, ix, iy, temp; + + for (im = 0; im < nmeasurement; im++) { + for (ix = 0; ix < MAXIQCAL - 1; ix++) { + for (iy = ix + 1; iy <= MAXIQCAL - 1; iy++) { + if (coeff->mag_coeff[i][im][iy] < + coeff->mag_coeff[i][im][ix]) { + temp = coeff->mag_coeff[i][im][ix]; + coeff->mag_coeff[i][im][ix] = + coeff->mag_coeff[i][im][iy]; + coeff->mag_coeff[i][im][iy] = temp; + } + if (coeff->phs_coeff[i][im][iy] < + coeff->phs_coeff[i][im][ix]) { + temp = coeff->phs_coeff[i][im][ix]; + coeff->phs_coeff[i][im][ix] = + coeff->phs_coeff[i][im][iy]; + coeff->phs_coeff[i][im][iy] = temp; + } + } + } + coeff->mag_coeff[i][im][0] = coeff->mag_coeff[i][im][MAXIQCAL / 2]; + coeff->phs_coeff[i][im][0] = coeff->phs_coeff[i][im][MAXIQCAL / 2]; + + ath_dbg(common, CALIBRATE, + "IQCAL: Median [ch%d][gain%d]: mag = %d phase = %d\n", + i, im, + coeff->mag_coeff[i][im][0], + coeff->phs_coeff[i][im][0]); + } +} + +static bool ar955x_tx_iq_cal_median(struct ath_hw *ah, + struct coeff *coeff, + int iqcal_idx, + int nmeasurement) +{ + int i; + + if ((iqcal_idx + 1) != MAXIQCAL) + return false; + + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + __ar955x_tx_iq_cal_sort(ah, coeff, i, nmeasurement); + } + + return true; +} + +static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, + int iqcal_idx, + bool is_reusable) { struct ath_common *common = ath9k_hw_common(ah); const u32 txiqcal_status[AR9300_MAX_CHAINS] = { @@ -1004,10 +1069,11 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable) AR_PHY_CHAN_INFO_TAB_1, AR_PHY_CHAN_INFO_TAB_2, }; - struct coeff coeff; + static struct coeff coeff; s32 iq_res[6]; int i, im, j; - int nmeasurement; + int nmeasurement = 0; + bool outlier_detect = true; for (i = 0; i < AR9300_MAX_CHAINS; i++) { if (!(ah->txchainmask & (1 << i))) @@ -1065,17 +1131,23 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable) goto tx_iqcal_fail; } - coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f; - coeff.phs_coeff[i][im] = + coeff.phs_coeff[i][im][iqcal_idx] = + coeff.iqc_coeff[0] & 0x7f; + coeff.mag_coeff[i][im][iqcal_idx] = (coeff.iqc_coeff[0] >> 7) & 0x7f; - if (coeff.mag_coeff[i][im] > 63) - coeff.mag_coeff[i][im] -= 128; - if (coeff.phs_coeff[i][im] > 63) - coeff.phs_coeff[i][im] -= 128; + if (coeff.mag_coeff[i][im][iqcal_idx] > 63) + coeff.mag_coeff[i][im][iqcal_idx] -= 128; + if (coeff.phs_coeff[i][im][iqcal_idx] > 63) + coeff.phs_coeff[i][im][iqcal_idx] -= 128; } } - ar9003_hw_tx_iqcal_load_avg_2_passes(ah, &coeff, is_reusable); + + if (AR_SREV_9550(ah)) + outlier_detect = ar955x_tx_iq_cal_median(ah, &coeff, + iqcal_idx, nmeasurement); + if (outlier_detect) + ar9003_hw_tx_iq_cal_outlier_detection(ah, &coeff, is_reusable); return; @@ -1409,7 +1481,7 @@ skip_tx_iqcal: } if (txiqcal_done) - ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable); + ar9003_hw_tx_iq_cal_post_proc(ah, 0, is_reusable); else if (caldata && test_bit(TXIQCAL_DONE, &caldata->cal_flags)) ar9003_hw_tx_iq_cal_reload(ah); @@ -1455,14 +1527,38 @@ skip_tx_iqcal: return true; } +static bool do_ar9003_agc_cal(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + bool status; + + REG_WRITE(ah, AR_PHY_AGC_CONTROL, + REG_READ(ah, AR_PHY_AGC_CONTROL) | + AR_PHY_AGC_CONTROL_CAL); + + status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_CAL, + 0, AH_WAIT_TIMEOUT); + if (!status) { + ath_dbg(common, CALIBRATE, + "offset calibration failed to complete in %d ms," + "noisy environment?\n", + AH_WAIT_TIMEOUT / 1000); + return false; + } + + return true; +} + static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_cal_data *caldata = ah->caldata; bool txiqcal_done = false; - bool is_reusable = true, status = true; + bool status = true; bool run_agc_cal = false, sep_iq_cal = false; + int i = 0; /* Use chip chainmask only for calibration */ ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask); @@ -1485,7 +1581,12 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, * AGC calibration. Specifically, AR9550 in SoC chips. */ if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) { - txiqcal_done = true; + if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0, + AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)) { + txiqcal_done = true; + } else { + txiqcal_done = false; + } run_agc_cal = true; } else { sep_iq_cal = true; @@ -1512,27 +1613,37 @@ skip_tx_iqcal: if (AR_SREV_9330_11(ah)) ar9003_hw_manual_peak_cal(ah, 0, IS_CHAN_2GHZ(chan)); - /* Calibrate the AGC */ - REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | - AR_PHY_AGC_CONTROL_CAL); - - /* Poll for offset calibration complete */ - status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_CAL, - 0, AH_WAIT_TIMEOUT); - } + /* + * For non-AR9550 chips, we just trigger AGC calibration + * in the HW, poll for completion and then process + * the results. + * + * For AR955x, we run it multiple times and use + * median IQ correction. + */ + if (!AR_SREV_9550(ah)) { + status = do_ar9003_agc_cal(ah); + if (!status) + return false; - if (!status) { - ath_dbg(common, CALIBRATE, - "offset calibration failed to complete in %d ms; noisy environment?\n", - AH_WAIT_TIMEOUT / 1000); - return false; + if (txiqcal_done) + ar9003_hw_tx_iq_cal_post_proc(ah, 0, false); + } else { + if (!txiqcal_done) { + status = do_ar9003_agc_cal(ah); + if (!status) + return false; + } else { + for (i = 0; i < MAXIQCAL; i++) { + status = do_ar9003_agc_cal(ah); + if (!status) + return false; + ar9003_hw_tx_iq_cal_post_proc(ah, i, false); + } + } + } } - if (txiqcal_done) - ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable); - /* Revert chainmask to runtime parameters */ ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index b8daff78b9d1..235053ba7737 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -23,8 +23,8 @@ #define COMP_HDR_LEN 4 #define COMP_CKSUM_LEN 2 -#define LE16(x) __constant_cpu_to_le16(x) -#define LE32(x) __constant_cpu_to_le32(x) +#define LE16(x) cpu_to_le16(x) +#define LE32(x) cpu_to_le32(x) /* Local defines to distinguish between extension and control CTL's */ #define EXT_ADDITIVE (0x8000) @@ -4792,43 +4792,54 @@ static void ar9003_hw_power_control_override(struct ath_hw *ah, tempslope: if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) { + u8 txmask = (eep->baseEepHeader.txrxMask & 0xf0) >> 4; + /* * AR955x has tempSlope register for each chain. * Check whether temp_compensation feature is enabled or not. */ if (eep->baseEepHeader.featureEnable & 0x1) { if (frequency < 4000) { - REG_RMW_FIELD(ah, AR_PHY_TPC_19, - AR_PHY_TPC_19_ALPHA_THERM, - eep->base_ext2.tempSlopeLow); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, - AR_PHY_TPC_19_ALPHA_THERM, - temp_slope); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, - AR_PHY_TPC_19_ALPHA_THERM, - eep->base_ext2.tempSlopeHigh); + if (txmask & BIT(0)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19, + AR_PHY_TPC_19_ALPHA_THERM, + eep->base_ext2.tempSlopeLow); + if (txmask & BIT(1)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, + AR_PHY_TPC_19_ALPHA_THERM, + temp_slope); + if (txmask & BIT(2)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, + AR_PHY_TPC_19_ALPHA_THERM, + eep->base_ext2.tempSlopeHigh); } else { - REG_RMW_FIELD(ah, AR_PHY_TPC_19, - AR_PHY_TPC_19_ALPHA_THERM, - temp_slope); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, - AR_PHY_TPC_19_ALPHA_THERM, - temp_slope1); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, - AR_PHY_TPC_19_ALPHA_THERM, - temp_slope2); + if (txmask & BIT(0)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19, + AR_PHY_TPC_19_ALPHA_THERM, + temp_slope); + if (txmask & BIT(1)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, + AR_PHY_TPC_19_ALPHA_THERM, + temp_slope1); + if (txmask & BIT(2)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, + AR_PHY_TPC_19_ALPHA_THERM, + temp_slope2); } } else { /* * If temp compensation is not enabled, * set all registers to 0. */ - REG_RMW_FIELD(ah, AR_PHY_TPC_19, - AR_PHY_TPC_19_ALPHA_THERM, 0); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, - AR_PHY_TPC_19_ALPHA_THERM, 0); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, - AR_PHY_TPC_19_ALPHA_THERM, 0); + if (txmask & BIT(0)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19, + AR_PHY_TPC_19_ALPHA_THERM, 0); + if (txmask & BIT(1)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, + AR_PHY_TPC_19_ALPHA_THERM, 0); + if (txmask & BIT(2)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, + AR_PHY_TPC_19_ALPHA_THERM, 0); } } else { REG_RMW_FIELD(ah, AR_PHY_TPC_19, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 09facba1dc6d..8927fc34d84c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -868,10 +868,6 @@ static void ar9003_hw_set_rfmode(struct ath_hw *ah, if (IS_CHAN_A_FAST_CLOCK(ah, chan)) rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); - if (IS_CHAN_QUARTER_RATE(chan)) - rfMode |= AR_PHY_MODE_QUARTER; - if (IS_CHAN_HALF_RATE(chan)) - rfMode |= AR_PHY_MODE_HALF; if (rfMode & (AR_PHY_MODE_QUARTER | AR_PHY_MODE_HALF)) REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index b5ac32cfbeb8..44d74495c4de 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -30,7 +30,6 @@ #include "spectral.h" struct ath_node; -struct ath_rate_table; extern struct ieee80211_ops ath9k_ops; extern int ath9k_modparam_nohwcrypt; @@ -150,6 +149,11 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, #define IS_CCK_RATE(rate) ((rate >= 0x18) && (rate <= 0x1e)) #define IS_OFDM_RATE(rate) ((rate >= 0x8) && (rate <= 0xf)) +enum { + WLAN_RC_PHY_OFDM, + WLAN_RC_PHY_CCK, +}; + struct ath_txq { int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */ u32 axq_qnum; /* ath9k hardware queue number */ @@ -399,21 +403,10 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw, #define ATH_BCBUF 8 #define ATH_DEFAULT_BINTVAL 100 /* TU */ #define ATH_DEFAULT_BMISS_LIMIT 10 -#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) #define TSF_TO_TU(_h,_l) \ ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) -struct ath_beacon_config { - int beacon_interval; - u16 listen_interval; - u16 dtim_period; - u16 bmiss_timeout; - u8 dtim_count; - bool enable_beacon; - bool ibss_creator; -}; - struct ath_beacon { enum { OK, /* no change needed */ @@ -423,11 +416,9 @@ struct ath_beacon { u32 beaconq; u32 bmisscnt; - u32 bc_tstamp; struct ieee80211_vif *bslot[ATH_BCBUF]; int slottime; int slotupdate; - struct ath9k_tx_queue_info beacon_qi; struct ath_descdma bdma; struct ath_txq *cabq; struct list_head bbuf; @@ -442,7 +433,8 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif); void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif); void ath9k_set_beacon(struct ath_softc *sc); -bool ath9k_csa_is_finished(struct ath_softc *sc); +bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif); +void ath9k_csa_update(struct ath_softc *sc); /*******************/ /* Link Monitoring */ @@ -693,15 +685,6 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs); #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ #define MAX_GTT_CNT 5 -enum sc_op_flags { - SC_OP_INVALID, - SC_OP_BEACONS, - SC_OP_ANI_RUN, - SC_OP_PRIM_STA_VIF, - SC_OP_HW_RESET, - SC_OP_SCANNING, -}; - /* Powersave flags */ #define PS_WAIT_FOR_BEACON BIT(0) #define PS_WAIT_FOR_CAB BIT(1) @@ -731,7 +714,6 @@ struct ath_softc { struct completion paprd_complete; wait_queue_head_t tx_wait; - unsigned long sc_flags; unsigned long driver_data; u8 gtt_cnt; @@ -748,7 +730,6 @@ struct ath_softc { struct ath_rx rx; struct ath_tx tx; struct ath_beacon beacon; - struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; #ifdef CONFIG_MAC80211_LEDS bool led_registered; @@ -757,7 +738,6 @@ struct ath_softc { #endif struct ath9k_hw_cal_data caldata; - int last_rssi; #ifdef CONFIG_ATH9K_DEBUGFS struct ath9k_debug debug; @@ -774,7 +754,6 @@ struct ath_softc { #endif struct ath_descdma txsdma; - struct ieee80211_vif *csa_vif; struct ath_ant_comb ant_comb; u8 ant_tx, ant_rx; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 2e8bba0eb361..bd9e634879e6 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -80,7 +80,7 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, u8 chainmask = ah->txchainmask; u8 rate = 0; - sband = &sc->sbands[common->hw->conf.chandef.chan->band]; + sband = &common->sbands[common->hw->conf.chandef.chan->band]; rate = sband->bitrates[rateidx].hw_value; if (vif->bss_conf.use_short_preamble) rate |= sband->bitrates[rateidx].hw_value_short; @@ -292,11 +292,8 @@ static void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif) (unsigned long long)tsfadjust, avp->av_bslot); } -bool ath9k_csa_is_finished(struct ath_softc *sc) +bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif) { - struct ieee80211_vif *vif; - - vif = sc->csa_vif; if (!vif || !vif->csa_active) return false; @@ -304,11 +301,22 @@ bool ath9k_csa_is_finished(struct ath_softc *sc) return false; ieee80211_csa_finish(vif); - - sc->csa_vif = NULL; return true; } +static void ath9k_csa_update_vif(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct ath_softc *sc = data; + ath9k_csa_is_finished(sc, vif); +} + +void ath9k_csa_update(struct ath_softc *sc) +{ + ieee80211_iterate_active_interfaces_atomic(sc->hw, + IEEE80211_IFACE_ITER_NORMAL, + ath9k_csa_update_vif, sc); +} + void ath9k_beacon_tasklet(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; @@ -319,7 +327,7 @@ void ath9k_beacon_tasklet(unsigned long data) bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA); int slot; - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) { + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) { ath_dbg(common, RESET, "reset work is pending, skip beaconing now\n"); return; @@ -362,13 +370,13 @@ void ath9k_beacon_tasklet(unsigned long data) return; } - /* EDMA devices check that in the tx completion function. */ - if (!edma && ath9k_csa_is_finished(sc)) - return; - slot = ath9k_beacon_choose_slot(sc); vif = sc->beacon.bslot[slot]; + /* EDMA devices check that in the tx completion function. */ + if (!edma && ath9k_csa_is_finished(sc, vif)) + return; + if (!vif || !vif->bss_conf.enable_beacon) return; @@ -438,33 +446,6 @@ static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, ath9k_hw_enable_interrupts(ah); } -/* Calculate the modulo of a 64 bit TSF snapshot with a TU divisor */ -static u32 ath9k_mod_tsf64_tu(u64 tsf, u32 div_tu) -{ - u32 tsf_mod, tsf_hi, tsf_lo, mod_hi, mod_lo; - - tsf_mod = tsf & (BIT(10) - 1); - tsf_hi = tsf >> 32; - tsf_lo = ((u32) tsf) >> 10; - - mod_hi = tsf_hi % div_tu; - mod_lo = ((mod_hi << 22) + tsf_lo) % div_tu; - - return (mod_lo << 10) | tsf_mod; -} - -static u32 ath9k_get_next_tbtt(struct ath_softc *sc, u64 tsf, - unsigned int interval) -{ - struct ath_hw *ah = sc->sc_ah; - unsigned int offset; - - tsf += TU_TO_USEC(FUDGE + ah->config.sw_beacon_response_time); - offset = ath9k_mod_tsf64_tu(tsf, interval); - - return (u32) tsf + TU_TO_USEC(interval) - offset; -} - /* * For multi-bss ap support beacons are either staggered evenly over N slots or * burst together. For the former arrange for the SWBA to be delivered for each @@ -474,115 +455,18 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc, struct ath_beacon_config *conf) { struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - u32 nexttbtt, intval; - - /* NB: the beacon interval is kept internally in TU's */ - intval = TU_TO_USEC(conf->beacon_interval); - intval /= ATH_BCBUF; - nexttbtt = ath9k_get_next_tbtt(sc, ath9k_hw_gettsf64(ah), - conf->beacon_interval); - - if (conf->enable_beacon) - ah->imask |= ATH9K_INT_SWBA; - else - ah->imask &= ~ATH9K_INT_SWBA; - - ath_dbg(common, BEACON, - "AP (%s) nexttbtt: %u intval: %u conf_intval: %u\n", - (conf->enable_beacon) ? "Enable" : "Disable", - nexttbtt, intval, conf->beacon_interval); - ath9k_beacon_init(sc, nexttbtt, intval, false); + ath9k_cmn_beacon_config_ap(ah, conf, ATH_BCBUF); + ath9k_beacon_init(sc, conf->nexttbtt, conf->intval, false); } -/* - * This sets up the beacon timers according to the timestamp of the last - * received beacon and the current TSF, configures PCF and DTIM - * handling, programs the sleep registers so the hardware will wakeup in - * time to receive beacons, and configures the beacon miss handling so - * we'll receive a BMISS interrupt when we stop seeing beacons from the AP - * we've associated with. - */ -static void ath9k_beacon_config_sta(struct ath_softc *sc, +static void ath9k_beacon_config_sta(struct ath_hw *ah, struct ath_beacon_config *conf) { - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); struct ath9k_beacon_state bs; - int dtim_intval, sleepduration; - u32 nexttbtt = 0, intval; - u64 tsf; - /* No need to configure beacon if we are not associated */ - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { - ath_dbg(common, BEACON, - "STA is not yet associated..skipping beacon config\n"); + if (ath9k_cmn_beacon_config_sta(ah, conf, &bs) == -EPERM) return; - } - - memset(&bs, 0, sizeof(bs)); - intval = conf->beacon_interval; - - /* - * Setup dtim parameters according to - * last beacon we received (which may be none). - */ - dtim_intval = intval * conf->dtim_period; - sleepduration = conf->listen_interval * intval; - - /* - * Pull nexttbtt forward to reflect the current - * TSF and calculate dtim state for the result. - */ - tsf = ath9k_hw_gettsf64(ah); - nexttbtt = ath9k_get_next_tbtt(sc, tsf, intval); - - bs.bs_intval = TU_TO_USEC(intval); - bs.bs_dtimperiod = conf->dtim_period * bs.bs_intval; - bs.bs_nexttbtt = nexttbtt; - bs.bs_nextdtim = nexttbtt; - if (conf->dtim_period > 1) - bs.bs_nextdtim = ath9k_get_next_tbtt(sc, tsf, dtim_intval); - - /* - * Calculate the number of consecutive beacons to miss* before taking - * a BMISS interrupt. The configuration is specified in TU so we only - * need calculate based on the beacon interval. Note that we clamp the - * result to at most 15 beacons. - */ - if (sleepduration > intval) { - bs.bs_bmissthreshold = conf->listen_interval * - ATH_DEFAULT_BMISS_LIMIT / 2; - } else { - bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval); - if (bs.bs_bmissthreshold > 15) - bs.bs_bmissthreshold = 15; - else if (bs.bs_bmissthreshold <= 0) - bs.bs_bmissthreshold = 1; - } - - /* - * Calculate sleep duration. The configuration is given in ms. - * We ensure a multiple of the beacon period is used. Also, if the sleep - * duration is greater than the DTIM period then it makes senses - * to make it a multiple of that. - * - * XXX fixed at 100ms - */ - - bs.bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100), - sleepduration)); - if (bs.bs_sleepduration > bs.bs_dtimperiod) - bs.bs_sleepduration = bs.bs_dtimperiod; - - /* TSF out of range threshold fixed at 1 second */ - bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; - - ath_dbg(common, BEACON, "bmiss: %u sleep: %u\n", - bs.bs_bmissthreshold, bs.bs_sleepduration); - - /* Set the computed STA beacon timers */ ath9k_hw_disable_interrupts(ah); ath9k_hw_set_sta_beacon_timers(ah, &bs); @@ -597,36 +481,19 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc, { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - u32 intval, nexttbtt; ath9k_reset_beacon_status(sc); - intval = TU_TO_USEC(conf->beacon_interval); - - if (conf->ibss_creator) - nexttbtt = intval; - else - nexttbtt = ath9k_get_next_tbtt(sc, ath9k_hw_gettsf64(ah), - conf->beacon_interval); - - if (conf->enable_beacon) - ah->imask |= ATH9K_INT_SWBA; - else - ah->imask &= ~ATH9K_INT_SWBA; - - ath_dbg(common, BEACON, - "IBSS (%s) nexttbtt: %u intval: %u conf_intval: %u\n", - (conf->enable_beacon) ? "Enable" : "Disable", - nexttbtt, intval, conf->beacon_interval); + ath9k_cmn_beacon_config_adhoc(ah, conf); - ath9k_beacon_init(sc, nexttbtt, intval, conf->ibss_creator); + ath9k_beacon_init(sc, conf->nexttbtt, conf->intval, conf->ibss_creator); /* * Set the global 'beacon has been configured' flag for the * joiner case in IBSS mode. */ if (!conf->ibss_creator && conf->enable_beacon) - set_bit(SC_OP_BEACONS, &sc->sc_flags); + set_bit(ATH_OP_BEACONS, &common->op_flags); } static bool ath9k_allow_beacon_config(struct ath_softc *sc, @@ -646,7 +513,7 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc, if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { if ((vif->type == NL80211_IFTYPE_STATION) && - test_bit(SC_OP_BEACONS, &sc->sc_flags) && + test_bit(ATH_OP_BEACONS, &common->op_flags) && !avp->primary_sta_vif) { ath_dbg(common, CONFIG, "Beacon already configured for a station interface\n"); @@ -668,7 +535,6 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc, cur_conf->beacon_interval = bss_conf->beacon_int; cur_conf->dtim_period = bss_conf->dtim_period; - cur_conf->listen_interval = 1; cur_conf->dtim_count = 1; cur_conf->ibss_creator = bss_conf->ibss_creator; cur_conf->bmiss_timeout = @@ -698,6 +564,8 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, { struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); unsigned long flags; bool skip_beacon = false; @@ -710,7 +578,7 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { ath9k_cache_beacon_config(sc, bss_conf); ath9k_set_beacon(sc); - set_bit(SC_OP_BEACONS, &sc->sc_flags); + set_bit(ATH_OP_BEACONS, &common->op_flags); return; } @@ -749,13 +617,13 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, } /* - * Do not set the SC_OP_BEACONS flag for IBSS joiner mode + * Do not set the ATH_OP_BEACONS flag for IBSS joiner mode * here, it is done in ath9k_beacon_config_adhoc(). */ if (cur_conf->enable_beacon && !skip_beacon) - set_bit(SC_OP_BEACONS, &sc->sc_flags); + set_bit(ATH_OP_BEACONS, &common->op_flags); else - clear_bit(SC_OP_BEACONS, &sc->sc_flags); + clear_bit(ATH_OP_BEACONS, &common->op_flags); } } @@ -773,7 +641,7 @@ void ath9k_set_beacon(struct ath_softc *sc) ath9k_beacon_config_adhoc(sc, cur_conf); break; case NL80211_IFTYPE_STATION: - ath9k_beacon_config_sta(sc, cur_conf); + ath9k_beacon_config_sta(sc->sc_ah, cur_conf); break; default: ath_dbg(common, CONFIG, "Unsupported beaconing mode\n"); diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.c b/drivers/net/wireless/ath/ath9k/common-beacon.c new file mode 100644 index 000000000000..775d1d20ce0b --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-beacon.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2008-2011 Atheros Communications 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 "common.h" + +#define FUDGE 2 + +/* Calculate the modulo of a 64 bit TSF snapshot with a TU divisor */ +static u32 ath9k_mod_tsf64_tu(u64 tsf, u32 div_tu) +{ + u32 tsf_mod, tsf_hi, tsf_lo, mod_hi, mod_lo; + + tsf_mod = tsf & (BIT(10) - 1); + tsf_hi = tsf >> 32; + tsf_lo = ((u32) tsf) >> 10; + + mod_hi = tsf_hi % div_tu; + mod_lo = ((mod_hi << 22) + tsf_lo) % div_tu; + + return (mod_lo << 10) | tsf_mod; +} + +static u32 ath9k_get_next_tbtt(struct ath_hw *ah, u64 tsf, + unsigned int interval) +{ + unsigned int offset; + + tsf += TU_TO_USEC(FUDGE + ah->config.sw_beacon_response_time); + offset = ath9k_mod_tsf64_tu(tsf, interval); + + return (u32) tsf + TU_TO_USEC(interval) - offset; +} + +/* + * This sets up the beacon timers according to the timestamp of the last + * received beacon and the current TSF, configures PCF and DTIM + * handling, programs the sleep registers so the hardware will wakeup in + * time to receive beacons, and configures the beacon miss handling so + * we'll receive a BMISS interrupt when we stop seeing beacons from the AP + * we've associated with. + */ +int ath9k_cmn_beacon_config_sta(struct ath_hw *ah, + struct ath_beacon_config *conf, + struct ath9k_beacon_state *bs) +{ + struct ath_common *common = ath9k_hw_common(ah); + int dtim_intval; + u64 tsf; + + /* No need to configure beacon if we are not associated */ + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { + ath_dbg(common, BEACON, + "STA is not yet associated..skipping beacon config\n"); + return -EPERM; + } + + memset(bs, 0, sizeof(*bs)); + conf->intval = conf->beacon_interval; + + /* + * Setup dtim parameters according to + * last beacon we received (which may be none). + */ + dtim_intval = conf->intval * conf->dtim_period; + + /* + * Pull nexttbtt forward to reflect the current + * TSF and calculate dtim state for the result. + */ + tsf = ath9k_hw_gettsf64(ah); + conf->nexttbtt = ath9k_get_next_tbtt(ah, tsf, conf->intval); + + bs->bs_intval = TU_TO_USEC(conf->intval); + bs->bs_dtimperiod = conf->dtim_period * bs->bs_intval; + bs->bs_nexttbtt = conf->nexttbtt; + bs->bs_nextdtim = conf->nexttbtt; + if (conf->dtim_period > 1) + bs->bs_nextdtim = ath9k_get_next_tbtt(ah, tsf, dtim_intval); + + /* + * Calculate the number of consecutive beacons to miss* before taking + * a BMISS interrupt. The configuration is specified in TU so we only + * need calculate based on the beacon interval. Note that we clamp the + * result to at most 15 beacons. + */ + bs->bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, conf->intval); + if (bs->bs_bmissthreshold > 15) + bs->bs_bmissthreshold = 15; + else if (bs->bs_bmissthreshold <= 0) + bs->bs_bmissthreshold = 1; + + /* + * Calculate sleep duration. The configuration is given in ms. + * We ensure a multiple of the beacon period is used. Also, if the sleep + * duration is greater than the DTIM period then it makes senses + * to make it a multiple of that. + * + * XXX fixed at 100ms + */ + + bs->bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100), + conf->intval)); + if (bs->bs_sleepduration > bs->bs_dtimperiod) + bs->bs_sleepduration = bs->bs_dtimperiod; + + /* TSF out of range threshold fixed at 1 second */ + bs->bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; + + ath_dbg(common, BEACON, "bmiss: %u sleep: %u\n", + bs->bs_bmissthreshold, bs->bs_sleepduration); + return 0; +} +EXPORT_SYMBOL(ath9k_cmn_beacon_config_sta); + +void ath9k_cmn_beacon_config_adhoc(struct ath_hw *ah, + struct ath_beacon_config *conf) +{ + struct ath_common *common = ath9k_hw_common(ah); + + conf->intval = TU_TO_USEC(conf->beacon_interval); + + if (conf->ibss_creator) + conf->nexttbtt = conf->intval; + else + conf->nexttbtt = ath9k_get_next_tbtt(ah, ath9k_hw_gettsf64(ah), + conf->beacon_interval); + + if (conf->enable_beacon) + ah->imask |= ATH9K_INT_SWBA; + else + ah->imask &= ~ATH9K_INT_SWBA; + + ath_dbg(common, BEACON, + "IBSS (%s) nexttbtt: %u intval: %u conf_intval: %u\n", + (conf->enable_beacon) ? "Enable" : "Disable", + conf->nexttbtt, conf->intval, conf->beacon_interval); +} +EXPORT_SYMBOL(ath9k_cmn_beacon_config_adhoc); + +/* + * For multi-bss ap support beacons are either staggered evenly over N slots or + * burst together. For the former arrange for the SWBA to be delivered for each + * slot. Slots that are not occupied will generate nothing. + */ +void ath9k_cmn_beacon_config_ap(struct ath_hw *ah, + struct ath_beacon_config *conf, + unsigned int bc_buf) +{ + struct ath_common *common = ath9k_hw_common(ah); + + /* NB: the beacon interval is kept internally in TU's */ + conf->intval = TU_TO_USEC(conf->beacon_interval); + conf->intval /= bc_buf; + conf->nexttbtt = ath9k_get_next_tbtt(ah, ath9k_hw_gettsf64(ah), + conf->beacon_interval); + + if (conf->enable_beacon) + ah->imask |= ATH9K_INT_SWBA; + else + ah->imask &= ~ATH9K_INT_SWBA; + + ath_dbg(common, BEACON, + "AP (%s) nexttbtt: %u intval: %u conf_intval: %u\n", + (conf->enable_beacon) ? "Enable" : "Disable", + conf->nexttbtt, conf->intval, conf->beacon_interval); +} +EXPORT_SYMBOL(ath9k_cmn_beacon_config_ap); diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.h b/drivers/net/wireless/ath/ath9k/common-beacon.h new file mode 100644 index 000000000000..3665d27f0dc7 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-beacon.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2009-2011 Atheros Communications 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. + */ + +struct ath_beacon_config; + +int ath9k_cmn_beacon_config_sta(struct ath_hw *ah, + struct ath_beacon_config *conf, + struct ath9k_beacon_state *bs); +void ath9k_cmn_beacon_config_adhoc(struct ath_hw *ah, + struct ath_beacon_config *conf); +void ath9k_cmn_beacon_config_ap(struct ath_hw *ah, + struct ath_beacon_config *conf, + unsigned int bc_buf); diff --git a/drivers/net/wireless/ath/ath9k/common-init.c b/drivers/net/wireless/ath/ath9k/common-init.c new file mode 100644 index 000000000000..a006c1499728 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-init.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2008-2011 Atheros Communications 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. + */ + +/* We use the hw_value as an index into our private channel structure */ + +#include "common.h" + +#define CHAN2G(_freq, _idx) { \ + .band = IEEE80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_idx), \ + .max_power = 20, \ +} + +#define CHAN5G(_freq, _idx) { \ + .band = IEEE80211_BAND_5GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_idx), \ + .max_power = 20, \ +} + +/* Some 2 GHz radios are actually tunable on 2312-2732 + * on 5 MHz steps, we support the channels which we know + * we have calibration data for all cards though to make + * this static */ +static const struct ieee80211_channel ath9k_2ghz_chantable[] = { + CHAN2G(2412, 0), /* Channel 1 */ + CHAN2G(2417, 1), /* Channel 2 */ + CHAN2G(2422, 2), /* Channel 3 */ + CHAN2G(2427, 3), /* Channel 4 */ + CHAN2G(2432, 4), /* Channel 5 */ + CHAN2G(2437, 5), /* Channel 6 */ + CHAN2G(2442, 6), /* Channel 7 */ + CHAN2G(2447, 7), /* Channel 8 */ + CHAN2G(2452, 8), /* Channel 9 */ + CHAN2G(2457, 9), /* Channel 10 */ + CHAN2G(2462, 10), /* Channel 11 */ + CHAN2G(2467, 11), /* Channel 12 */ + CHAN2G(2472, 12), /* Channel 13 */ + CHAN2G(2484, 13), /* Channel 14 */ +}; + +/* Some 5 GHz radios are actually tunable on XXXX-YYYY + * on 5 MHz steps, we support the channels which we know + * we have calibration data for all cards though to make + * this static */ +static const struct ieee80211_channel ath9k_5ghz_chantable[] = { + /* _We_ call this UNII 1 */ + CHAN5G(5180, 14), /* Channel 36 */ + CHAN5G(5200, 15), /* Channel 40 */ + CHAN5G(5220, 16), /* Channel 44 */ + CHAN5G(5240, 17), /* Channel 48 */ + /* _We_ call this UNII 2 */ + CHAN5G(5260, 18), /* Channel 52 */ + CHAN5G(5280, 19), /* Channel 56 */ + CHAN5G(5300, 20), /* Channel 60 */ + CHAN5G(5320, 21), /* Channel 64 */ + /* _We_ call this "Middle band" */ + CHAN5G(5500, 22), /* Channel 100 */ + CHAN5G(5520, 23), /* Channel 104 */ + CHAN5G(5540, 24), /* Channel 108 */ + CHAN5G(5560, 25), /* Channel 112 */ + CHAN5G(5580, 26), /* Channel 116 */ + CHAN5G(5600, 27), /* Channel 120 */ + CHAN5G(5620, 28), /* Channel 124 */ + CHAN5G(5640, 29), /* Channel 128 */ + CHAN5G(5660, 30), /* Channel 132 */ + CHAN5G(5680, 31), /* Channel 136 */ + CHAN5G(5700, 32), /* Channel 140 */ + /* _We_ call this UNII 3 */ + CHAN5G(5745, 33), /* Channel 149 */ + CHAN5G(5765, 34), /* Channel 153 */ + CHAN5G(5785, 35), /* Channel 157 */ + CHAN5G(5805, 36), /* Channel 161 */ + CHAN5G(5825, 37), /* Channel 165 */ +}; + +/* Atheros hardware rate code addition for short premble */ +#define SHPCHECK(__hw_rate, __flags) \ + ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0) + +#define RATE(_bitrate, _hw_rate, _flags) { \ + .bitrate = (_bitrate), \ + .flags = (_flags), \ + .hw_value = (_hw_rate), \ + .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ +} + +static struct ieee80211_rate ath9k_legacy_rates[] = { + RATE(10, 0x1b, 0), + RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(60, 0x0b, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(90, 0x0f, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(120, 0x0a, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(180, 0x0e, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(240, 0x09, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(360, 0x0d, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(480, 0x08, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(540, 0x0c, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), +}; + +int ath9k_cmn_init_channels_rates(struct ath_common *common) +{ + struct ath_hw *ah = (struct ath_hw *)common->ah; + void *channels; + + BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) + + ARRAY_SIZE(ath9k_5ghz_chantable) != + ATH9K_NUM_CHANNELS); + + if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { + channels = devm_kzalloc(ah->dev, + sizeof(ath9k_2ghz_chantable), GFP_KERNEL); + if (!channels) + return -ENOMEM; + + memcpy(channels, ath9k_2ghz_chantable, + sizeof(ath9k_2ghz_chantable)); + common->sbands[IEEE80211_BAND_2GHZ].channels = channels; + common->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; + common->sbands[IEEE80211_BAND_2GHZ].n_channels = + ARRAY_SIZE(ath9k_2ghz_chantable); + common->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; + common->sbands[IEEE80211_BAND_2GHZ].n_bitrates = + ARRAY_SIZE(ath9k_legacy_rates); + } + + if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) { + channels = devm_kzalloc(ah->dev, + sizeof(ath9k_5ghz_chantable), GFP_KERNEL); + if (!channels) + return -ENOMEM; + + memcpy(channels, ath9k_5ghz_chantable, + sizeof(ath9k_5ghz_chantable)); + common->sbands[IEEE80211_BAND_5GHZ].channels = channels; + common->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; + common->sbands[IEEE80211_BAND_5GHZ].n_channels = + ARRAY_SIZE(ath9k_5ghz_chantable); + common->sbands[IEEE80211_BAND_5GHZ].bitrates = + ath9k_legacy_rates + 4; + common->sbands[IEEE80211_BAND_5GHZ].n_bitrates = + ARRAY_SIZE(ath9k_legacy_rates) - 4; + } + return 0; +} +EXPORT_SYMBOL(ath9k_cmn_init_channels_rates); + +void ath9k_cmn_setup_ht_cap(struct ath_hw *ah, + struct ieee80211_sta_ht_cap *ht_info) +{ + struct ath_common *common = ath9k_hw_common(ah); + u8 tx_streams, rx_streams; + int i, max_streams; + + ht_info->ht_supported = true; + ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_SM_PS | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_DSSSCCK40; + + if (ah->caps.hw_caps & ATH9K_HW_CAP_LDPC) + ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; + + if (ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) + ht_info->cap |= IEEE80211_HT_CAP_SGI_20; + + ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; + + if (AR_SREV_9271(ah) || AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) + max_streams = 1; + else if (AR_SREV_9462(ah)) + max_streams = 2; + else if (AR_SREV_9300_20_OR_LATER(ah)) + max_streams = 3; + else + max_streams = 2; + + if (AR_SREV_9280_20_OR_LATER(ah)) { + if (max_streams >= 2) + ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; + ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); + } + + /* set up supported mcs set */ + memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); + tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams); + rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams); + + ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n", + tx_streams, rx_streams); + + if (tx_streams != rx_streams) { + ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; + ht_info->mcs.tx_params |= ((tx_streams - 1) << + IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); + } + + for (i = 0; i < rx_streams; i++) + ht_info->mcs.rx_mask[i] = 0xff; + + ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; +} +EXPORT_SYMBOL(ath9k_cmn_setup_ht_cap); + +void ath9k_cmn_reload_chainmask(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_HT)) + return; + + if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) + ath9k_cmn_setup_ht_cap(ah, + &common->sbands[IEEE80211_BAND_2GHZ].ht_cap); + if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) + ath9k_cmn_setup_ht_cap(ah, + &common->sbands[IEEE80211_BAND_5GHZ].ht_cap); +} +EXPORT_SYMBOL(ath9k_cmn_reload_chainmask); diff --git a/drivers/net/wireless/ath/ath9k/common-init.h b/drivers/net/wireless/ath/ath9k/common-init.h new file mode 100644 index 000000000000..ac03fca5ffdd --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-init.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2009-2011 Atheros Communications 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. + */ + +int ath9k_cmn_init_channels_rates(struct ath_common *common); +void ath9k_cmn_setup_ht_cap(struct ath_hw *ah, + struct ieee80211_sta_ht_cap *ht_info); +void ath9k_cmn_reload_chainmask(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 768c733cad31..c6dd7f1fed65 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -27,6 +27,250 @@ MODULE_AUTHOR("Atheros Communications"); MODULE_DESCRIPTION("Shared library for Atheros wireless 802.11n LAN cards."); MODULE_LICENSE("Dual BSD/GPL"); +/* Assumes you've already done the endian to CPU conversion */ +bool ath9k_cmn_rx_accept(struct ath_common *common, + struct ieee80211_hdr *hdr, + struct ieee80211_rx_status *rxs, + struct ath_rx_status *rx_stats, + bool *decrypt_error, + unsigned int rxfilter) +{ + struct ath_hw *ah = common->ah; + bool is_mc, is_valid_tkip, strip_mic, mic_error; + __le16 fc; + + fc = hdr->frame_control; + + is_mc = !!is_multicast_ether_addr(hdr->addr1); + is_valid_tkip = rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID && + test_bit(rx_stats->rs_keyix, common->tkip_keymap); + strip_mic = is_valid_tkip && ieee80211_is_data(fc) && + ieee80211_has_protected(fc) && + !(rx_stats->rs_status & + (ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC | + ATH9K_RXERR_KEYMISS)); + + /* + * Key miss events are only relevant for pairwise keys where the + * descriptor does contain a valid key index. This has been observed + * mostly with CCMP encryption. + */ + if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID || + !test_bit(rx_stats->rs_keyix, common->ccmp_keymap)) + rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS; + + mic_error = is_valid_tkip && !ieee80211_is_ctl(fc) && + !ieee80211_has_morefrags(fc) && + !(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) && + (rx_stats->rs_status & ATH9K_RXERR_MIC); + + /* + * The rx_stats->rs_status will not be set until the end of the + * chained descriptors so it can be ignored if rs_more is set. The + * rs_more will be false at the last element of the chained + * descriptors. + */ + if (rx_stats->rs_status != 0) { + u8 status_mask; + + if (rx_stats->rs_status & ATH9K_RXERR_CRC) { + rxs->flag |= RX_FLAG_FAILED_FCS_CRC; + mic_error = false; + } + + if ((rx_stats->rs_status & ATH9K_RXERR_DECRYPT) || + (!is_mc && (rx_stats->rs_status & ATH9K_RXERR_KEYMISS))) { + *decrypt_error = true; + mic_error = false; + } + + + /* + * Reject error frames with the exception of + * decryption and MIC failures. For monitor mode, + * we also ignore the CRC error. + */ + status_mask = ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | + ATH9K_RXERR_KEYMISS; + + if (ah->is_monitoring && (rxfilter & FIF_FCSFAIL)) + status_mask |= ATH9K_RXERR_CRC; + + if (rx_stats->rs_status & ~status_mask) + return false; + } + + /* + * For unicast frames the MIC error bit can have false positives, + * so all MIC error reports need to be validated in software. + * False negatives are not common, so skip software verification + * if the hardware considers the MIC valid. + */ + if (strip_mic) + rxs->flag |= RX_FLAG_MMIC_STRIPPED; + else if (is_mc && mic_error) + rxs->flag |= RX_FLAG_MMIC_ERROR; + + return true; +} +EXPORT_SYMBOL(ath9k_cmn_rx_accept); + +void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, + struct sk_buff *skb, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs, + bool decrypt_error) +{ + struct ath_hw *ah = common->ah; + struct ieee80211_hdr *hdr; + int hdrlen, padpos, padsize; + u8 keyix; + __le16 fc; + + /* see if any padding is done by the hw and remove it */ + hdr = (struct ieee80211_hdr *) skb->data; + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + fc = hdr->frame_control; + padpos = ieee80211_hdrlen(fc); + + /* The MAC header is padded to have 32-bit boundary if the + * packet payload is non-zero. The general calculation for + * padsize would take into account odd header lengths: + * padsize = (4 - padpos % 4) % 4; However, since only + * even-length headers are used, padding can only be 0 or 2 + * bytes and we can optimize this a bit. In addition, we must + * not try to remove padding from short control frames that do + * not have payload. */ + padsize = padpos & 3; + if (padsize && skb->len>=padpos+padsize+FCS_LEN) { + memmove(skb->data + padsize, skb->data, padpos); + skb_pull(skb, padsize); + } + + keyix = rx_stats->rs_keyix; + + if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error && + ieee80211_has_protected(fc)) { + rxs->flag |= RX_FLAG_DECRYPTED; + } else if (ieee80211_has_protected(fc) + && !decrypt_error && skb->len >= hdrlen + 4) { + keyix = skb->data[hdrlen + 3] >> 6; + + if (test_bit(keyix, common->keymap)) + rxs->flag |= RX_FLAG_DECRYPTED; + } + if (ah->sw_mgmt_crypto && + (rxs->flag & RX_FLAG_DECRYPTED) && + ieee80211_is_mgmt(fc)) + /* Use software decrypt for management frames. */ + rxs->flag &= ~RX_FLAG_DECRYPTED; +} +EXPORT_SYMBOL(ath9k_cmn_rx_skb_postprocess); + +int ath9k_cmn_process_rate(struct ath_common *common, + struct ieee80211_hw *hw, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs) +{ + struct ieee80211_supported_band *sband; + enum ieee80211_band band; + unsigned int i = 0; + struct ath_hw *ah = common->ah; + + band = ah->curchan->chan->band; + sband = hw->wiphy->bands[band]; + + if (IS_CHAN_QUARTER_RATE(ah->curchan)) + rxs->flag |= RX_FLAG_5MHZ; + else if (IS_CHAN_HALF_RATE(ah->curchan)) + rxs->flag |= RX_FLAG_10MHZ; + + if (rx_stats->rs_rate & 0x80) { + /* HT rate */ + rxs->flag |= RX_FLAG_HT; + rxs->flag |= rx_stats->flag; + rxs->rate_idx = rx_stats->rs_rate & 0x7f; + return 0; + } + + for (i = 0; i < sband->n_bitrates; i++) { + if (sband->bitrates[i].hw_value == rx_stats->rs_rate) { + rxs->rate_idx = i; + return 0; + } + if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) { + rxs->flag |= RX_FLAG_SHORTPRE; + rxs->rate_idx = i; + return 0; + } + } + + return -EINVAL; +} +EXPORT_SYMBOL(ath9k_cmn_process_rate); + +void ath9k_cmn_process_rssi(struct ath_common *common, + struct ieee80211_hw *hw, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs) +{ + struct ath_hw *ah = common->ah; + int last_rssi; + int rssi = rx_stats->rs_rssi; + int i, j; + + /* + * RSSI is not available for subframes in an A-MPDU. + */ + if (rx_stats->rs_moreaggr) { + rxs->flag |= RX_FLAG_NO_SIGNAL_VAL; + return; + } + + /* + * Check if the RSSI for the last subframe in an A-MPDU + * or an unaggregated frame is valid. + */ + if (rx_stats->rs_rssi == ATH9K_RSSI_BAD) { + rxs->flag |= RX_FLAG_NO_SIGNAL_VAL; + return; + } + + for (i = 0, j = 0; i < ARRAY_SIZE(rx_stats->rs_rssi_ctl); i++) { + s8 rssi; + + if (!(ah->rxchainmask & BIT(i))) + continue; + + rssi = rx_stats->rs_rssi_ctl[i]; + if (rssi != ATH9K_RSSI_BAD) { + rxs->chains |= BIT(j); + rxs->chain_signal[j] = ah->noise + rssi; + } + j++; + } + + /* + * Update Beacon RSSI, this is used by ANI. + */ + if (rx_stats->is_mybeacon && + ((ah->opmode == NL80211_IFTYPE_STATION) || + (ah->opmode == NL80211_IFTYPE_ADHOC))) { + ATH_RSSI_LPF(common->last_rssi, rx_stats->rs_rssi); + last_rssi = common->last_rssi; + + if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) + rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); + if (rssi < 0) + rssi = 0; + + ah->stats.avgbrssi = rssi; + } + + rxs->signal = ah->noise + rx_stats->rs_rssi; +} +EXPORT_SYMBOL(ath9k_cmn_process_rssi); + int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb) { struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index eb85e1bdca88..ca38116838f0 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -21,6 +21,9 @@ #include "hw.h" #include "hw-ops.h" +#include "common-init.h" +#include "common-beacon.h" + /* Common header for Atheros 802.11n base driver cores */ #define WME_BA_BMP_SIZE 64 @@ -42,6 +45,38 @@ #define ATH_EP_RND(x, mul) \ (((x) + ((mul)/2)) / (mul)) +#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) + +struct ath_beacon_config { + int beacon_interval; + u16 dtim_period; + u16 bmiss_timeout; + u8 dtim_count; + bool enable_beacon; + bool ibss_creator; + u32 nexttbtt; + u32 intval; +}; + +bool ath9k_cmn_rx_accept(struct ath_common *common, + struct ieee80211_hdr *hdr, + struct ieee80211_rx_status *rxs, + struct ath_rx_status *rx_stats, + bool *decrypt_error, + unsigned int rxfilter); +void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, + struct sk_buff *skb, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs, + bool decrypt_error); +int ath9k_cmn_process_rate(struct ath_common *common, + struct ieee80211_hw *hw, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs); +void ath9k_cmn_process_rssi(struct ath_common *common, + struct ieee80211_hw *hw, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs); int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb); struct ath9k_channel *ath9k_cmn_get_channel(struct ieee80211_hw *hw, struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index ab7264c1d8f7..780ff1bee6f6 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -135,46 +135,45 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf, struct ath_softc *sc = file->private_data; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_hw *ah = sc->sc_ah; - unsigned int len = 0, size = 1024; + unsigned int len = 0; + const unsigned int size = 1024; ssize_t retval = 0; char *buf; + int i; + struct { + const char *name; + unsigned int val; + } ani_info[] = { + { "ANI RESET", ah->stats.ast_ani_reset }, + { "OFDM LEVEL", ah->ani.ofdmNoiseImmunityLevel }, + { "CCK LEVEL", ah->ani.cckNoiseImmunityLevel }, + { "SPUR UP", ah->stats.ast_ani_spurup }, + { "SPUR DOWN", ah->stats.ast_ani_spurup }, + { "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon }, + { "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff }, + { "MRC-CCK ON", ah->stats.ast_ani_ccklow }, + { "MRC-CCK OFF", ah->stats.ast_ani_cckhigh }, + { "FIR-STEP UP", ah->stats.ast_ani_stepup }, + { "FIR-STEP DOWN", ah->stats.ast_ani_stepdown }, + { "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero }, + { "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs }, + { "CCK ERRORS", ah->stats.ast_ani_cckerrs }, + }; buf = kzalloc(size, GFP_KERNEL); if (buf == NULL) return -ENOMEM; - if (common->disable_ani) { - len += scnprintf(buf + len, size - len, "%s: %s\n", - "ANI", "DISABLED"); + len += scnprintf(buf + len, size - len, "%15s: %s\n", "ANI", + common->disable_ani ? "DISABLED" : "ENABLED"); + + if (common->disable_ani) goto exit; - } - len += scnprintf(buf + len, size - len, "%15s: %s\n", - "ANI", "ENABLED"); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "ANI RESET", ah->stats.ast_ani_reset); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "SPUR UP", ah->stats.ast_ani_spurup); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "SPUR DOWN", ah->stats.ast_ani_spurup); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "MRC-CCK ON", ah->stats.ast_ani_ccklow); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "MRC-CCK OFF", ah->stats.ast_ani_cckhigh); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "FIR-STEP UP", ah->stats.ast_ani_stepup); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "FIR-STEP DOWN", ah->stats.ast_ani_stepdown); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "CCK ERRORS", ah->stats.ast_ani_cckerrs); + for (i = 0; i < ARRAY_SIZE(ani_info); i++) + len += scnprintf(buf + len, size - len, "%15s: %u\n", + ani_info[i].name, ani_info[i].val); + exit: if (len > size) len = size; @@ -209,7 +208,7 @@ static ssize_t write_file_ani(struct file *file, common->disable_ani = !ani; if (common->disable_ani) { - clear_bit(SC_OP_ANI_RUN, &sc->sc_flags); + clear_bit(ATH_OP_ANI_RUN, &common->op_flags); ath_stop_ani(sc); } else { ath_check_ani(sc); @@ -307,13 +306,13 @@ static ssize_t read_file_antenna_diversity(struct file *file, struct ath_antenna_stats *as_main = &sc->debug.stats.ant_stats[ANT_MAIN]; struct ath_antenna_stats *as_alt = &sc->debug.stats.ant_stats[ANT_ALT]; struct ath_hw_antcomb_conf div_ant_conf; - unsigned int len = 0, size = 1024; + unsigned int len = 0; + const unsigned int size = 1024; ssize_t retval = 0; char *buf; - char *lna_conf_str[4] = {"LNA1_MINUS_LNA2", - "LNA2", - "LNA1", - "LNA1_PLUS_LNA2"}; + static const char *lna_conf_str[4] = { + "LNA1_MINUS_LNA2", "LNA2", "LNA1", "LNA1_PLUS_LNA2" + }; buf = kzalloc(size, GFP_KERNEL); if (buf == NULL) @@ -716,10 +715,13 @@ static ssize_t read_file_queues(struct file *file, char __user *user_buf, struct ath_softc *sc = file->private_data; struct ath_txq *txq; char *buf; - unsigned int len = 0, size = 1024; + unsigned int len = 0; + const unsigned int size = 1024; ssize_t retval = 0; int i; - char *qname[4] = {"VO", "VI", "BE", "BK"}; + static const char *qname[4] = { + "VO", "VI", "BE", "BK" + }; buf = kzalloc(size, GFP_KERNEL); if (buf == NULL) @@ -866,6 +868,12 @@ static ssize_t read_file_reset(struct file *file, char __user *user_buf, "%17s: %2d\n", "PLL RX Hang", sc->debug.stats.reset[RESET_TYPE_PLL_HANG]); len += scnprintf(buf + len, sizeof(buf) - len, + "%17s: %2d\n", "MAC Hang", + sc->debug.stats.reset[RESET_TYPE_MAC_HANG]); + len += scnprintf(buf + len, sizeof(buf) - len, + "%17s: %2d\n", "Stuck Beacon", + sc->debug.stats.reset[RESET_TYPE_BEACON_STUCK]); + len += scnprintf(buf + len, sizeof(buf) - len, "%17s: %2d\n", "MCI Reset", sc->debug.stats.reset[RESET_TYPE_MCI]); diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index cc7a025d833e..559a68c2709c 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -18,7 +18,6 @@ #define DEBUG_H #include "hw.h" -#include "rc.h" #include "dfs_debug.h" struct ath_txq; diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.h b/drivers/net/wireless/ath/ath9k/dfs_debug.h index 0a7ddf4c88c9..7936c9126a20 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_debug.h +++ b/drivers/net/wireless/ath/ath9k/dfs_debug.h @@ -21,6 +21,8 @@ #include "hw.h" +struct ath_softc; + /** * struct ath_dfs_stats - DFS Statistics per wiphy * @pulses_total: pulses reported by HW diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 6d5d716adc1b..8e7153b186ed 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -54,6 +54,8 @@ static struct usb_device_id ath9k_hif_usb_ids[] = { .driver_info = AR9280_USB }, /* SMC Networks */ { USB_DEVICE(0x0411, 0x017f), .driver_info = AR9280_USB }, /* Sony UWA-BR100 */ + { USB_DEVICE(0x0411, 0x0197), + .driver_info = AR9280_USB }, /* Buffalo WLI-UV-AG300P */ { USB_DEVICE(0x04da, 0x3904), .driver_info = AR9280_USB }, diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 99a203174f45..dab1f0cab993 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -39,7 +39,6 @@ #define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ #define ATH_DEFAULT_BMISS_LIMIT 10 -#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) #define TSF_TO_TU(_h, _l) \ ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) @@ -277,7 +276,6 @@ struct ath9k_htc_rxbuf { }; struct ath9k_htc_rx { - int last_rssi; /* FIXME: per-STA */ struct list_head rxbuf; spinlock_t rxbuflock; }; @@ -407,12 +405,18 @@ static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, #define DEFAULT_SWBA_RESPONSE 40 /* in TUs */ #define MIN_SWBA_RESPONSE 10 /* in TUs */ -struct htc_beacon_config { +struct htc_beacon { + enum { + OK, /* no change needed */ + UPDATE, /* update pending */ + COMMIT /* beacon sent, commit change */ + } updateslot; /* slot time update fsm */ + struct ieee80211_vif *bslot[ATH9K_HTC_MAX_BCN_VIF]; - u16 beacon_interval; - u16 dtim_period; - u16 bmiss_timeout; - u32 bmiss_cnt; + u32 bmisscnt; + u32 beaconq; + int slottime; + int slotupdate; }; struct ath_btcoex { @@ -440,12 +444,8 @@ static inline void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv) } #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ -#define OP_INVALID BIT(0) -#define OP_SCANNING BIT(1) -#define OP_ENABLE_BEACON BIT(2) #define OP_BT_PRIORITY_DETECTED BIT(3) #define OP_BT_SCAN BIT(4) -#define OP_ANI_RUNNING BIT(5) #define OP_TSF_RESET BIT(6) struct ath9k_htc_priv { @@ -488,10 +488,10 @@ struct ath9k_htc_priv { unsigned long op_flags; struct ath9k_hw_cal_data caldata; - struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; spinlock_t beacon_lock; - struct htc_beacon_config cur_beacon_conf; + struct ath_beacon_config cur_beacon_conf; + struct htc_beacon beacon; struct ath9k_htc_rx rx; struct ath9k_htc_tx tx; @@ -516,7 +516,6 @@ struct ath9k_htc_priv { struct work_struct led_work; #endif - int beaconq; int cabq; int hwq_map[IEEE80211_NUM_ACS]; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 8b5757734596..e8b6ec3c1dbb 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -26,7 +26,7 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info)); - ath9k_hw_get_txq_props(ah, priv->beaconq, &qi); + ath9k_hw_get_txq_props(ah, priv->beacon.beaconq, &qi); if (priv->ah->opmode == NL80211_IFTYPE_AP || priv->ah->opmode == NL80211_IFTYPE_MESH_POINT) { @@ -54,220 +54,78 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) } - if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) { + if (!ath9k_hw_set_txq_props(ah, priv->beacon.beaconq, &qi)) { ath_err(ath9k_hw_common(ah), - "Unable to update beacon queue %u!\n", priv->beaconq); + "Unable to update beacon queue %u!\n", priv->beacon.beaconq); } else { - ath9k_hw_resettxqueue(ah, priv->beaconq); + ath9k_hw_resettxqueue(ah, priv->beacon.beaconq); } } - -static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, - struct htc_beacon_config *bss_conf) +/* + * Both nexttbtt and intval have to be in usecs. + */ +static void ath9k_htc_beacon_init(struct ath9k_htc_priv *priv, + struct ath_beacon_config *conf, + bool reset_tsf) { - struct ath_common *common = ath9k_hw_common(priv->ah); - struct ath9k_beacon_state bs; - enum ath9k_int imask = 0; - int dtimperiod, dtimcount, sleepduration; - int bmiss_timeout; - u32 nexttbtt = 0, intval, tsftu; - __be32 htc_imask = 0; - u64 tsf; - int num_beacons, offset, dtim_dec_count; + struct ath_hw *ah = priv->ah; int ret __attribute__ ((unused)); + __be32 htc_imask = 0; u8 cmd_rsp; - memset(&bs, 0, sizeof(bs)); - - intval = bss_conf->beacon_interval; - bmiss_timeout = (ATH_DEFAULT_BMISS_LIMIT * bss_conf->beacon_interval); - - /* - * Setup dtim parameters according to - * last beacon we received (which may be none). - */ - dtimperiod = bss_conf->dtim_period; - if (dtimperiod <= 0) /* NB: 0 if not known */ - dtimperiod = 1; - dtimcount = 1; - if (dtimcount >= dtimperiod) /* NB: sanity check */ - dtimcount = 0; - - sleepduration = intval; - if (sleepduration <= 0) - sleepduration = intval; - - /* - * Pull nexttbtt forward to reflect the current - * TSF and calculate dtim state for the result. - */ - tsf = ath9k_hw_gettsf64(priv->ah); - tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; - - num_beacons = tsftu / intval + 1; - offset = tsftu % intval; - nexttbtt = tsftu - offset; - if (offset) - nexttbtt += intval; - - /* DTIM Beacon every dtimperiod Beacon */ - dtim_dec_count = num_beacons % dtimperiod; - dtimcount -= dtim_dec_count; - if (dtimcount < 0) - dtimcount += dtimperiod; - - bs.bs_intval = TU_TO_USEC(intval); - bs.bs_nexttbtt = TU_TO_USEC(nexttbtt); - bs.bs_dtimperiod = dtimperiod * bs.bs_intval; - bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount * bs.bs_intval; - - /* - * Calculate the number of consecutive beacons to miss* before taking - * a BMISS interrupt. The configuration is specified in TU so we only - * need calculate based on the beacon interval. Note that we clamp the - * result to at most 15 beacons. - */ - if (sleepduration > intval) { - bs.bs_bmissthreshold = ATH_DEFAULT_BMISS_LIMIT / 2; - } else { - bs.bs_bmissthreshold = DIV_ROUND_UP(bmiss_timeout, intval); - if (bs.bs_bmissthreshold > 15) - bs.bs_bmissthreshold = 15; - else if (bs.bs_bmissthreshold <= 0) - bs.bs_bmissthreshold = 1; - } - - /* - * Calculate sleep duration. The configuration is given in ms. - * We ensure a multiple of the beacon period is used. Also, if the sleep - * duration is greater than the DTIM period then it makes senses - * to make it a multiple of that. - * - * XXX fixed at 100ms - */ - - bs.bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100), - sleepduration)); - if (bs.bs_sleepduration > bs.bs_dtimperiod) - bs.bs_sleepduration = bs.bs_dtimperiod; - - /* TSF out of range threshold fixed at 1 second */ - bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; - - ath_dbg(common, CONFIG, "intval: %u tsf: %llu tsftu: %u\n", - intval, tsf, tsftu); - ath_dbg(common, CONFIG, "bmiss: %u sleep: %u\n", - bs.bs_bmissthreshold, bs.bs_sleepduration); - - /* Set the computed STA beacon timers */ + if (conf->intval >= TU_TO_USEC(DEFAULT_SWBA_RESPONSE)) + ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; + else + ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; WMI_CMD(WMI_DISABLE_INTR_CMDID); - ath9k_hw_set_sta_beacon_timers(priv->ah, &bs); - imask |= ATH9K_INT_BMISS; - htc_imask = cpu_to_be32(imask); + if (reset_tsf) + ath9k_hw_reset_tsf(ah); + ath9k_htc_beaconq_config(priv); + ath9k_hw_beaconinit(ah, conf->nexttbtt, conf->intval); + priv->beacon.bmisscnt = 0; + htc_imask = cpu_to_be32(ah->imask); WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); } -static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, - struct htc_beacon_config *bss_conf) +static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, + struct ath_beacon_config *bss_conf) { - struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_beacon_state bs; enum ath9k_int imask = 0; - u32 nexttbtt, intval, tsftu; __be32 htc_imask = 0; int ret __attribute__ ((unused)); u8 cmd_rsp; - u64 tsf; - intval = bss_conf->beacon_interval; - intval /= ATH9K_HTC_MAX_BCN_VIF; - nexttbtt = intval; - - /* - * To reduce beacon misses under heavy TX load, - * set the beacon response time to a larger value. - */ - if (intval > DEFAULT_SWBA_RESPONSE) - priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; - else - priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; - - if (test_bit(OP_TSF_RESET, &priv->op_flags)) { - ath9k_hw_reset_tsf(priv->ah); - clear_bit(OP_TSF_RESET, &priv->op_flags); - } else { - /* - * Pull nexttbtt forward to reflect the current TSF. - */ - tsf = ath9k_hw_gettsf64(priv->ah); - tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE; - do { - nexttbtt += intval; - } while (nexttbtt < tsftu); - } - - if (test_bit(OP_ENABLE_BEACON, &priv->op_flags)) - imask |= ATH9K_INT_SWBA; - - ath_dbg(common, CONFIG, - "AP Beacon config, intval: %d, nexttbtt: %u, resp_time: %d imask: 0x%x\n", - bss_conf->beacon_interval, nexttbtt, - priv->ah->config.sw_beacon_response_time, imask); - - ath9k_htc_beaconq_config(priv); + if (ath9k_cmn_beacon_config_sta(priv->ah, bss_conf, &bs) == -EPERM) + return; WMI_CMD(WMI_DISABLE_INTR_CMDID); - ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); - priv->cur_beacon_conf.bmiss_cnt = 0; + ath9k_hw_set_sta_beacon_timers(priv->ah, &bs); + imask |= ATH9K_INT_BMISS; htc_imask = cpu_to_be32(imask); WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); } -static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, - struct htc_beacon_config *bss_conf) +static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, + struct ath_beacon_config *conf) { - struct ath_common *common = ath9k_hw_common(priv->ah); - enum ath9k_int imask = 0; - u32 nexttbtt, intval, tsftu; - __be32 htc_imask = 0; - int ret __attribute__ ((unused)); - u8 cmd_rsp; - u64 tsf; - - intval = bss_conf->beacon_interval; - nexttbtt = intval; - - /* - * Pull nexttbtt forward to reflect the current TSF. - */ - tsf = ath9k_hw_gettsf64(priv->ah); - tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE; - do { - nexttbtt += intval; - } while (nexttbtt < tsftu); - - /* - * Only one IBSS interfce is allowed. - */ - if (intval > DEFAULT_SWBA_RESPONSE) - priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; - else - priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; + struct ath_hw *ah = priv->ah; + ah->imask = 0; - if (test_bit(OP_ENABLE_BEACON, &priv->op_flags)) - imask |= ATH9K_INT_SWBA; + ath9k_cmn_beacon_config_ap(ah, conf, ATH9K_HTC_MAX_BCN_VIF); + ath9k_htc_beacon_init(priv, conf, false); +} - ath_dbg(common, CONFIG, - "IBSS Beacon config, intval: %d, nexttbtt: %u, resp_time: %d, imask: 0x%x\n", - bss_conf->beacon_interval, nexttbtt, - priv->ah->config.sw_beacon_response_time, imask); +static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, + struct ath_beacon_config *conf) +{ + struct ath_hw *ah = priv->ah; + ah->imask = 0; - WMI_CMD(WMI_DISABLE_INTR_CMDID); - ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); - priv->cur_beacon_conf.bmiss_cnt = 0; - htc_imask = cpu_to_be32(imask); - WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); + ath9k_cmn_beacon_config_adhoc(ah, conf); + ath9k_htc_beacon_init(priv, conf, conf->ibss_creator); } void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, @@ -287,7 +145,7 @@ static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv, spin_lock_bh(&priv->beacon_lock); - vif = priv->cur_beacon_conf.bslot[slot]; + vif = priv->beacon.bslot[slot]; skb = ieee80211_get_buffered_bc(priv->hw, vif); @@ -348,10 +206,10 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, spin_lock_bh(&priv->beacon_lock); - vif = priv->cur_beacon_conf.bslot[slot]; + vif = priv->beacon.bslot[slot]; avp = (struct ath9k_htc_vif *)vif->drv_priv; - if (unlikely(test_bit(OP_SCANNING, &priv->op_flags))) { + if (unlikely(test_bit(ATH_OP_SCANNING, &common->op_flags))) { spin_unlock_bh(&priv->beacon_lock); return; } @@ -431,8 +289,8 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, int slot; if (swba->beacon_pending != 0) { - priv->cur_beacon_conf.bmiss_cnt++; - if (priv->cur_beacon_conf.bmiss_cnt > BSTUCK_THRESHOLD) { + priv->beacon.bmisscnt++; + if (priv->beacon.bmisscnt > BSTUCK_THRESHOLD) { ath_dbg(common, BSTUCK, "Beacon stuck, HW reset\n"); ieee80211_queue_work(priv->hw, &priv->fatal_work); @@ -440,16 +298,16 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, return; } - if (priv->cur_beacon_conf.bmiss_cnt) { + if (priv->beacon.bmisscnt) { ath_dbg(common, BSTUCK, "Resuming beacon xmit after %u misses\n", - priv->cur_beacon_conf.bmiss_cnt); - priv->cur_beacon_conf.bmiss_cnt = 0; + priv->beacon.bmisscnt); + priv->beacon.bmisscnt = 0; } slot = ath9k_htc_choose_bslot(priv, swba); spin_lock_bh(&priv->beacon_lock); - if (priv->cur_beacon_conf.bslot[slot] == NULL) { + if (priv->beacon.bslot[slot] == NULL) { spin_unlock_bh(&priv->beacon_lock); return; } @@ -468,13 +326,13 @@ void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv, spin_lock_bh(&priv->beacon_lock); for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) { - if (priv->cur_beacon_conf.bslot[i] == NULL) { + if (priv->beacon.bslot[i] == NULL) { avp->bslot = i; break; } } - priv->cur_beacon_conf.bslot[avp->bslot] = vif; + priv->beacon.bslot[avp->bslot] = vif; spin_unlock_bh(&priv->beacon_lock); ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n", @@ -488,7 +346,7 @@ void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv, struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; spin_lock_bh(&priv->beacon_lock); - priv->cur_beacon_conf.bslot[avp->bslot] = NULL; + priv->beacon.bslot[avp->bslot] = NULL; spin_unlock_bh(&priv->beacon_lock); ath_dbg(common, CONFIG, "Removed interface at beacon slot: %d\n", @@ -504,7 +362,7 @@ void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv, { struct ath_common *common = ath9k_hw_common(priv->ah); struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; - struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; u64 tsfadjust; if (avp->bslot == 0) @@ -536,7 +394,7 @@ static bool ath9k_htc_check_beacon_config(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif) { struct ath_common *common = ath9k_hw_common(priv->ah); - struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; bool beacon_configured; @@ -591,7 +449,7 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif) { struct ath_common *common = ath9k_hw_common(priv->ah); - struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv; @@ -627,7 +485,7 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv) { struct ath_common *common = ath9k_hw_common(priv->ah); - struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; switch (priv->ah->opmode) { case NL80211_IFTYPE_STATION: diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index c57d6b859c04..8a3bd5fe3a54 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -38,93 +38,6 @@ static int ath9k_ps_enable; module_param_named(ps_enable, ath9k_ps_enable, int, 0444); MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); -#define CHAN2G(_freq, _idx) { \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 20, \ -} - -#define CHAN5G(_freq, _idx) { \ - .band = IEEE80211_BAND_5GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 20, \ -} - -static struct ieee80211_channel ath9k_2ghz_channels[] = { - CHAN2G(2412, 0), /* Channel 1 */ - CHAN2G(2417, 1), /* Channel 2 */ - CHAN2G(2422, 2), /* Channel 3 */ - CHAN2G(2427, 3), /* Channel 4 */ - CHAN2G(2432, 4), /* Channel 5 */ - CHAN2G(2437, 5), /* Channel 6 */ - CHAN2G(2442, 6), /* Channel 7 */ - CHAN2G(2447, 7), /* Channel 8 */ - CHAN2G(2452, 8), /* Channel 9 */ - CHAN2G(2457, 9), /* Channel 10 */ - CHAN2G(2462, 10), /* Channel 11 */ - CHAN2G(2467, 11), /* Channel 12 */ - CHAN2G(2472, 12), /* Channel 13 */ - CHAN2G(2484, 13), /* Channel 14 */ -}; - -static struct ieee80211_channel ath9k_5ghz_channels[] = { - /* _We_ call this UNII 1 */ - CHAN5G(5180, 14), /* Channel 36 */ - CHAN5G(5200, 15), /* Channel 40 */ - CHAN5G(5220, 16), /* Channel 44 */ - CHAN5G(5240, 17), /* Channel 48 */ - /* _We_ call this UNII 2 */ - CHAN5G(5260, 18), /* Channel 52 */ - CHAN5G(5280, 19), /* Channel 56 */ - CHAN5G(5300, 20), /* Channel 60 */ - CHAN5G(5320, 21), /* Channel 64 */ - /* _We_ call this "Middle band" */ - CHAN5G(5500, 22), /* Channel 100 */ - CHAN5G(5520, 23), /* Channel 104 */ - CHAN5G(5540, 24), /* Channel 108 */ - CHAN5G(5560, 25), /* Channel 112 */ - CHAN5G(5580, 26), /* Channel 116 */ - CHAN5G(5600, 27), /* Channel 120 */ - CHAN5G(5620, 28), /* Channel 124 */ - CHAN5G(5640, 29), /* Channel 128 */ - CHAN5G(5660, 30), /* Channel 132 */ - CHAN5G(5680, 31), /* Channel 136 */ - CHAN5G(5700, 32), /* Channel 140 */ - /* _We_ call this UNII 3 */ - CHAN5G(5745, 33), /* Channel 149 */ - CHAN5G(5765, 34), /* Channel 153 */ - CHAN5G(5785, 35), /* Channel 157 */ - CHAN5G(5805, 36), /* Channel 161 */ - CHAN5G(5825, 37), /* Channel 165 */ -}; - -/* Atheros hardware rate code addition for short premble */ -#define SHPCHECK(__hw_rate, __flags) \ - ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04) : 0) - -#define RATE(_bitrate, _hw_rate, _flags) { \ - .bitrate = (_bitrate), \ - .flags = (_flags), \ - .hw_value = (_hw_rate), \ - .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ -} - -static struct ieee80211_rate ath9k_legacy_rates[] = { - RATE(10, 0x1b, 0), - RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp : 0x1e */ - RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp: 0x1d */ - RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), /* short: 0x1c */ - RATE(60, 0x0b, 0), - RATE(90, 0x0f, 0), - RATE(120, 0x0a, 0), - RATE(180, 0x0e, 0), - RATE(240, 0x09, 0), - RATE(360, 0x0d, 0), - RATE(480, 0x08, 0), - RATE(540, 0x0c, 0), -}; - #ifdef CONFIG_MAC80211_LEDS static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = { { .throughput = 0 * 1024, .blink_time = 334 }, @@ -343,6 +256,25 @@ static void ath9k_multi_regread(void *hw_priv, u32 *addr, } } +static void ath9k_regwrite_multi(struct ath_common *common) +{ + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + u32 rsp_status; + int r; + + r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, + (u8 *) &priv->wmi->multi_write, + sizeof(struct register_write) * priv->wmi->multi_write_idx, + (u8 *) &rsp_status, sizeof(rsp_status), + 100); + if (unlikely(r)) { + ath_dbg(common, WMI, + "REGISTER WRITE FAILED, multi len: %d\n", + priv->wmi->multi_write_idx); + } + priv->wmi->multi_write_idx = 0; +} + static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset) { struct ath_hw *ah = (struct ath_hw *) hw_priv; @@ -369,8 +301,6 @@ static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset) struct ath_hw *ah = (struct ath_hw *) hw_priv; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; - u32 rsp_status; - int r; mutex_lock(&priv->wmi->multi_write_mutex); @@ -383,19 +313,8 @@ static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset) priv->wmi->multi_write_idx++; /* If the buffer is full, send it out. */ - if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) { - r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, - (u8 *) &priv->wmi->multi_write, - sizeof(struct register_write) * priv->wmi->multi_write_idx, - (u8 *) &rsp_status, sizeof(rsp_status), - 100); - if (unlikely(r)) { - ath_dbg(common, WMI, - "REGISTER WRITE FAILED, multi len: %d\n", - priv->wmi->multi_write_idx); - } - priv->wmi->multi_write_idx = 0; - } + if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) + ath9k_regwrite_multi(common); mutex_unlock(&priv->wmi->multi_write_mutex); } @@ -426,26 +345,13 @@ static void ath9k_regwrite_flush(void *hw_priv) struct ath_hw *ah = (struct ath_hw *) hw_priv; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; - u32 rsp_status; - int r; atomic_dec(&priv->wmi->mwrite_cnt); mutex_lock(&priv->wmi->multi_write_mutex); - if (priv->wmi->multi_write_idx) { - r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, - (u8 *) &priv->wmi->multi_write, - sizeof(struct register_write) * priv->wmi->multi_write_idx, - (u8 *) &rsp_status, sizeof(rsp_status), - 100); - if (unlikely(r)) { - ath_dbg(common, WMI, - "REGISTER WRITE FAILED, multi len: %d\n", - priv->wmi->multi_write_idx); - } - priv->wmi->multi_write_idx = 0; - } + if (priv->wmi->multi_write_idx) + ath9k_regwrite_multi(common); mutex_unlock(&priv->wmi->multi_write_mutex); } @@ -491,51 +397,6 @@ static const struct ath_bus_ops ath9k_usb_bus_ops = { .eeprom_read = ath_usb_eeprom_read, }; -static void setup_ht_cap(struct ath9k_htc_priv *priv, - struct ieee80211_sta_ht_cap *ht_info) -{ - struct ath_common *common = ath9k_hw_common(priv->ah); - u8 tx_streams, rx_streams; - int i; - - ht_info->ht_supported = true; - ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | - IEEE80211_HT_CAP_SM_PS | - IEEE80211_HT_CAP_SGI_40 | - IEEE80211_HT_CAP_DSSSCCK40; - - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) - ht_info->cap |= IEEE80211_HT_CAP_SGI_20; - - ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); - - ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; - ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; - - memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - - /* ath9k_htc supports only 1 or 2 stream devices */ - tx_streams = ath9k_cmn_count_streams(priv->ah->txchainmask, 2); - rx_streams = ath9k_cmn_count_streams(priv->ah->rxchainmask, 2); - - ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n", - tx_streams, rx_streams); - - if (tx_streams >= 2) - ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; - - if (tx_streams != rx_streams) { - ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; - ht_info->mcs.tx_params |= ((tx_streams - 1) << - IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); - } - - for (i = 0; i < rx_streams; i++) - ht_info->mcs.rx_mask[i] = 0xff; - - ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; -} - static int ath9k_init_queues(struct ath9k_htc_priv *priv) { struct ath_common *common = ath9k_hw_common(priv->ah); @@ -544,8 +405,8 @@ static int ath9k_init_queues(struct ath9k_htc_priv *priv) for (i = 0; i < ARRAY_SIZE(priv->hwq_map); i++) priv->hwq_map[i] = -1; - priv->beaconq = ath9k_hw_beaconq_setup(priv->ah); - if (priv->beaconq == -1) { + priv->beacon.beaconq = ath9k_hw_beaconq_setup(priv->ah); + if (priv->beacon.beaconq == -1) { ath_err(common, "Unable to setup BEACON xmit queue\n"); goto err; } @@ -580,37 +441,13 @@ err: return -EINVAL; } -static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv) -{ - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { - priv->sbands[IEEE80211_BAND_2GHZ].channels = - ath9k_2ghz_channels; - priv->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; - priv->sbands[IEEE80211_BAND_2GHZ].n_channels = - ARRAY_SIZE(ath9k_2ghz_channels); - priv->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; - priv->sbands[IEEE80211_BAND_2GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates); - } - - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) { - priv->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_channels; - priv->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; - priv->sbands[IEEE80211_BAND_5GHZ].n_channels = - ARRAY_SIZE(ath9k_5ghz_channels); - priv->sbands[IEEE80211_BAND_5GHZ].bitrates = - ath9k_legacy_rates + 4; - priv->sbands[IEEE80211_BAND_5GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates) - 4; - } -} - static void ath9k_init_misc(struct ath9k_htc_priv *priv) { struct ath_common *common = ath9k_hw_common(priv->ah); memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); + common->last_rssi = ATH_RSSI_DUMMY_MARKER; priv->ah->opmode = NL80211_IFTYPE_STATION; } @@ -622,12 +459,11 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, struct ath_common *common; int i, ret = 0, csz = 0; - set_bit(OP_INVALID, &priv->op_flags); - ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); if (!ah) return -ENOMEM; + ah->dev = priv->dev; ah->hw_version.devid = devid; ah->hw_version.usbdev = drv_info; ah->ah_flags |= AH_USE_EEPROM; @@ -647,6 +483,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, common->priv = priv; common->debug_mask = ath9k_debug; common->btcoex_enabled = ath9k_htc_btcoex_enable == 1; + set_bit(ATH_OP_INVALID, &common->op_flags); spin_lock_init(&priv->beacon_lock); spin_lock_init(&priv->tx.tx_lock); @@ -682,10 +519,11 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, goto err_queues; for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) - priv->cur_beacon_conf.bslot[i] = NULL; + priv->beacon.bslot[i] = NULL; + priv->beacon.slottime = ATH9K_SLOT_TIME_9; + ath9k_cmn_init_channels_rates(common); ath9k_cmn_init_crypto(ah); - ath9k_init_channels_rates(priv); ath9k_init_misc(priv); ath9k_htc_init_btcoex(priv, product); @@ -721,6 +559,7 @@ static const struct ieee80211_iface_combination if_comb = { static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, struct ieee80211_hw *hw) { + struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(priv->ah); struct base_eep_header *pBase; @@ -765,19 +604,12 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &priv->sbands[IEEE80211_BAND_2GHZ]; + &common->sbands[IEEE80211_BAND_2GHZ]; if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &priv->sbands[IEEE80211_BAND_5GHZ]; - - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) { - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) - setup_ht_cap(priv, - &priv->sbands[IEEE80211_BAND_2GHZ].ht_cap); - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) - setup_ht_cap(priv, - &priv->sbands[IEEE80211_BAND_5GHZ].ht_cap); - } + &common->sbands[IEEE80211_BAND_5GHZ]; + + ath9k_cmn_reload_chainmask(ah); pBase = ath9k_htc_get_eeprom_base(priv); if (pBase) { diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index c9254a61ca52..f46cd0250e48 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -250,7 +250,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, u8 cmd_rsp; int ret; - if (test_bit(OP_INVALID, &priv->op_flags)) + if (test_bit(ATH_OP_INVALID, &common->op_flags)) return -EIO; fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); @@ -304,7 +304,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, htc_start(priv->htc); - if (!test_bit(OP_SCANNING, &priv->op_flags) && + if (!test_bit(ATH_OP_SCANNING, &common->op_flags) && !(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) ath9k_htc_vif_reconfig(priv); @@ -748,7 +748,7 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv) common->ani.shortcal_timer = timestamp; common->ani.checkani_timer = timestamp; - set_bit(OP_ANI_RUNNING, &priv->op_flags); + set_bit(ATH_OP_ANI_RUN, &common->op_flags); ieee80211_queue_delayed_work(common->hw, &priv->ani_work, msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); @@ -756,8 +756,9 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv) void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv) { + struct ath_common *common = ath9k_hw_common(priv->ah); cancel_delayed_work_sync(&priv->ani_work); - clear_bit(OP_ANI_RUNNING, &priv->op_flags); + clear_bit(ATH_OP_ANI_RUN, &common->op_flags); } void ath9k_htc_ani_work(struct work_struct *work) @@ -942,7 +943,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) ath_dbg(common, CONFIG, "Failed to update capability in target\n"); - clear_bit(OP_INVALID, &priv->op_flags); + clear_bit(ATH_OP_INVALID, &common->op_flags); htc_start(priv->htc); spin_lock_bh(&priv->tx.tx_lock); @@ -971,7 +972,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) mutex_lock(&priv->mutex); - if (test_bit(OP_INVALID, &priv->op_flags)) { + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_dbg(common, ANY, "Device not present\n"); mutex_unlock(&priv->mutex); return; @@ -1013,7 +1014,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) ath9k_htc_ps_restore(priv); ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP); - set_bit(OP_INVALID, &priv->op_flags); + set_bit(ATH_OP_INVALID, &common->op_flags); ath_dbg(common, CONFIG, "Driver halt\n"); mutex_unlock(&priv->mutex); @@ -1087,7 +1088,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, ath9k_htc_set_opmode(priv); if ((priv->ah->opmode == NL80211_IFTYPE_AP) && - !test_bit(OP_ANI_RUNNING, &priv->op_flags)) { + !test_bit(ATH_OP_ANI_RUN, &common->op_flags)) { ath9k_hw_set_tsfadjust(priv->ah, true); ath9k_htc_start_ani(priv); } @@ -1245,13 +1246,14 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw, u64 multicast) { struct ath9k_htc_priv *priv = hw->priv; + struct ath_common *common = ath9k_hw_common(priv->ah); u32 rfilt; mutex_lock(&priv->mutex); changed_flags &= SUPPORTED_FILTERS; *total_flags &= SUPPORTED_FILTERS; - if (test_bit(OP_INVALID, &priv->op_flags)) { + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_dbg(ath9k_hw_common(priv->ah), ANY, "Unable to configure filter on invalid state\n"); mutex_unlock(&priv->mutex); @@ -1474,7 +1476,9 @@ static void ath9k_htc_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) if ((vif->type == NL80211_IFTYPE_STATION) && bss_conf->assoc) { common->curaid = bss_conf->aid; + common->last_rssi = ATH_RSSI_DUMMY_MARKER; memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); + set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); } } @@ -1496,6 +1500,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, struct ath9k_htc_priv *priv = hw->priv; struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(ah); + int slottime; mutex_lock(&priv->mutex); ath9k_htc_ps_wakeup(priv); @@ -1507,6 +1512,9 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, bss_conf->assoc ? priv->num_sta_assoc_vif++ : priv->num_sta_assoc_vif--; + if (!bss_conf->assoc) + clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); + if (priv->ah->opmode == NL80211_IFTYPE_STATION) { ath9k_htc_choose_set_bssid(priv); if (bss_conf->assoc && (priv->num_sta_assoc_vif == 1)) @@ -1528,7 +1536,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, ath_dbg(common, CONFIG, "Beacon enabled for BSS: %pM\n", bss_conf->bssid); ath9k_htc_set_tsfadjust(priv, vif); - set_bit(OP_ENABLE_BEACON, &priv->op_flags); + priv->cur_beacon_conf.enable_beacon = 1; ath9k_htc_beacon_config(priv, vif); } @@ -1542,7 +1550,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, ath_dbg(common, CONFIG, "Beacon disabled for BSS: %pM\n", bss_conf->bssid); - clear_bit(OP_ENABLE_BEACON, &priv->op_flags); + priv->cur_beacon_conf.enable_beacon = 0; ath9k_htc_beacon_config(priv, vif); } } @@ -1568,11 +1576,21 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ERP_SLOT) { if (bss_conf->use_short_slot) - ah->slottime = 9; + slottime = 9; else - ah->slottime = 20; - - ath9k_hw_init_global_settings(ah); + slottime = 20; + if (vif->type == NL80211_IFTYPE_AP) { + /* + * Defer update, so that connected stations can adjust + * their settings at the same time. + * See beacon.c for more details + */ + priv->beacon.slottime = slottime; + priv->beacon.updateslot = UPDATE; + } else { + ah->slottime = slottime; + ath9k_hw_init_global_settings(ah); + } } if (changed & BSS_CHANGED_HT) @@ -1669,10 +1687,11 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw) { struct ath9k_htc_priv *priv = hw->priv; + struct ath_common *common = ath9k_hw_common(priv->ah); mutex_lock(&priv->mutex); spin_lock_bh(&priv->beacon_lock); - set_bit(OP_SCANNING, &priv->op_flags); + set_bit(ATH_OP_SCANNING, &common->op_flags); spin_unlock_bh(&priv->beacon_lock); cancel_work_sync(&priv->ps_work); ath9k_htc_stop_ani(priv); @@ -1682,10 +1701,11 @@ static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw) static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw) { struct ath9k_htc_priv *priv = hw->priv; + struct ath_common *common = ath9k_hw_common(priv->ah); mutex_lock(&priv->mutex); spin_lock_bh(&priv->beacon_lock); - clear_bit(OP_SCANNING, &priv->op_flags); + clear_bit(ATH_OP_SCANNING, &common->op_flags); spin_unlock_bh(&priv->beacon_lock); ath9k_htc_ps_wakeup(priv); ath9k_htc_vif_reconfig(priv); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 12e0f32a4905..289f3d8924b5 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -471,8 +471,11 @@ static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, if (!txok || !vif || !txs) goto send_mac80211; - if (txs->ts_flags & ATH9K_HTC_TXSTAT_ACK) + if (txs->ts_flags & ATH9K_HTC_TXSTAT_ACK) { tx_info->flags |= IEEE80211_TX_STAT_ACK; + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) + tx_info->flags |= IEEE80211_TX_STAT_AMPDU; + } if (txs->ts_flags & ATH9K_HTC_TXSTAT_FILT) tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; @@ -924,46 +927,43 @@ static void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv) void ath9k_host_rx_init(struct ath9k_htc_priv *priv) { + struct ath_common *common = ath9k_hw_common(priv->ah); ath9k_hw_rxena(priv->ah); ath9k_htc_opmode_init(priv); - ath9k_hw_startpcureceive(priv->ah, test_bit(OP_SCANNING, &priv->op_flags)); - priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER; + ath9k_hw_startpcureceive(priv->ah, test_bit(ATH_OP_SCANNING, &common->op_flags)); } -static void ath9k_process_rate(struct ieee80211_hw *hw, - struct ieee80211_rx_status *rxs, - u8 rx_rate, u8 rs_flags) +static inline void convert_htc_flag(struct ath_rx_status *rx_stats, + struct ath_htc_rx_status *rxstatus) { - struct ieee80211_supported_band *sband; - enum ieee80211_band band; - unsigned int i = 0; - - if (rx_rate & 0x80) { - /* HT rate */ - rxs->flag |= RX_FLAG_HT; - if (rs_flags & ATH9K_RX_2040) - rxs->flag |= RX_FLAG_40MHZ; - if (rs_flags & ATH9K_RX_GI) - rxs->flag |= RX_FLAG_SHORT_GI; - rxs->rate_idx = rx_rate & 0x7f; - return; - } - - band = hw->conf.chandef.chan->band; - sband = hw->wiphy->bands[band]; - - for (i = 0; i < sband->n_bitrates; i++) { - if (sband->bitrates[i].hw_value == rx_rate) { - rxs->rate_idx = i; - return; - } - if (sband->bitrates[i].hw_value_short == rx_rate) { - rxs->rate_idx = i; - rxs->flag |= RX_FLAG_SHORTPRE; - return; - } - } + rx_stats->flag = 0; + if (rxstatus->rs_flags & ATH9K_RX_2040) + rx_stats->flag |= RX_FLAG_40MHZ; + if (rxstatus->rs_flags & ATH9K_RX_GI) + rx_stats->flag |= RX_FLAG_SHORT_GI; +} +static void rx_status_htc_to_ath(struct ath_rx_status *rx_stats, + struct ath_htc_rx_status *rxstatus) +{ + rx_stats->rs_datalen = rxstatus->rs_datalen; + rx_stats->rs_status = rxstatus->rs_status; + rx_stats->rs_phyerr = rxstatus->rs_phyerr; + rx_stats->rs_rssi = rxstatus->rs_rssi; + rx_stats->rs_keyix = rxstatus->rs_keyix; + rx_stats->rs_rate = rxstatus->rs_rate; + rx_stats->rs_antenna = rxstatus->rs_antenna; + rx_stats->rs_more = rxstatus->rs_more; + + memcpy(rx_stats->rs_rssi_ctl, rxstatus->rs_rssi_ctl, + sizeof(rx_stats->rs_rssi_ctl)); + memcpy(rx_stats->rs_rssi_ext, rxstatus->rs_rssi_ext, + sizeof(rx_stats->rs_rssi_ext)); + + rx_stats->rs_isaggr = rxstatus->rs_isaggr; + rx_stats->rs_moreaggr = rxstatus->rs_moreaggr; + rx_stats->rs_num_delims = rxstatus->rs_num_delims; + convert_htc_flag(rx_stats, rxstatus); } static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, @@ -975,10 +975,10 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, struct ieee80211_hw *hw = priv->hw; struct sk_buff *skb = rxbuf->skb; struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath_hw *ah = common->ah; struct ath_htc_rx_status *rxstatus; - int hdrlen, padsize; - int last_rssi = ATH_RSSI_DUMMY_MARKER; - __le16 fc; + struct ath_rx_status rx_stats; + bool decrypt_error; if (skb->len < HTC_RX_FRAME_HEADER_SIZE) { ath_err(common, "Corrupted RX frame, dropping (len: %d)\n", @@ -999,103 +999,39 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, ath9k_htc_err_stat_rx(priv, rxstatus); /* Get the RX status information */ - memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE); - skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); - - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - - padsize = hdrlen & 3; - if (padsize && skb->len >= hdrlen+padsize+FCS_LEN) { - memmove(skb->data + padsize, skb->data, hdrlen); - skb_pull(skb, padsize); - } memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); - if (rxbuf->rxstatus.rs_status != 0) { - if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_CRC) - rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; - if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_PHY) - goto rx_next; - - if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT) { - /* FIXME */ - } else if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_MIC) { - if (ieee80211_is_ctl(fc)) - /* - * Sometimes, we get invalid - * MIC failures on valid control frames. - * Remove these mic errors. - */ - rxbuf->rxstatus.rs_status &= ~ATH9K_RXERR_MIC; - else - rx_status->flag |= RX_FLAG_MMIC_ERROR; - } - - /* - * Reject error frames with the exception of - * decryption and MIC failures. For monitor mode, - * we also ignore the CRC error. - */ - if (priv->ah->opmode == NL80211_IFTYPE_MONITOR) { - if (rxbuf->rxstatus.rs_status & - ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | - ATH9K_RXERR_CRC)) - goto rx_next; - } else { - if (rxbuf->rxstatus.rs_status & - ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { - goto rx_next; - } - } - } - - if (!(rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT)) { - u8 keyix; - keyix = rxbuf->rxstatus.rs_keyix; - if (keyix != ATH9K_RXKEYIX_INVALID) { - rx_status->flag |= RX_FLAG_DECRYPTED; - } else if (ieee80211_has_protected(fc) && - skb->len >= hdrlen + 4) { - keyix = skb->data[hdrlen + 3] >> 6; - if (test_bit(keyix, common->keymap)) - rx_status->flag |= RX_FLAG_DECRYPTED; - } - } - - ath9k_process_rate(hw, rx_status, rxbuf->rxstatus.rs_rate, - rxbuf->rxstatus.rs_flags); - - if (rxbuf->rxstatus.rs_rssi != ATH9K_RSSI_BAD && - !rxbuf->rxstatus.rs_moreaggr) - ATH_RSSI_LPF(priv->rx.last_rssi, - rxbuf->rxstatus.rs_rssi); - - last_rssi = priv->rx.last_rssi; + /* Copy everything from ath_htc_rx_status (HTC_RX_FRAME_HEADER). + * After this, we can drop this part of skb. */ + rx_status_htc_to_ath(&rx_stats, rxstatus); + rx_status->mactime = be64_to_cpu(rxstatus->rs_tstamp); + skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); - if (ath_is_mybeacon(common, hdr)) { - s8 rssi = rxbuf->rxstatus.rs_rssi; + /* + * everything but the rate is checked here, the rate check is done + * separately to avoid doing two lookups for a rate for each frame. + */ + hdr = (struct ieee80211_hdr *)skb->data; + if (!ath9k_cmn_rx_accept(common, hdr, rx_status, &rx_stats, + &decrypt_error, priv->rxfilter)) + goto rx_next; - if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) - rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); + ath9k_cmn_rx_skb_postprocess(common, skb, &rx_stats, + rx_status, decrypt_error); - if (rssi < 0) - rssi = 0; + if (ath9k_cmn_process_rate(common, hw, &rx_stats, rx_status)) + goto rx_next; - priv->ah->stats.avgbrssi = rssi; - } + rx_stats.is_mybeacon = ath_is_mybeacon(common, hdr); + ath9k_cmn_process_rssi(common, hw, &rx_stats, rx_status); - rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp); - rx_status->band = hw->conf.chandef.chan->band; - rx_status->freq = hw->conf.chandef.chan->center_freq; - rx_status->signal = rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR; - rx_status->antenna = rxbuf->rxstatus.rs_antenna; + rx_status->band = ah->curchan->chan->band; + rx_status->freq = ah->curchan->chan->center_freq; + rx_status->antenna = rx_stats.rs_antenna; rx_status->flag |= RX_FLAG_MACTIME_END; return true; - rx_next: return false; } diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index aac4a406a513..a0ff5b637054 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -358,6 +358,36 @@ ret: kfree_skb(skb); } +static void ath9k_htc_fw_panic_report(struct htc_target *htc_handle, + struct sk_buff *skb) +{ + uint32_t *pattern = (uint32_t *)skb->data; + + switch (*pattern) { + case 0x33221199: + { + struct htc_panic_bad_vaddr *htc_panic; + htc_panic = (struct htc_panic_bad_vaddr *) skb->data; + dev_err(htc_handle->dev, "ath: firmware panic! " + "exccause: 0x%08x; pc: 0x%08x; badvaddr: 0x%08x.\n", + htc_panic->exccause, htc_panic->pc, + htc_panic->badvaddr); + break; + } + case 0x33221299: + { + struct htc_panic_bad_epid *htc_panic; + htc_panic = (struct htc_panic_bad_epid *) skb->data; + dev_err(htc_handle->dev, "ath: firmware panic! " + "bad epid: 0x%08x\n", htc_panic->epid); + break; + } + default: + dev_err(htc_handle->dev, "ath: uknown panic pattern!\n"); + break; + } +} + /* * HTC Messages are handled directly here and the obtained SKB * is freed. @@ -379,6 +409,12 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle, htc_hdr = (struct htc_frame_hdr *) skb->data; epid = htc_hdr->endpoint_id; + if (epid == 0x99) { + ath9k_htc_fw_panic_report(htc_handle, skb); + kfree_skb(skb); + return; + } + if (epid >= ENDPOINT_MAX) { if (pipe_id != USB_REG_IN_PIPE) dev_kfree_skb_any(skb); diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h index e1ffbb6bd636..06474ccc7696 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.h +++ b/drivers/net/wireless/ath/ath9k/htc_hst.h @@ -77,6 +77,18 @@ struct htc_config_pipe_msg { u8 credits; } __packed; +struct htc_panic_bad_vaddr { + __be32 pattern; + __be32 exccause; + __be32 pc; + __be32 badvaddr; +} __packed; + +struct htc_panic_bad_epid { + __be32 pattern; + __be32 epid; +} __packed; + struct htc_ep_callbacks { void *priv; void (*tx) (void *, struct sk_buff *, enum htc_endpoint_id, bool txok); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 9078a6c5a74e..c8a9dfab1fee 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -23,7 +23,6 @@ #include "hw.h" #include "hw-ops.h" -#include "rc.h" #include "ar9003_mac.h" #include "ar9003_mci.h" #include "ar9003_phy.h" @@ -883,7 +882,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, AR_IMR_RXORN | AR_IMR_BCNMISC; - if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) + if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; if (AR_SREV_9300_20_OR_LATER(ah)) { @@ -3048,6 +3047,7 @@ static struct { { AR_SREV_VERSION_9462, "9462" }, { AR_SREV_VERSION_9550, "9550" }, { AR_SREV_VERSION_9565, "9565" }, + { AR_SREV_VERSION_9531, "9531" }, }; /* For devices with external radios */ diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 1fc2e5a26b52..cbbb02a6b13b 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -62,111 +62,6 @@ module_param_named(ps_enable, ath9k_ps_enable, int, 0444); MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); bool is_ath9k_unloaded; -/* We use the hw_value as an index into our private channel structure */ - -#define CHAN2G(_freq, _idx) { \ - .band = IEEE80211_BAND_2GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 20, \ -} - -#define CHAN5G(_freq, _idx) { \ - .band = IEEE80211_BAND_5GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 20, \ -} - -/* Some 2 GHz radios are actually tunable on 2312-2732 - * on 5 MHz steps, we support the channels which we know - * we have calibration data for all cards though to make - * this static */ -static const struct ieee80211_channel ath9k_2ghz_chantable[] = { - CHAN2G(2412, 0), /* Channel 1 */ - CHAN2G(2417, 1), /* Channel 2 */ - CHAN2G(2422, 2), /* Channel 3 */ - CHAN2G(2427, 3), /* Channel 4 */ - CHAN2G(2432, 4), /* Channel 5 */ - CHAN2G(2437, 5), /* Channel 6 */ - CHAN2G(2442, 6), /* Channel 7 */ - CHAN2G(2447, 7), /* Channel 8 */ - CHAN2G(2452, 8), /* Channel 9 */ - CHAN2G(2457, 9), /* Channel 10 */ - CHAN2G(2462, 10), /* Channel 11 */ - CHAN2G(2467, 11), /* Channel 12 */ - CHAN2G(2472, 12), /* Channel 13 */ - CHAN2G(2484, 13), /* Channel 14 */ -}; - -/* Some 5 GHz radios are actually tunable on XXXX-YYYY - * on 5 MHz steps, we support the channels which we know - * we have calibration data for all cards though to make - * this static */ -static const struct ieee80211_channel ath9k_5ghz_chantable[] = { - /* _We_ call this UNII 1 */ - CHAN5G(5180, 14), /* Channel 36 */ - CHAN5G(5200, 15), /* Channel 40 */ - CHAN5G(5220, 16), /* Channel 44 */ - CHAN5G(5240, 17), /* Channel 48 */ - /* _We_ call this UNII 2 */ - CHAN5G(5260, 18), /* Channel 52 */ - CHAN5G(5280, 19), /* Channel 56 */ - CHAN5G(5300, 20), /* Channel 60 */ - CHAN5G(5320, 21), /* Channel 64 */ - /* _We_ call this "Middle band" */ - CHAN5G(5500, 22), /* Channel 100 */ - CHAN5G(5520, 23), /* Channel 104 */ - CHAN5G(5540, 24), /* Channel 108 */ - CHAN5G(5560, 25), /* Channel 112 */ - CHAN5G(5580, 26), /* Channel 116 */ - CHAN5G(5600, 27), /* Channel 120 */ - CHAN5G(5620, 28), /* Channel 124 */ - CHAN5G(5640, 29), /* Channel 128 */ - CHAN5G(5660, 30), /* Channel 132 */ - CHAN5G(5680, 31), /* Channel 136 */ - CHAN5G(5700, 32), /* Channel 140 */ - /* _We_ call this UNII 3 */ - CHAN5G(5745, 33), /* Channel 149 */ - CHAN5G(5765, 34), /* Channel 153 */ - CHAN5G(5785, 35), /* Channel 157 */ - CHAN5G(5805, 36), /* Channel 161 */ - CHAN5G(5825, 37), /* Channel 165 */ -}; - -/* Atheros hardware rate code addition for short premble */ -#define SHPCHECK(__hw_rate, __flags) \ - ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0) - -#define RATE(_bitrate, _hw_rate, _flags) { \ - .bitrate = (_bitrate), \ - .flags = (_flags), \ - .hw_value = (_hw_rate), \ - .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ -} - -static struct ieee80211_rate ath9k_legacy_rates[] = { - RATE(10, 0x1b, 0), - RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(60, 0x0b, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), - RATE(90, 0x0f, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), - RATE(120, 0x0a, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), - RATE(180, 0x0e, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), - RATE(240, 0x09, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), - RATE(360, 0x0d, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), - RATE(480, 0x08, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), - RATE(540, 0x0c, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), -}; #ifdef CONFIG_MAC80211_LEDS static const struct ieee80211_tpt_blink ath9k_tpt_blink[] = { @@ -258,64 +153,6 @@ static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 cl /* Initialization */ /**************************/ -static void setup_ht_cap(struct ath_softc *sc, - struct ieee80211_sta_ht_cap *ht_info) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - u8 tx_streams, rx_streams; - int i, max_streams; - - ht_info->ht_supported = true; - ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | - IEEE80211_HT_CAP_SM_PS | - IEEE80211_HT_CAP_SGI_40 | - IEEE80211_HT_CAP_DSSSCCK40; - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_LDPC) - ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) - ht_info->cap |= IEEE80211_HT_CAP_SGI_20; - - ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; - ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; - - if (AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) - max_streams = 1; - else if (AR_SREV_9462(ah)) - max_streams = 2; - else if (AR_SREV_9300_20_OR_LATER(ah)) - max_streams = 3; - else - max_streams = 2; - - if (AR_SREV_9280_20_OR_LATER(ah)) { - if (max_streams >= 2) - ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; - ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); - } - - /* set up supported mcs set */ - memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams); - rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams); - - ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n", - tx_streams, rx_streams); - - if (tx_streams != rx_streams) { - ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; - ht_info->mcs.tx_params |= ((tx_streams - 1) << - IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); - } - - for (i = 0; i < rx_streams; i++) - ht_info->mcs.rx_mask[i] = 0xff; - - ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; -} - static void ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { @@ -486,51 +323,6 @@ static int ath9k_init_queues(struct ath_softc *sc) return 0; } -static int ath9k_init_channels_rates(struct ath_softc *sc) -{ - void *channels; - - BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) + - ARRAY_SIZE(ath9k_5ghz_chantable) != - ATH9K_NUM_CHANNELS); - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { - channels = devm_kzalloc(sc->dev, - sizeof(ath9k_2ghz_chantable), GFP_KERNEL); - if (!channels) - return -ENOMEM; - - memcpy(channels, ath9k_2ghz_chantable, - sizeof(ath9k_2ghz_chantable)); - sc->sbands[IEEE80211_BAND_2GHZ].channels = channels; - sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; - sc->sbands[IEEE80211_BAND_2GHZ].n_channels = - ARRAY_SIZE(ath9k_2ghz_chantable); - sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; - sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates); - } - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) { - channels = devm_kzalloc(sc->dev, - sizeof(ath9k_5ghz_chantable), GFP_KERNEL); - if (!channels) - return -ENOMEM; - - memcpy(channels, ath9k_5ghz_chantable, - sizeof(ath9k_5ghz_chantable)); - sc->sbands[IEEE80211_BAND_5GHZ].channels = channels; - sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; - sc->sbands[IEEE80211_BAND_5GHZ].n_channels = - ARRAY_SIZE(ath9k_5ghz_chantable); - sc->sbands[IEEE80211_BAND_5GHZ].bitrates = - ath9k_legacy_rates + 4; - sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates) - 4; - } - return 0; -} - static void ath9k_init_misc(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); @@ -538,7 +330,7 @@ static void ath9k_init_misc(struct ath_softc *sc) setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); - sc->last_rssi = ATH_RSSI_DUMMY_MARKER; + common->last_rssi = ATH_RSSI_DUMMY_MARKER; sc->config.txpowlimit = ATH_TXPOWER_MAX; memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); sc->beacon.slottime = ATH9K_SLOT_TIME_9; @@ -793,7 +585,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, if (ret) goto err_btcoex; - ret = ath9k_init_channels_rates(sc); + ret = ath9k_cmn_init_channels_rates(common); if (ret) goto err_btcoex; @@ -823,10 +615,11 @@ static void ath9k_init_band_txpower(struct ath_softc *sc, int band) struct ieee80211_supported_band *sband; struct ieee80211_channel *chan; struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct cfg80211_chan_def chandef; int i; - sband = &sc->sbands[band]; + sband = &common->sbands[band]; for (i = 0; i < sband->n_channels; i++) { chan = &sband->channels[i]; ah->curchan = &ah->channels[chan->hw_value]; @@ -849,17 +642,6 @@ static void ath9k_init_txpower_limits(struct ath_softc *sc) ah->curchan = curchan; } -void ath9k_reload_chainmask_settings(struct ath_softc *sc) -{ - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)) - return; - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) - setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) - setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); -} - static const struct ieee80211_iface_limit if_limits[] = { { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_P2P_CLIENT) | @@ -888,6 +670,7 @@ static const struct ieee80211_iface_combination if_comb[] = { .num_different_channels = 1, .beacon_int_infra_match = true, }, +#ifdef CONFIG_ATH9K_DFS_CERTIFIED { .limits = if_dfs_limits, .n_limits = ARRAY_SIZE(if_dfs_limits), @@ -897,6 +680,7 @@ static const struct ieee80211_iface_combination if_comb[] = { .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | BIT(NL80211_CHAN_WIDTH_20), } +#endif }; static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) @@ -949,6 +733,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ; hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; hw->queues = 4; hw->max_rates = 4; @@ -969,13 +754,13 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &sc->sbands[IEEE80211_BAND_2GHZ]; + &common->sbands[IEEE80211_BAND_2GHZ]; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &sc->sbands[IEEE80211_BAND_5GHZ]; + &common->sbands[IEEE80211_BAND_5GHZ]; ath9k_init_wow(hw); - ath9k_reload_chainmask_settings(sc); + ath9k_cmn_reload_chainmask(ah); SET_IEEE80211_PERM_ADDR(hw, common->macaddr); } @@ -1106,19 +891,11 @@ static int __init ath9k_init(void) { int error; - /* Register rate control algorithm */ - error = ath_rate_control_register(); - if (error != 0) { - pr_err("Unable to register rate control algorithm: %d\n", - error); - goto err_out; - } - error = ath_pci_init(); if (error < 0) { pr_err("No PCI devices found, driver not installed\n"); error = -ENODEV; - goto err_rate_unregister; + goto err_out; } error = ath_ahb_init(); @@ -1131,9 +908,6 @@ static int __init ath9k_init(void) err_pci_exit: ath_pci_exit(); - - err_rate_unregister: - ath_rate_control_unregister(); err_out: return error; } @@ -1144,7 +918,6 @@ static void __exit ath9k_exit(void) is_ath9k_unloaded = true; ath_ahb_exit(); ath_pci_exit(); - ath_rate_control_unregister(); pr_info("%s: Driver unloaded\n", dev_info); } module_exit(ath9k_exit); diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 30dcef5aba10..72a715fe8f24 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -115,13 +115,14 @@ void ath_hw_pll_work(struct work_struct *work) u32 pll_sqsum; struct ath_softc *sc = container_of(work, struct ath_softc, hw_pll_work.work); + struct ath_common *common = ath9k_hw_common(sc->sc_ah); /* * ensure that the PLL WAR is executed only * after the STA is associated (or) if the * beaconing had started in interfaces that * uses beacons. */ - if (!test_bit(SC_OP_BEACONS, &sc->sc_flags)) + if (!test_bit(ATH_OP_BEACONS, &common->op_flags)) return; if (sc->tx99_state) @@ -414,7 +415,7 @@ void ath_start_ani(struct ath_softc *sc) unsigned long timestamp = jiffies_to_msecs(jiffies); if (common->disable_ani || - !test_bit(SC_OP_ANI_RUN, &sc->sc_flags) || + !test_bit(ATH_OP_ANI_RUN, &common->op_flags) || (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) return; @@ -438,6 +439,7 @@ void ath_stop_ani(struct ath_softc *sc) void ath_check_ani(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; /* @@ -453,23 +455,23 @@ void ath_check_ani(struct ath_softc *sc) * Disable ANI only when there are no * associated stations. */ - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) goto stop_ani; } } else if (ah->opmode == NL80211_IFTYPE_STATION) { - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) goto stop_ani; } - if (!test_bit(SC_OP_ANI_RUN, &sc->sc_flags)) { - set_bit(SC_OP_ANI_RUN, &sc->sc_flags); + if (!test_bit(ATH_OP_ANI_RUN, &common->op_flags)) { + set_bit(ATH_OP_ANI_RUN, &common->op_flags); ath_start_ani(sc); } return; stop_ani: - clear_bit(SC_OP_ANI_RUN, &sc->sc_flags); + clear_bit(ATH_OP_ANI_RUN, &common->op_flags); ath_stop_ani(sc); } diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 5f727588ca27..51ce36f108f9 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -827,7 +827,7 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) return; } - if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) + if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; async_mask = AR_INTR_MAC_IRQ; diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 10271373a0cd..89df634e81f9 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -155,12 +155,8 @@ struct ath_htc_rx_status { u8 rs_status; u8 rs_phyerr; int8_t rs_rssi; - int8_t rs_rssi_ctl0; - int8_t rs_rssi_ctl1; - int8_t rs_rssi_ctl2; - int8_t rs_rssi_ext0; - int8_t rs_rssi_ext1; - int8_t rs_rssi_ext2; + int8_t rs_rssi_ctl[3]; + int8_t rs_rssi_ext[3]; u8 rs_keyix; u8 rs_rate; u8 rs_antenna; @@ -170,6 +166,7 @@ struct ath_htc_rx_status { u8 rs_num_delims; u8 rs_flags; u8 rs_dummy; + /* FIXME: evm* never used? */ __be32 evm0; __be32 evm1; __be32 evm2; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 5924f72dd493..d69853b848ce 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -229,16 +229,16 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) ath9k_cmn_update_txpow(ah, sc->curtxpow, sc->config.txpowlimit, &sc->curtxpow); - clear_bit(SC_OP_HW_RESET, &sc->sc_flags); + clear_bit(ATH_OP_HW_RESET, &common->op_flags); ath9k_hw_set_interrupts(ah); ath9k_hw_enable_interrupts(ah); if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) && start) { - if (!test_bit(SC_OP_BEACONS, &sc->sc_flags)) + if (!test_bit(ATH_OP_BEACONS, &common->op_flags)) goto work; if (ah->opmode == NL80211_IFTYPE_STATION && - test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { + test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { spin_lock_irqsave(&sc->sc_pm_lock, flags); sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; spin_unlock_irqrestore(&sc->sc_pm_lock, flags); @@ -336,7 +336,7 @@ static int ath_set_channel(struct ath_softc *sc, struct cfg80211_chan_def *chand int old_pos = -1; int r; - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) + if (test_bit(ATH_OP_INVALID, &common->op_flags)) return -EIO; offchannel = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); @@ -402,7 +402,7 @@ static int ath_set_channel(struct ath_softc *sc, struct cfg80211_chan_def *chand chan->center_freq); } else { /* perform spectral scan if requested. */ - if (test_bit(SC_OP_SCANNING, &sc->sc_flags) && + if (test_bit(ATH_OP_SCANNING, &common->op_flags) && sc->spectral_mode == SPECTRAL_CHANSCAN) ath9k_spectral_scan_trigger(hw); } @@ -451,7 +451,7 @@ void ath9k_tasklet(unsigned long data) * interrupts are enabled in the reset routine. */ atomic_inc(&ah->intr_ref_cnt); - ath_dbg(common, ANY, "FATAL: Skipping interrupts\n"); + ath_dbg(common, RESET, "FATAL: Skipping interrupts\n"); goto out; } @@ -471,7 +471,7 @@ void ath9k_tasklet(unsigned long data) * interrupts are enabled in the reset routine. */ atomic_inc(&ah->intr_ref_cnt); - ath_dbg(common, ANY, + ath_dbg(common, RESET, "BB_WATCHDOG: Skipping interrupts\n"); goto out; } @@ -484,7 +484,7 @@ void ath9k_tasklet(unsigned long data) type = RESET_TYPE_TX_GTT; ath9k_queue_reset(sc, type); atomic_inc(&ah->intr_ref_cnt); - ath_dbg(common, ANY, + ath_dbg(common, RESET, "GTT: Skipping interrupts\n"); goto out; } @@ -566,6 +566,7 @@ irqreturn_t ath_isr(int irq, void *dev) struct ath_softc *sc = dev; struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); enum ath9k_int status; u32 sync_cause = 0; bool sched = false; @@ -575,7 +576,7 @@ irqreturn_t ath_isr(int irq, void *dev) * touch anything. Note this can happen early * on if the IRQ is shared. */ - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) + if (test_bit(ATH_OP_INVALID, &common->op_flags)) return IRQ_NONE; /* shared irq, not for us */ @@ -583,7 +584,7 @@ irqreturn_t ath_isr(int irq, void *dev) if (!ath9k_hw_intrpend(ah)) return IRQ_NONE; - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) { + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) { ath9k_hw_kill_interrupts(ah); return IRQ_HANDLED; } @@ -684,10 +685,11 @@ int ath_reset(struct ath_softc *sc) void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); #ifdef CONFIG_ATH9K_DEBUGFS RESET_STAT_INC(sc, type); #endif - set_bit(SC_OP_HW_RESET, &sc->sc_flags); + set_bit(ATH_OP_HW_RESET, &common->op_flags); ieee80211_queue_work(sc->hw, &sc->hw_reset_work); } @@ -768,7 +770,7 @@ static int ath9k_start(struct ieee80211_hw *hw) ath_mci_enable(sc); - clear_bit(SC_OP_INVALID, &sc->sc_flags); + clear_bit(ATH_OP_INVALID, &common->op_flags); sc->sc_ah->is_monitoring = false; if (!ath_complete_reset(sc, false)) @@ -885,7 +887,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) ath_cancel_work(sc); - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_dbg(common, ANY, "Device not present\n"); mutex_unlock(&sc->mutex); return; @@ -940,7 +942,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) ath9k_ps_restore(sc); - set_bit(SC_OP_INVALID, &sc->sc_flags); + set_bit(ATH_OP_INVALID, &common->op_flags); sc->ps_idle = prev_idle; mutex_unlock(&sc->mutex); @@ -1081,7 +1083,7 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, */ if (ah->opmode == NL80211_IFTYPE_STATION && old_opmode == NL80211_IFTYPE_AP && - test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { + test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { ieee80211_iterate_active_interfaces_atomic( sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, ath9k_sta_vif_iter, sc); @@ -1178,9 +1180,6 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, if (ath9k_uses_beacons(vif->type)) ath9k_beacon_remove_slot(sc, vif); - if (sc->csa_vif == vif) - sc->csa_vif = NULL; - ath9k_ps_wakeup(sc); ath9k_calculate_summary_state(hw, NULL); ath9k_ps_restore(sc); @@ -1593,7 +1592,7 @@ static void ath9k_set_assoc_state(struct ath_softc *sc, struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; unsigned long flags; - set_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags); + set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); avp->primary_sta_vif = true; /* @@ -1609,7 +1608,7 @@ static void ath9k_set_assoc_state(struct ath_softc *sc, common->curaid = bss_conf->aid; ath9k_hw_write_associd(sc->sc_ah); - sc->last_rssi = ATH_RSSI_DUMMY_MARKER; + common->last_rssi = ATH_RSSI_DUMMY_MARKER; sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; spin_lock_irqsave(&sc->sc_pm_lock, flags); @@ -1628,8 +1627,9 @@ static void ath9k_bss_assoc_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { struct ath_softc *sc = data; struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); - if (test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) + if (test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) return; if (bss_conf->assoc) @@ -1660,18 +1660,18 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, bss_conf->bssid, bss_conf->assoc); if (avp->primary_sta_vif && !bss_conf->assoc) { - clear_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags); + clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); avp->primary_sta_vif = false; if (ah->opmode == NL80211_IFTYPE_STATION) - clear_bit(SC_OP_BEACONS, &sc->sc_flags); + clear_bit(ATH_OP_BEACONS, &common->op_flags); } ieee80211_iterate_active_interfaces_atomic( sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, ath9k_bss_assoc_iter, sc); - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags) && + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags) && ah->opmode == NL80211_IFTYPE_STATION) { memset(common->curbssid, 0, ETH_ALEN); common->curaid = 0; @@ -1866,7 +1866,7 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) static bool ath9k_has_tx_pending(struct ath_softc *sc) { - int i, npend; + int i, npend = 0; for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (!ATH_TXQ_SETUP(sc, i)) @@ -1900,7 +1900,7 @@ static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) return; } - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_dbg(common, ANY, "Device not present\n"); mutex_unlock(&sc->mutex); return; @@ -2056,7 +2056,7 @@ static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) ah->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant); ah->txchainmask = fill_chainmask(ah->caps.tx_chainmask, tx_ant); - ath9k_reload_chainmask_settings(sc); + ath9k_cmn_reload_chainmask(ah); return 0; } @@ -2073,26 +2073,23 @@ static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) static void ath9k_sw_scan_start(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; - set_bit(SC_OP_SCANNING, &sc->sc_flags); + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + set_bit(ATH_OP_SCANNING, &common->op_flags); } static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; - clear_bit(SC_OP_SCANNING, &sc->sc_flags); + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + clear_bit(ATH_OP_SCANNING, &common->op_flags); } static void ath9k_channel_switch_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_chan_def *chandef) { - struct ath_softc *sc = hw->priv; - - /* mac80211 does not support CSA in multi-if cases (yet) */ - if (WARN_ON(sc->csa_vif)) - return; - - sc->csa_vif = vif; + /* depend on vif->csa_active only */ + return; } struct ieee80211_ops ath9k_ops = { diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 71799fcade54..a0dbcc412384 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -555,7 +555,7 @@ void ath_mci_intr(struct ath_softc *sc) mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_GPM; while (more_data == MCI_GPM_MORE) { - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) return; pgpm = mci->gpm_buf.bf_addr; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 55724b02316b..25304adece57 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -784,6 +784,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct ath_softc *sc; struct ieee80211_hw *hw; + struct ath_common *common; u8 csz; u32 val; int ret = 0; @@ -858,9 +859,6 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) sc->mem = pcim_iomap_table(pdev)[0]; sc->driver_data = id->driver_data; - /* Will be cleared in ath9k_start() */ - set_bit(SC_OP_INVALID, &sc->sc_flags); - ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc); if (ret) { dev_err(&pdev->dev, "request_irq failed\n"); @@ -879,6 +877,10 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n", hw_name, (unsigned long)sc->mem, pdev->irq); + /* Will be cleared in ath9k_start() */ + common = ath9k_hw_common(sc->sc_ah); + set_bit(ATH_OP_INVALID, &common->op_flags); + return 0; err_init: diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c deleted file mode 100644 index d829bb62a3fc..000000000000 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ /dev/null @@ -1,1495 +0,0 @@ -/* - * Copyright (c) 2004 Video54 Technologies, Inc. - * Copyright (c) 2004-2011 Atheros Communications, 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 <linux/slab.h> -#include <linux/export.h> - -#include "ath9k.h" - -static const struct ath_rate_table ar5416_11na_ratetable = { - 68, - 8, /* MCS start */ - { - [0] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 6000, - 5400, 0, 12 }, /* 6 Mb */ - [1] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 9000, - 7800, 1, 18 }, /* 9 Mb */ - [2] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, - 10000, 2, 24 }, /* 12 Mb */ - [3] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, - 13900, 3, 36 }, /* 18 Mb */ - [4] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, - 17300, 4, 48 }, /* 24 Mb */ - [5] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, - 23000, 5, 72 }, /* 36 Mb */ - [6] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, - 27400, 6, 96 }, /* 48 Mb */ - [7] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, - 29300, 7, 108 }, /* 54 Mb */ - [8] = { RC_HT_SDT_2040, WLAN_RC_PHY_HT_20_SS, 6500, - 6400, 0, 0 }, /* 6.5 Mb */ - [9] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 13000, - 12700, 1, 1 }, /* 13 Mb */ - [10] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 19500, - 18800, 2, 2 }, /* 19.5 Mb */ - [11] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 26000, - 25000, 3, 3 }, /* 26 Mb */ - [12] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 39000, - 36700, 4, 4 }, /* 39 Mb */ - [13] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 52000, - 48100, 5, 5 }, /* 52 Mb */ - [14] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 58500, - 53500, 6, 6 }, /* 58.5 Mb */ - [15] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 65000, - 59000, 7, 7 }, /* 65 Mb */ - [16] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS_HGI, 72200, - 65400, 7, 7 }, /* 75 Mb */ - [17] = { RC_INVALID, WLAN_RC_PHY_HT_20_DS, 13000, - 12700, 8, 8 }, /* 13 Mb */ - [18] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 26000, - 24800, 9, 9 }, /* 26 Mb */ - [19] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 39000, - 36600, 10, 10 }, /* 39 Mb */ - [20] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 52000, - 48100, 11, 11 }, /* 52 Mb */ - [21] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 78000, - 69500, 12, 12 }, /* 78 Mb */ - [22] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 104000, - 89500, 13, 13 }, /* 104 Mb */ - [23] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 117000, - 98900, 14, 14 }, /* 117 Mb */ - [24] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 130000, - 108300, 15, 15 }, /* 130 Mb */ - [25] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS_HGI, 144400, - 120000, 15, 15 }, /* 144.4 Mb */ - [26] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 19500, - 17400, 16, 16 }, /* 19.5 Mb */ - [27] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 39000, - 35100, 17, 17 }, /* 39 Mb */ - [28] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 58500, - 52600, 18, 18 }, /* 58.5 Mb */ - [29] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 78000, - 70400, 19, 19 }, /* 78 Mb */ - [30] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 117000, - 104900, 20, 20 }, /* 117 Mb */ - [31] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS_HGI, 130000, - 115800, 20, 20 }, /* 130 Mb*/ - [32] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 156000, - 137200, 21, 21 }, /* 156 Mb */ - [33] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 173300, - 151100, 21, 21 }, /* 173.3 Mb */ - [34] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 175500, - 152800, 22, 22 }, /* 175.5 Mb */ - [35] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 195000, - 168400, 22, 22 }, /* 195 Mb*/ - [36] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 195000, - 168400, 23, 23 }, /* 195 Mb */ - [37] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 216700, - 185000, 23, 23 }, /* 216.7 Mb */ - [38] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 13500, - 13200, 0, 0 }, /* 13.5 Mb*/ - [39] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 27500, - 25900, 1, 1 }, /* 27.0 Mb*/ - [40] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 40500, - 38600, 2, 2 }, /* 40.5 Mb*/ - [41] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 54000, - 49800, 3, 3 }, /* 54 Mb */ - [42] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 81500, - 72200, 4, 4 }, /* 81 Mb */ - [43] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 108000, - 92900, 5, 5 }, /* 108 Mb */ - [44] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 121500, - 102700, 6, 6 }, /* 121.5 Mb*/ - [45] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 135000, - 112000, 7, 7 }, /* 135 Mb */ - [46] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, - 122000, 7, 7 }, /* 150 Mb */ - [47] = { RC_INVALID, WLAN_RC_PHY_HT_40_DS, 27000, - 25800, 8, 8 }, /* 27 Mb */ - [48] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 54000, - 49800, 9, 9 }, /* 54 Mb */ - [49] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 81000, - 71900, 10, 10 }, /* 81 Mb */ - [50] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 108000, - 92500, 11, 11 }, /* 108 Mb */ - [51] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 162000, - 130300, 12, 12 }, /* 162 Mb */ - [52] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 216000, - 162800, 13, 13 }, /* 216 Mb */ - [53] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 243000, - 178200, 14, 14 }, /* 243 Mb */ - [54] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 270000, - 192100, 15, 15 }, /* 270 Mb */ - [55] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS_HGI, 300000, - 207000, 15, 15 }, /* 300 Mb */ - [56] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 40500, - 36100, 16, 16 }, /* 40.5 Mb */ - [57] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 81000, - 72900, 17, 17 }, /* 81 Mb */ - [58] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 121500, - 108300, 18, 18 }, /* 121.5 Mb */ - [59] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 162000, - 142000, 19, 19 }, /* 162 Mb */ - [60] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000, - 205100, 20, 20 }, /* 243 Mb */ - [61] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000, - 224700, 20, 20 }, /* 270 Mb */ - [62] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000, - 263100, 21, 21 }, /* 324 Mb */ - [63] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000, - 288000, 21, 21 }, /* 360 Mb */ - [64] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 364500, - 290700, 22, 22 }, /* 364.5 Mb */ - [65] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 405000, - 317200, 22, 22 }, /* 405 Mb */ - [66] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 405000, - 317200, 23, 23 }, /* 405 Mb */ - [67] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 450000, - 346400, 23, 23 }, /* 450 Mb */ - }, - 50, /* probe interval */ - WLAN_RC_HT_FLAG, /* Phy rates allowed initially */ -}; - -/* 4ms frame limit not used for NG mode. The values filled - * for HT are the 64K max aggregate limit */ - -static const struct ath_rate_table ar5416_11ng_ratetable = { - 72, - 12, /* MCS start */ - { - [0] = { RC_ALL, WLAN_RC_PHY_CCK, 1000, - 900, 0, 2 }, /* 1 Mb */ - [1] = { RC_ALL, WLAN_RC_PHY_CCK, 2000, - 1900, 1, 4 }, /* 2 Mb */ - [2] = { RC_ALL, WLAN_RC_PHY_CCK, 5500, - 4900, 2, 11 }, /* 5.5 Mb */ - [3] = { RC_ALL, WLAN_RC_PHY_CCK, 11000, - 8100, 3, 22 }, /* 11 Mb */ - [4] = { RC_INVALID, WLAN_RC_PHY_OFDM, 6000, - 5400, 4, 12 }, /* 6 Mb */ - [5] = { RC_INVALID, WLAN_RC_PHY_OFDM, 9000, - 7800, 5, 18 }, /* 9 Mb */ - [6] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, - 10100, 6, 24 }, /* 12 Mb */ - [7] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, - 14100, 7, 36 }, /* 18 Mb */ - [8] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, - 17700, 8, 48 }, /* 24 Mb */ - [9] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, - 23700, 9, 72 }, /* 36 Mb */ - [10] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, - 27400, 10, 96 }, /* 48 Mb */ - [11] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, - 30900, 11, 108 }, /* 54 Mb */ - [12] = { RC_INVALID, WLAN_RC_PHY_HT_20_SS, 6500, - 6400, 0, 0 }, /* 6.5 Mb */ - [13] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 13000, - 12700, 1, 1 }, /* 13 Mb */ - [14] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 19500, - 18800, 2, 2 }, /* 19.5 Mb*/ - [15] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 26000, - 25000, 3, 3 }, /* 26 Mb */ - [16] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 39000, - 36700, 4, 4 }, /* 39 Mb */ - [17] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 52000, - 48100, 5, 5 }, /* 52 Mb */ - [18] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 58500, - 53500, 6, 6 }, /* 58.5 Mb */ - [19] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 65000, - 59000, 7, 7 }, /* 65 Mb */ - [20] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS_HGI, 72200, - 65400, 7, 7 }, /* 65 Mb*/ - [21] = { RC_INVALID, WLAN_RC_PHY_HT_20_DS, 13000, - 12700, 8, 8 }, /* 13 Mb */ - [22] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 26000, - 24800, 9, 9 }, /* 26 Mb */ - [23] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 39000, - 36600, 10, 10 }, /* 39 Mb */ - [24] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 52000, - 48100, 11, 11 }, /* 52 Mb */ - [25] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 78000, - 69500, 12, 12 }, /* 78 Mb */ - [26] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 104000, - 89500, 13, 13 }, /* 104 Mb */ - [27] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 117000, - 98900, 14, 14 }, /* 117 Mb */ - [28] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 130000, - 108300, 15, 15 }, /* 130 Mb */ - [29] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS_HGI, 144400, - 120000, 15, 15 }, /* 144.4 Mb */ - [30] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 19500, - 17400, 16, 16 }, /* 19.5 Mb */ - [31] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 39000, - 35100, 17, 17 }, /* 39 Mb */ - [32] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 58500, - 52600, 18, 18 }, /* 58.5 Mb */ - [33] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 78000, - 70400, 19, 19 }, /* 78 Mb */ - [34] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 117000, - 104900, 20, 20 }, /* 117 Mb */ - [35] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS_HGI, 130000, - 115800, 20, 20 }, /* 130 Mb */ - [36] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 156000, - 137200, 21, 21 }, /* 156 Mb */ - [37] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 173300, - 151100, 21, 21 }, /* 173.3 Mb */ - [38] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 175500, - 152800, 22, 22 }, /* 175.5 Mb */ - [39] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 195000, - 168400, 22, 22 }, /* 195 Mb */ - [40] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 195000, - 168400, 23, 23 }, /* 195 Mb */ - [41] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 216700, - 185000, 23, 23 }, /* 216.7 Mb */ - [42] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 13500, - 13200, 0, 0 }, /* 13.5 Mb */ - [43] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 27500, - 25900, 1, 1 }, /* 27.0 Mb */ - [44] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 40500, - 38600, 2, 2 }, /* 40.5 Mb */ - [45] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 54000, - 49800, 3, 3 }, /* 54 Mb */ - [46] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 81500, - 72200, 4, 4 }, /* 81 Mb */ - [47] = { RC_HT_S_40 , WLAN_RC_PHY_HT_40_SS, 108000, - 92900, 5, 5 }, /* 108 Mb */ - [48] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 121500, - 102700, 6, 6 }, /* 121.5 Mb */ - [49] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 135000, - 112000, 7, 7 }, /* 135 Mb */ - [50] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, - 122000, 7, 7 }, /* 150 Mb */ - [51] = { RC_INVALID, WLAN_RC_PHY_HT_40_DS, 27000, - 25800, 8, 8 }, /* 27 Mb */ - [52] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 54000, - 49800, 9, 9 }, /* 54 Mb */ - [53] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 81000, - 71900, 10, 10 }, /* 81 Mb */ - [54] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 108000, - 92500, 11, 11 }, /* 108 Mb */ - [55] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 162000, - 130300, 12, 12 }, /* 162 Mb */ - [56] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 216000, - 162800, 13, 13 }, /* 216 Mb */ - [57] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 243000, - 178200, 14, 14 }, /* 243 Mb */ - [58] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 270000, - 192100, 15, 15 }, /* 270 Mb */ - [59] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS_HGI, 300000, - 207000, 15, 15 }, /* 300 Mb */ - [60] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 40500, - 36100, 16, 16 }, /* 40.5 Mb */ - [61] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 81000, - 72900, 17, 17 }, /* 81 Mb */ - [62] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 121500, - 108300, 18, 18 }, /* 121.5 Mb */ - [63] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 162000, - 142000, 19, 19 }, /* 162 Mb */ - [64] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000, - 205100, 20, 20 }, /* 243 Mb */ - [65] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000, - 224700, 20, 20 }, /* 270 Mb */ - [66] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000, - 263100, 21, 21 }, /* 324 Mb */ - [67] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000, - 288000, 21, 21 }, /* 360 Mb */ - [68] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 364500, - 290700, 22, 22 }, /* 364.5 Mb */ - [69] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 405000, - 317200, 22, 22 }, /* 405 Mb */ - [70] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 405000, - 317200, 23, 23 }, /* 405 Mb */ - [71] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 450000, - 346400, 23, 23 }, /* 450 Mb */ - }, - 50, /* probe interval */ - WLAN_RC_HT_FLAG, /* Phy rates allowed initially */ -}; - -static const struct ath_rate_table ar5416_11a_ratetable = { - 8, - 0, - { - { RC_L_SDT, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ - 5400, 0, 12}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ - 7800, 1, 18}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ - 10000, 2, 24}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ - 13900, 3, 36}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ - 17300, 4, 48}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ - 23000, 5, 72}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ - 27400, 6, 96}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ - 29300, 7, 108}, - }, - 50, /* probe interval */ - 0, /* Phy rates allowed initially */ -}; - -static const struct ath_rate_table ar5416_11g_ratetable = { - 12, - 0, - { - { RC_L_SDT, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ - 900, 0, 2}, - { RC_L_SDT, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ - 1900, 1, 4}, - { RC_L_SDT, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ - 4900, 2, 11}, - { RC_L_SDT, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ - 8100, 3, 22}, - { RC_INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ - 5400, 4, 12}, - { RC_INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ - 7800, 5, 18}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ - 10000, 6, 24}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ - 13900, 7, 36}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ - 17300, 8, 48}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ - 23000, 9, 72}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ - 27400, 10, 96}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ - 29300, 11, 108}, - }, - 50, /* probe interval */ - 0, /* Phy rates allowed initially */ -}; - -static int ath_rc_get_rateindex(struct ath_rate_priv *ath_rc_priv, - struct ieee80211_tx_rate *rate) -{ - const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; - int rix, i, idx = 0; - - if (!(rate->flags & IEEE80211_TX_RC_MCS)) - return rate->idx; - - for (i = 0; i < ath_rc_priv->max_valid_rate; i++) { - idx = ath_rc_priv->valid_rate_index[i]; - - if (WLAN_RC_PHY_HT(rate_table->info[idx].phy) && - rate_table->info[idx].ratecode == rate->idx) - break; - } - - rix = idx; - - if (rate->flags & IEEE80211_TX_RC_SHORT_GI) - rix++; - - return rix; -} - -static void ath_rc_sort_validrates(struct ath_rate_priv *ath_rc_priv) -{ - const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; - u8 i, j, idx, idx_next; - - for (i = ath_rc_priv->max_valid_rate - 1; i > 0; i--) { - for (j = 0; j <= i-1; j++) { - idx = ath_rc_priv->valid_rate_index[j]; - idx_next = ath_rc_priv->valid_rate_index[j+1]; - - if (rate_table->info[idx].ratekbps > - rate_table->info[idx_next].ratekbps) { - ath_rc_priv->valid_rate_index[j] = idx_next; - ath_rc_priv->valid_rate_index[j+1] = idx; - } - } - } -} - -static inline -int ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table, - struct ath_rate_priv *ath_rc_priv, - u8 cur_valid_txrate, - u8 *next_idx) -{ - u8 i; - - for (i = 0; i < ath_rc_priv->max_valid_rate - 1; i++) { - if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) { - *next_idx = ath_rc_priv->valid_rate_index[i+1]; - return 1; - } - } - - /* No more valid rates */ - *next_idx = 0; - - return 0; -} - -/* Return true only for single stream */ - -static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw) -{ - if (WLAN_RC_PHY_HT(phy) && !(capflag & WLAN_RC_HT_FLAG)) - return 0; - if (WLAN_RC_PHY_DS(phy) && !(capflag & WLAN_RC_DS_FLAG)) - return 0; - if (WLAN_RC_PHY_TS(phy) && !(capflag & WLAN_RC_TS_FLAG)) - return 0; - if (WLAN_RC_PHY_SGI(phy) && !(capflag & WLAN_RC_SGI_FLAG)) - return 0; - if (!ignore_cw && WLAN_RC_PHY_HT(phy)) - if (WLAN_RC_PHY_40(phy) && !(capflag & WLAN_RC_40_FLAG)) - return 0; - return 1; -} - -static inline int -ath_rc_get_lower_rix(struct ath_rate_priv *ath_rc_priv, - u8 cur_valid_txrate, u8 *next_idx) -{ - int8_t i; - - for (i = 1; i < ath_rc_priv->max_valid_rate ; i++) { - if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) { - *next_idx = ath_rc_priv->valid_rate_index[i-1]; - return 1; - } - } - - return 0; -} - -static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv) -{ - const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; - u8 i, hi = 0; - - for (i = 0; i < rate_table->rate_cnt; i++) { - if (rate_table->info[i].rate_flags & RC_LEGACY) { - u32 phy = rate_table->info[i].phy; - u8 valid_rate_count = 0; - - if (!ath_rc_valid_phyrate(phy, ath_rc_priv->ht_cap, 0)) - continue; - - valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy]; - - ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i; - ath_rc_priv->valid_phy_ratecnt[phy] += 1; - ath_rc_priv->valid_rate_index[i] = true; - hi = i; - } - } - - return hi; -} - -static inline bool ath_rc_check_legacy(u8 rate, u8 dot11rate, u16 rate_flags, - u32 phy, u32 capflag) -{ - if (rate != dot11rate || WLAN_RC_PHY_HT(phy)) - return false; - - if ((rate_flags & WLAN_RC_CAP_MODE(capflag)) != WLAN_RC_CAP_MODE(capflag)) - return false; - - if (!(rate_flags & WLAN_RC_CAP_STREAM(capflag))) - return false; - - return true; -} - -static inline bool ath_rc_check_ht(u8 rate, u8 dot11rate, u16 rate_flags, - u32 phy, u32 capflag) -{ - if (rate != dot11rate || !WLAN_RC_PHY_HT(phy)) - return false; - - if (!WLAN_RC_PHY_HT_VALID(rate_flags, capflag)) - return false; - - if (!(rate_flags & WLAN_RC_CAP_STREAM(capflag))) - return false; - - return true; -} - -static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, bool legacy) -{ - const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; - struct ath_rateset *rateset; - u32 phy, capflag = ath_rc_priv->ht_cap; - u16 rate_flags; - u8 i, j, hi = 0, rate, dot11rate, valid_rate_count; - - if (legacy) - rateset = &ath_rc_priv->neg_rates; - else - rateset = &ath_rc_priv->neg_ht_rates; - - for (i = 0; i < rateset->rs_nrates; i++) { - for (j = 0; j < rate_table->rate_cnt; j++) { - phy = rate_table->info[j].phy; - rate_flags = rate_table->info[j].rate_flags; - rate = rateset->rs_rates[i]; - dot11rate = rate_table->info[j].dot11rate; - - if (legacy && - !ath_rc_check_legacy(rate, dot11rate, - rate_flags, phy, capflag)) - continue; - - if (!legacy && - !ath_rc_check_ht(rate, dot11rate, - rate_flags, phy, capflag)) - continue; - - if (!ath_rc_valid_phyrate(phy, capflag, 0)) - continue; - - valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy]; - ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = j; - ath_rc_priv->valid_phy_ratecnt[phy] += 1; - ath_rc_priv->valid_rate_index[j] = true; - hi = max(hi, j); - } - } - - return hi; -} - -static u8 ath_rc_get_highest_rix(struct ath_rate_priv *ath_rc_priv, - int *is_probing) -{ - const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; - u32 best_thruput, this_thruput, now_msec; - u8 rate, next_rate, best_rate, maxindex, minindex; - int8_t index = 0; - - now_msec = jiffies_to_msecs(jiffies); - *is_probing = 0; - best_thruput = 0; - maxindex = ath_rc_priv->max_valid_rate-1; - minindex = 0; - best_rate = minindex; - - /* - * Try the higher rate first. It will reduce memory moving time - * if we have very good channel characteristics. - */ - for (index = maxindex; index >= minindex ; index--) { - u8 per_thres; - - rate = ath_rc_priv->valid_rate_index[index]; - if (rate > ath_rc_priv->rate_max_phy) - continue; - - /* - * For TCP the average collision rate is around 11%, - * so we ignore PERs less than this. This is to - * prevent the rate we are currently using (whose - * PER might be in the 10-15 range because of TCP - * collisions) looking worse than the next lower - * rate whose PER has decayed close to 0. If we - * used to next lower rate, its PER would grow to - * 10-15 and we would be worse off then staying - * at the current rate. - */ - per_thres = ath_rc_priv->per[rate]; - if (per_thres < 12) - per_thres = 12; - - this_thruput = rate_table->info[rate].user_ratekbps * - (100 - per_thres); - - if (best_thruput <= this_thruput) { - best_thruput = this_thruput; - best_rate = rate; - } - } - - rate = best_rate; - - /* - * Must check the actual rate (ratekbps) to account for - * non-monoticity of 11g's rate table - */ - - if (rate >= ath_rc_priv->rate_max_phy) { - rate = ath_rc_priv->rate_max_phy; - - /* Probe the next allowed phy state */ - if (ath_rc_get_nextvalid_txrate(rate_table, - ath_rc_priv, rate, &next_rate) && - (now_msec - ath_rc_priv->probe_time > - rate_table->probe_interval) && - (ath_rc_priv->hw_maxretry_pktcnt >= 1)) { - rate = next_rate; - ath_rc_priv->probe_rate = rate; - ath_rc_priv->probe_time = now_msec; - ath_rc_priv->hw_maxretry_pktcnt = 0; - *is_probing = 1; - } - } - - if (rate > (ath_rc_priv->rate_table_size - 1)) - rate = ath_rc_priv->rate_table_size - 1; - - if (RC_TS_ONLY(rate_table->info[rate].rate_flags) && - (ath_rc_priv->ht_cap & WLAN_RC_TS_FLAG)) - return rate; - - if (RC_DS_OR_LATER(rate_table->info[rate].rate_flags) && - (ath_rc_priv->ht_cap & (WLAN_RC_DS_FLAG | WLAN_RC_TS_FLAG))) - return rate; - - if (RC_SS_OR_LEGACY(rate_table->info[rate].rate_flags)) - return rate; - - /* This should not happen */ - WARN_ON_ONCE(1); - - rate = ath_rc_priv->valid_rate_index[0]; - - return rate; -} - -static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table, - struct ieee80211_tx_rate *rate, - struct ieee80211_tx_rate_control *txrc, - u8 tries, u8 rix, int rtsctsenable) -{ - rate->count = tries; - rate->idx = rate_table->info[rix].ratecode; - - if (txrc->rts || rtsctsenable) - rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; - - if (WLAN_RC_PHY_HT(rate_table->info[rix].phy)) { - rate->flags |= IEEE80211_TX_RC_MCS; - if (WLAN_RC_PHY_40(rate_table->info[rix].phy) && - conf_is_ht40(&txrc->hw->conf)) - rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; - if (WLAN_RC_PHY_SGI(rate_table->info[rix].phy)) - rate->flags |= IEEE80211_TX_RC_SHORT_GI; - } -} - -static void ath_rc_rate_set_rtscts(struct ath_softc *sc, - const struct ath_rate_table *rate_table, - struct ieee80211_tx_info *tx_info) -{ - struct ieee80211_bss_conf *bss_conf; - - if (!tx_info->control.vif) - return; - /* - * For legacy frames, mac80211 takes care of CTS protection. - */ - if (!(tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS)) - return; - - bss_conf = &tx_info->control.vif->bss_conf; - - if (!bss_conf->basic_rates) - return; - - /* - * For now, use the lowest allowed basic rate for HT frames. - */ - tx_info->control.rts_cts_rate_idx = __ffs(bss_conf->basic_rates); -} - -static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, - struct ieee80211_tx_rate_control *txrc) -{ - struct ath_softc *sc = priv; - struct ath_rate_priv *ath_rc_priv = priv_sta; - const struct ath_rate_table *rate_table; - struct sk_buff *skb = txrc->skb; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_rate *rates = tx_info->control.rates; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - __le16 fc = hdr->frame_control; - u8 try_per_rate, i = 0, rix; - int is_probe = 0; - - if (rate_control_send_low(sta, priv_sta, txrc)) - return; - - /* - * For Multi Rate Retry we use a different number of - * retry attempt counts. This ends up looking like this: - * - * MRR[0] = 4 - * MRR[1] = 4 - * MRR[2] = 4 - * MRR[3] = 8 - * - */ - try_per_rate = 4; - - rate_table = ath_rc_priv->rate_table; - rix = ath_rc_get_highest_rix(ath_rc_priv, &is_probe); - - if (conf_is_ht(&sc->hw->conf) && - (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING)) - tx_info->flags |= IEEE80211_TX_CTL_LDPC; - - if (conf_is_ht(&sc->hw->conf) && - (sta->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)) - tx_info->flags |= (1 << IEEE80211_TX_CTL_STBC_SHIFT); - - if (is_probe) { - /* - * Set one try for probe rates. For the - * probes don't enable RTS. - */ - ath_rc_rate_set_series(rate_table, &rates[i++], txrc, - 1, rix, 0); - /* - * Get the next tried/allowed rate. - * No RTS for the next series after the probe rate. - */ - ath_rc_get_lower_rix(ath_rc_priv, rix, &rix); - ath_rc_rate_set_series(rate_table, &rates[i++], txrc, - try_per_rate, rix, 0); - - tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; - } else { - /* - * Set the chosen rate. No RTS for first series entry. - */ - ath_rc_rate_set_series(rate_table, &rates[i++], txrc, - try_per_rate, rix, 0); - } - - for ( ; i < 4; i++) { - /* - * Use twice the number of tries for the last MRR segment. - */ - if (i + 1 == 4) - try_per_rate = 8; - - ath_rc_get_lower_rix(ath_rc_priv, rix, &rix); - - /* - * All other rates in the series have RTS enabled. - */ - ath_rc_rate_set_series(rate_table, &rates[i], txrc, - try_per_rate, rix, 1); - } - - /* - * NB:Change rate series to enable aggregation when operating - * at lower MCS rates. When first rate in series is MCS2 - * in HT40 @ 2.4GHz, series should look like: - * - * {MCS2, MCS1, MCS0, MCS0}. - * - * When first rate in series is MCS3 in HT20 @ 2.4GHz, series should - * look like: - * - * {MCS3, MCS2, MCS1, MCS1} - * - * So, set fourth rate in series to be same as third one for - * above conditions. - */ - if ((sc->hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ) && - (conf_is_ht(&sc->hw->conf))) { - u8 dot11rate = rate_table->info[rix].dot11rate; - u8 phy = rate_table->info[rix].phy; - if (i == 4 && - ((dot11rate == 2 && phy == WLAN_RC_PHY_HT_40_SS) || - (dot11rate == 3 && phy == WLAN_RC_PHY_HT_20_SS))) { - rates[3].idx = rates[2].idx; - rates[3].flags = rates[2].flags; - } - } - - /* - * Force hardware to use computed duration for next - * fragment by disabling multi-rate retry, which - * updates duration based on the multi-rate duration table. - * - * FIXME: Fix duration - */ - if (ieee80211_has_morefrags(fc) || - (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) { - rates[1].count = rates[2].count = rates[3].count = 0; - rates[1].idx = rates[2].idx = rates[3].idx = 0; - rates[0].count = ATH_TXMAXTRY; - } - - ath_rc_rate_set_rtscts(sc, rate_table, tx_info); -} - -static void ath_rc_update_per(struct ath_softc *sc, - const struct ath_rate_table *rate_table, - struct ath_rate_priv *ath_rc_priv, - struct ieee80211_tx_info *tx_info, - int tx_rate, int xretries, int retries, - u32 now_msec) -{ - int count, n_bad_frames; - u8 last_per; - static const u32 nretry_to_per_lookup[10] = { - 100 * 0 / 1, - 100 * 1 / 4, - 100 * 1 / 2, - 100 * 3 / 4, - 100 * 4 / 5, - 100 * 5 / 6, - 100 * 6 / 7, - 100 * 7 / 8, - 100 * 8 / 9, - 100 * 9 / 10 - }; - - last_per = ath_rc_priv->per[tx_rate]; - n_bad_frames = tx_info->status.ampdu_len - tx_info->status.ampdu_ack_len; - - if (xretries) { - if (xretries == 1) { - ath_rc_priv->per[tx_rate] += 30; - if (ath_rc_priv->per[tx_rate] > 100) - ath_rc_priv->per[tx_rate] = 100; - } else { - /* xretries == 2 */ - count = ARRAY_SIZE(nretry_to_per_lookup); - if (retries >= count) - retries = count - 1; - - /* new_PER = 7/8*old_PER + 1/8*(currentPER) */ - ath_rc_priv->per[tx_rate] = - (u8)(last_per - (last_per >> 3) + (100 >> 3)); - } - - /* xretries == 1 or 2 */ - - if (ath_rc_priv->probe_rate == tx_rate) - ath_rc_priv->probe_rate = 0; - - } else { /* xretries == 0 */ - count = ARRAY_SIZE(nretry_to_per_lookup); - if (retries >= count) - retries = count - 1; - - if (n_bad_frames) { - /* new_PER = 7/8*old_PER + 1/8*(currentPER) - * Assuming that n_frames is not 0. The current PER - * from the retries is 100 * retries / (retries+1), - * since the first retries attempts failed, and the - * next one worked. For the one that worked, - * n_bad_frames subframes out of n_frames wored, - * so the PER for that part is - * 100 * n_bad_frames / n_frames, and it contributes - * 100 * n_bad_frames / (n_frames * (retries+1)) to - * the above PER. The expression below is a - * simplified version of the sum of these two terms. - */ - if (tx_info->status.ampdu_len > 0) { - int n_frames, n_bad_tries; - u8 cur_per, new_per; - - n_bad_tries = retries * tx_info->status.ampdu_len + - n_bad_frames; - n_frames = tx_info->status.ampdu_len * (retries + 1); - cur_per = (100 * n_bad_tries / n_frames) >> 3; - new_per = (u8)(last_per - (last_per >> 3) + cur_per); - ath_rc_priv->per[tx_rate] = new_per; - } - } else { - ath_rc_priv->per[tx_rate] = - (u8)(last_per - (last_per >> 3) + - (nretry_to_per_lookup[retries] >> 3)); - } - - - /* - * If we got at most one retry then increase the max rate if - * this was a probe. Otherwise, ignore the probe. - */ - if (ath_rc_priv->probe_rate && ath_rc_priv->probe_rate == tx_rate) { - if (retries > 0 || 2 * n_bad_frames > tx_info->status.ampdu_len) { - /* - * Since we probed with just a single attempt, - * any retries means the probe failed. Also, - * if the attempt worked, but more than half - * the subframes were bad then also consider - * the probe a failure. - */ - ath_rc_priv->probe_rate = 0; - } else { - u8 probe_rate = 0; - - ath_rc_priv->rate_max_phy = - ath_rc_priv->probe_rate; - probe_rate = ath_rc_priv->probe_rate; - - if (ath_rc_priv->per[probe_rate] > 30) - ath_rc_priv->per[probe_rate] = 20; - - ath_rc_priv->probe_rate = 0; - - /* - * Since this probe succeeded, we allow the next - * probe twice as soon. This allows the maxRate - * to move up faster if the probes are - * successful. - */ - ath_rc_priv->probe_time = - now_msec - rate_table->probe_interval / 2; - } - } - - if (retries > 0) { - /* - * Don't update anything. We don't know if - * this was because of collisions or poor signal. - */ - ath_rc_priv->hw_maxretry_pktcnt = 0; - } else { - /* - * It worked with no retries. First ignore bogus (small) - * rssi_ack values. - */ - if (tx_rate == ath_rc_priv->rate_max_phy && - ath_rc_priv->hw_maxretry_pktcnt < 255) { - ath_rc_priv->hw_maxretry_pktcnt++; - } - - } - } -} - -static void ath_rc_update_ht(struct ath_softc *sc, - struct ath_rate_priv *ath_rc_priv, - struct ieee80211_tx_info *tx_info, - int tx_rate, int xretries, int retries) -{ - u32 now_msec = jiffies_to_msecs(jiffies); - int rate; - u8 last_per; - const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; - int size = ath_rc_priv->rate_table_size; - - if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt)) - return; - - last_per = ath_rc_priv->per[tx_rate]; - - /* Update PER first */ - ath_rc_update_per(sc, rate_table, ath_rc_priv, - tx_info, tx_rate, xretries, - retries, now_msec); - - /* - * If this rate looks bad (high PER) then stop using it for - * a while (except if we are probing). - */ - if (ath_rc_priv->per[tx_rate] >= 55 && tx_rate > 0 && - rate_table->info[tx_rate].ratekbps <= - rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) { - ath_rc_get_lower_rix(ath_rc_priv, (u8)tx_rate, - &ath_rc_priv->rate_max_phy); - - /* Don't probe for a little while. */ - ath_rc_priv->probe_time = now_msec; - } - - /* Make sure the rates below this have lower PER */ - /* Monotonicity is kept only for rates below the current rate. */ - if (ath_rc_priv->per[tx_rate] < last_per) { - for (rate = tx_rate - 1; rate >= 0; rate--) { - - if (ath_rc_priv->per[rate] > - ath_rc_priv->per[rate+1]) { - ath_rc_priv->per[rate] = - ath_rc_priv->per[rate+1]; - } - } - } - - /* Maintain monotonicity for rates above the current rate */ - for (rate = tx_rate; rate < size - 1; rate++) { - if (ath_rc_priv->per[rate+1] < - ath_rc_priv->per[rate]) - ath_rc_priv->per[rate+1] = - ath_rc_priv->per[rate]; - } - - /* Every so often, we reduce the thresholds - * and PER (different for CCK and OFDM). */ - if (now_msec - ath_rc_priv->per_down_time >= - rate_table->probe_interval) { - for (rate = 0; rate < size; rate++) { - ath_rc_priv->per[rate] = - 7 * ath_rc_priv->per[rate] / 8; - } - - ath_rc_priv->per_down_time = now_msec; - } - - ath_debug_stat_retries(ath_rc_priv, tx_rate, xretries, retries, - ath_rc_priv->per[tx_rate]); - -} - -static void ath_rc_tx_status(struct ath_softc *sc, - struct ath_rate_priv *ath_rc_priv, - struct sk_buff *skb) -{ - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_rate *rates = tx_info->status.rates; - struct ieee80211_tx_rate *rate; - int final_ts_idx = 0, xretries = 0, long_retry = 0; - u8 flags; - u32 i = 0, rix; - - for (i = 0; i < sc->hw->max_rates; i++) { - rate = &tx_info->status.rates[i]; - if (rate->idx < 0 || !rate->count) - break; - - final_ts_idx = i; - long_retry = rate->count - 1; - } - - if (!(tx_info->flags & IEEE80211_TX_STAT_ACK)) - xretries = 1; - - /* - * If the first rate is not the final index, there - * are intermediate rate failures to be processed. - */ - if (final_ts_idx != 0) { - for (i = 0; i < final_ts_idx ; i++) { - if (rates[i].count != 0 && (rates[i].idx >= 0)) { - flags = rates[i].flags; - - /* If HT40 and we have switched mode from - * 40 to 20 => don't update */ - - if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && - !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG)) - return; - - rix = ath_rc_get_rateindex(ath_rc_priv, &rates[i]); - ath_rc_update_ht(sc, ath_rc_priv, tx_info, - rix, xretries ? 1 : 2, - rates[i].count); - } - } - } - - flags = rates[final_ts_idx].flags; - - /* If HT40 and we have switched mode from 40 to 20 => don't update */ - if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && - !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG)) - return; - - rix = ath_rc_get_rateindex(ath_rc_priv, &rates[final_ts_idx]); - ath_rc_update_ht(sc, ath_rc_priv, tx_info, rix, xretries, long_retry); - ath_debug_stat_rc(ath_rc_priv, rix); -} - -static const -struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, - enum ieee80211_band band, - bool is_ht) -{ - switch(band) { - case IEEE80211_BAND_2GHZ: - if (is_ht) - return &ar5416_11ng_ratetable; - return &ar5416_11g_ratetable; - case IEEE80211_BAND_5GHZ: - if (is_ht) - return &ar5416_11na_ratetable; - return &ar5416_11a_ratetable; - default: - return NULL; - } -} - -static void ath_rc_init(struct ath_softc *sc, - struct ath_rate_priv *ath_rc_priv) -{ - const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; - struct ath_rateset *rateset = &ath_rc_priv->neg_rates; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - u8 i, j, k, hi = 0, hthi = 0; - - ath_rc_priv->rate_table_size = RATE_TABLE_SIZE; - - for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) { - ath_rc_priv->per[i] = 0; - ath_rc_priv->valid_rate_index[i] = 0; - } - - for (i = 0; i < WLAN_RC_PHY_MAX; i++) { - for (j = 0; j < RATE_TABLE_SIZE; j++) - ath_rc_priv->valid_phy_rateidx[i][j] = 0; - ath_rc_priv->valid_phy_ratecnt[i] = 0; - } - - if (!rateset->rs_nrates) { - hi = ath_rc_init_validrates(ath_rc_priv); - } else { - hi = ath_rc_setvalid_rates(ath_rc_priv, true); - - if (ath_rc_priv->ht_cap & WLAN_RC_HT_FLAG) - hthi = ath_rc_setvalid_rates(ath_rc_priv, false); - - hi = max(hi, hthi); - } - - ath_rc_priv->rate_table_size = hi + 1; - ath_rc_priv->rate_max_phy = 0; - WARN_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE); - - for (i = 0, k = 0; i < WLAN_RC_PHY_MAX; i++) { - for (j = 0; j < ath_rc_priv->valid_phy_ratecnt[i]; j++) { - ath_rc_priv->valid_rate_index[k++] = - ath_rc_priv->valid_phy_rateidx[i][j]; - } - - if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, 1) || - !ath_rc_priv->valid_phy_ratecnt[i]) - continue; - - ath_rc_priv->rate_max_phy = ath_rc_priv->valid_phy_rateidx[i][j-1]; - } - WARN_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE); - WARN_ON(k > RATE_TABLE_SIZE); - - ath_rc_priv->max_valid_rate = k; - ath_rc_sort_validrates(ath_rc_priv); - ath_rc_priv->rate_max_phy = (k > 4) ? - ath_rc_priv->valid_rate_index[k-4] : - ath_rc_priv->valid_rate_index[k-1]; - - ath_dbg(common, CONFIG, "RC Initialized with capabilities: 0x%x\n", - ath_rc_priv->ht_cap); -} - -static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta) -{ - u8 caps = 0; - - if (sta->ht_cap.ht_supported) { - caps = WLAN_RC_HT_FLAG; - if (sta->ht_cap.mcs.rx_mask[1] && sta->ht_cap.mcs.rx_mask[2]) - caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG; - else if (sta->ht_cap.mcs.rx_mask[1]) - caps |= WLAN_RC_DS_FLAG; - if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) { - caps |= WLAN_RC_40_FLAG; - if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) - caps |= WLAN_RC_SGI_FLAG; - } else { - if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) - caps |= WLAN_RC_SGI_FLAG; - } - } - - return caps; -} - -static bool ath_tx_aggr_check(struct ath_softc *sc, struct ieee80211_sta *sta, - u8 tidno) -{ - struct ath_node *an = (struct ath_node *)sta->drv_priv; - struct ath_atx_tid *txtid; - - if (!sta->ht_cap.ht_supported) - return false; - - txtid = ATH_AN_2_TID(an, tidno); - return !txtid->active; -} - - -/***********************************/ -/* mac80211 Rate Control callbacks */ -/***********************************/ - -static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb) -{ - struct ath_softc *sc = priv; - struct ath_rate_priv *ath_rc_priv = priv_sta; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - __le16 fc = hdr->frame_control; - - if (!priv_sta || !ieee80211_is_data(fc)) - return; - - /* This packet was aggregated but doesn't carry status info */ - if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && - !(tx_info->flags & IEEE80211_TX_STAT_AMPDU)) - return; - - if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) - return; - - ath_rc_tx_status(sc, ath_rc_priv, skb); - - /* Check if aggregation has to be enabled for this tid */ - if (conf_is_ht(&sc->hw->conf) && - !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { - if (ieee80211_is_data_qos(fc) && - skb_get_queue_mapping(skb) != IEEE80211_AC_VO) { - u8 *qc, tid; - - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; - - if(ath_tx_aggr_check(sc, sta, tid)) - ieee80211_start_tx_ba_session(sta, tid, 0); - } - } -} - -static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, - struct cfg80211_chan_def *chandef, - struct ieee80211_sta *sta, void *priv_sta) -{ - struct ath_softc *sc = priv; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_rate_priv *ath_rc_priv = priv_sta; - int i, j = 0; - u32 rate_flags = ieee80211_chandef_rate_flags(&sc->hw->conf.chandef); - - for (i = 0; i < sband->n_bitrates; i++) { - if (sta->supp_rates[sband->band] & BIT(i)) { - if ((rate_flags & sband->bitrates[i].flags) - != rate_flags) - continue; - - ath_rc_priv->neg_rates.rs_rates[j] - = (sband->bitrates[i].bitrate * 2) / 10; - j++; - } - } - ath_rc_priv->neg_rates.rs_nrates = j; - - if (sta->ht_cap.ht_supported) { - for (i = 0, j = 0; i < 77; i++) { - if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) - ath_rc_priv->neg_ht_rates.rs_rates[j++] = i; - if (j == ATH_RATE_MAX) - break; - } - ath_rc_priv->neg_ht_rates.rs_nrates = j; - } - - ath_rc_priv->rate_table = ath_choose_rate_table(sc, sband->band, - sta->ht_cap.ht_supported); - if (!ath_rc_priv->rate_table) { - ath_err(common, "No rate table chosen\n"); - return; - } - - ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta); - ath_rc_init(sc, priv_sta); -} - -static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, - struct cfg80211_chan_def *chandef, - struct ieee80211_sta *sta, void *priv_sta, - u32 changed) -{ - struct ath_softc *sc = priv; - struct ath_rate_priv *ath_rc_priv = priv_sta; - - if (changed & IEEE80211_RC_BW_CHANGED) { - ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta); - ath_rc_init(sc, priv_sta); - - ath_dbg(ath9k_hw_common(sc->sc_ah), CONFIG, - "Operating Bandwidth changed to: %d\n", - sc->hw->conf.chandef.width); - } -} - -#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) - -void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate) -{ - struct ath_rc_stats *stats; - - stats = &rc->rcstats[final_rate]; - stats->success++; -} - -void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, - int xretries, int retries, u8 per) -{ - struct ath_rc_stats *stats = &rc->rcstats[rix]; - - stats->xretries += xretries; - stats->retries += retries; - stats->per = per; -} - -static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_rate_priv *rc = file->private_data; - char *buf; - unsigned int len = 0, max; - int rix; - ssize_t retval; - - if (rc->rate_table == NULL) - return 0; - - max = 80 + rc->rate_table_size * 1024 + 1; - buf = kmalloc(max, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - len += sprintf(buf, "%6s %6s %6s " - "%10s %10s %10s %10s\n", - "HT", "MCS", "Rate", - "Success", "Retries", "XRetries", "PER"); - - for (rix = 0; rix < rc->max_valid_rate; rix++) { - u8 i = rc->valid_rate_index[rix]; - u32 ratekbps = rc->rate_table->info[i].ratekbps; - struct ath_rc_stats *stats = &rc->rcstats[i]; - char mcs[5]; - char htmode[5]; - int used_mcs = 0, used_htmode = 0; - - if (WLAN_RC_PHY_HT(rc->rate_table->info[i].phy)) { - used_mcs = scnprintf(mcs, 5, "%d", - rc->rate_table->info[i].ratecode); - - if (WLAN_RC_PHY_40(rc->rate_table->info[i].phy)) - used_htmode = scnprintf(htmode, 5, "HT40"); - else if (WLAN_RC_PHY_20(rc->rate_table->info[i].phy)) - used_htmode = scnprintf(htmode, 5, "HT20"); - else - used_htmode = scnprintf(htmode, 5, "????"); - } - - mcs[used_mcs] = '\0'; - htmode[used_htmode] = '\0'; - - len += scnprintf(buf + len, max - len, - "%6s %6s %3u.%d: " - "%10u %10u %10u %10u\n", - htmode, - mcs, - ratekbps / 1000, - (ratekbps % 1000) / 100, - stats->success, - stats->retries, - stats->xretries, - stats->per); - } - - if (len > max) - len = max; - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - return retval; -} - -static const struct file_operations fops_rcstat = { - .read = read_file_rcstat, - .open = simple_open, - .owner = THIS_MODULE -}; - -static void ath_rate_add_sta_debugfs(void *priv, void *priv_sta, - struct dentry *dir) -{ - struct ath_rate_priv *rc = priv_sta; - rc->debugfs_rcstats = debugfs_create_file("rc_stats", S_IRUGO, - dir, rc, &fops_rcstat); -} - -static void ath_rate_remove_sta_debugfs(void *priv, void *priv_sta) -{ - struct ath_rate_priv *rc = priv_sta; - debugfs_remove(rc->debugfs_rcstats); -} - -#endif /* CONFIG_MAC80211_DEBUGFS && CONFIG_ATH9K_DEBUGFS */ - -static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) -{ - return hw->priv; -} - -static void ath_rate_free(void *priv) -{ - return; -} - -static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) -{ - return kzalloc(sizeof(struct ath_rate_priv), gfp); -} - -static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta, - void *priv_sta) -{ - struct ath_rate_priv *rate_priv = priv_sta; - kfree(rate_priv); -} - -static struct rate_control_ops ath_rate_ops = { - .module = NULL, - .name = "ath9k_rate_control", - .tx_status = ath_tx_status, - .get_rate = ath_get_rate, - .rate_init = ath_rate_init, - .rate_update = ath_rate_update, - .alloc = ath_rate_alloc, - .free = ath_rate_free, - .alloc_sta = ath_rate_alloc_sta, - .free_sta = ath_rate_free_sta, - -#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) - .add_sta_debugfs = ath_rate_add_sta_debugfs, - .remove_sta_debugfs = ath_rate_remove_sta_debugfs, -#endif -}; - -int ath_rate_control_register(void) -{ - return ieee80211_rate_control_register(&ath_rate_ops); -} - -void ath_rate_control_unregister(void) -{ - ieee80211_rate_control_unregister(&ath_rate_ops); -} diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h deleted file mode 100644 index b9a87383cb43..000000000000 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (c) 2004 Sam Leffler, Errno Consulting - * Copyright (c) 2004 Video54 Technologies, Inc. - * Copyright (c) 2008-2011 Atheros Communications 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 RC_H -#define RC_H - -#include "hw.h" - -struct ath_softc; - -#define ATH_RATE_MAX 30 -#define RATE_TABLE_SIZE 72 - -#define RC_INVALID 0x0000 -#define RC_LEGACY 0x0001 -#define RC_SS 0x0002 -#define RC_DS 0x0004 -#define RC_TS 0x0008 -#define RC_HT_20 0x0010 -#define RC_HT_40 0x0020 - -#define RC_STREAM_MASK 0xe -#define RC_DS_OR_LATER(f) ((((f) & RC_STREAM_MASK) == RC_DS) || \ - (((f) & RC_STREAM_MASK) == (RC_DS | RC_TS))) -#define RC_TS_ONLY(f) (((f) & RC_STREAM_MASK) == RC_TS) -#define RC_SS_OR_LEGACY(f) ((f) & (RC_SS | RC_LEGACY)) - -#define RC_HT_2040 (RC_HT_20 | RC_HT_40) -#define RC_ALL_STREAM (RC_SS | RC_DS | RC_TS) -#define RC_L_SD (RC_LEGACY | RC_SS | RC_DS) -#define RC_L_SDT (RC_LEGACY | RC_SS | RC_DS | RC_TS) -#define RC_HT_S_20 (RC_HT_20 | RC_SS) -#define RC_HT_D_20 (RC_HT_20 | RC_DS) -#define RC_HT_T_20 (RC_HT_20 | RC_TS) -#define RC_HT_S_40 (RC_HT_40 | RC_SS) -#define RC_HT_D_40 (RC_HT_40 | RC_DS) -#define RC_HT_T_40 (RC_HT_40 | RC_TS) - -#define RC_HT_SD_20 (RC_HT_20 | RC_SS | RC_DS) -#define RC_HT_DT_20 (RC_HT_20 | RC_DS | RC_TS) -#define RC_HT_SD_40 (RC_HT_40 | RC_SS | RC_DS) -#define RC_HT_DT_40 (RC_HT_40 | RC_DS | RC_TS) - -#define RC_HT_SD_2040 (RC_HT_2040 | RC_SS | RC_DS) -#define RC_HT_SDT_2040 (RC_HT_2040 | RC_SS | RC_DS | RC_TS) - -#define RC_HT_SDT_20 (RC_HT_20 | RC_SS | RC_DS | RC_TS) -#define RC_HT_SDT_40 (RC_HT_40 | RC_SS | RC_DS | RC_TS) - -#define RC_ALL (RC_LEGACY | RC_HT_2040 | RC_ALL_STREAM) - -enum { - WLAN_RC_PHY_OFDM, - WLAN_RC_PHY_CCK, - WLAN_RC_PHY_HT_20_SS, - WLAN_RC_PHY_HT_20_DS, - WLAN_RC_PHY_HT_20_TS, - WLAN_RC_PHY_HT_40_SS, - WLAN_RC_PHY_HT_40_DS, - WLAN_RC_PHY_HT_40_TS, - WLAN_RC_PHY_HT_20_SS_HGI, - WLAN_RC_PHY_HT_20_DS_HGI, - WLAN_RC_PHY_HT_20_TS_HGI, - WLAN_RC_PHY_HT_40_SS_HGI, - WLAN_RC_PHY_HT_40_DS_HGI, - WLAN_RC_PHY_HT_40_TS_HGI, - WLAN_RC_PHY_MAX -}; - -#define WLAN_RC_PHY_DS(_phy) ((_phy == WLAN_RC_PHY_HT_20_DS) \ - || (_phy == WLAN_RC_PHY_HT_40_DS) \ - || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) -#define WLAN_RC_PHY_TS(_phy) ((_phy == WLAN_RC_PHY_HT_20_TS) \ - || (_phy == WLAN_RC_PHY_HT_40_TS) \ - || (_phy == WLAN_RC_PHY_HT_20_TS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_TS_HGI)) -#define WLAN_RC_PHY_20(_phy) ((_phy == WLAN_RC_PHY_HT_20_SS) \ - || (_phy == WLAN_RC_PHY_HT_20_DS) \ - || (_phy == WLAN_RC_PHY_HT_20_TS) \ - || (_phy == WLAN_RC_PHY_HT_20_SS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_20_TS_HGI)) -#define WLAN_RC_PHY_40(_phy) ((_phy == WLAN_RC_PHY_HT_40_SS) \ - || (_phy == WLAN_RC_PHY_HT_40_DS) \ - || (_phy == WLAN_RC_PHY_HT_40_TS) \ - || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_DS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_TS_HGI)) -#define WLAN_RC_PHY_SGI(_phy) ((_phy == WLAN_RC_PHY_HT_20_SS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_20_TS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_DS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_TS_HGI)) - -#define WLAN_RC_PHY_HT(_phy) (_phy >= WLAN_RC_PHY_HT_20_SS) - -#define WLAN_RC_CAP_MODE(capflag) (((capflag & WLAN_RC_HT_FLAG) ? \ - ((capflag & WLAN_RC_40_FLAG) ? RC_HT_40 : RC_HT_20) : RC_LEGACY)) - -#define WLAN_RC_CAP_STREAM(capflag) (((capflag & WLAN_RC_TS_FLAG) ? \ - (RC_TS) : ((capflag & WLAN_RC_DS_FLAG) ? RC_DS : RC_SS))) - -/* Return TRUE if flag supports HT20 && client supports HT20 or - * return TRUE if flag supports HT40 && client supports HT40. - * This is used becos some rates overlap between HT20/HT40. - */ -#define WLAN_RC_PHY_HT_VALID(flag, capflag) \ - (((flag & RC_HT_20) && !(capflag & WLAN_RC_40_FLAG)) || \ - ((flag & RC_HT_40) && (capflag & WLAN_RC_40_FLAG))) - -#define WLAN_RC_DS_FLAG (0x01) -#define WLAN_RC_TS_FLAG (0x02) -#define WLAN_RC_40_FLAG (0x04) -#define WLAN_RC_SGI_FLAG (0x08) -#define WLAN_RC_HT_FLAG (0x10) - -/** - * struct ath_rate_table - Rate Control table - * @rate_cnt: total number of rates for the given wireless mode - * @mcs_start: MCS rate index offset - * @rate_flags: Rate Control flags - * @phy: CCK/OFDM/HT20/HT40 - * @ratekbps: rate in Kbits per second - * @user_ratekbps: user rate in Kbits per second - * @ratecode: rate that goes into HW descriptors - * @dot11rate: value that goes into supported - * rates info element of MLME - * @ctrl_rate: Index of next lower basic rate, used for duration computation - * @cw40index: Index of rates having 40MHz channel width - * @sgi_index: Index of rates having Short Guard Interval - * @ht_index: high throughput rates having 40MHz channel width and - * Short Guard Interval - * @probe_interval: interval for rate control to probe for other rates - * @initial_ratemax: initial ratemax value - */ -struct ath_rate_table { - int rate_cnt; - int mcs_start; - struct { - u16 rate_flags; - u8 phy; - u32 ratekbps; - u32 user_ratekbps; - u8 ratecode; - u8 dot11rate; - } info[RATE_TABLE_SIZE]; - u32 probe_interval; - u8 initial_ratemax; -}; - -struct ath_rateset { - u8 rs_nrates; - u8 rs_rates[ATH_RATE_MAX]; -}; - -struct ath_rc_stats { - u32 success; - u32 retries; - u32 xretries; - u8 per; -}; - -/** - * struct ath_rate_priv - Rate Control priv data - * @state: RC state - * @probe_rate: rate we are probing at - * @probe_time: msec timestamp for last probe - * @hw_maxretry_pktcnt: num of packets since we got HW max retry error - * @max_valid_rate: maximum number of valid rate - * @per_down_time: msec timestamp for last PER down step - * @valid_phy_ratecnt: valid rate count - * @rate_max_phy: phy index for the max rate - * @per: PER for every valid rate in % - * @probe_interval: interval for ratectrl to probe for other rates - * @ht_cap: HT capabilities - * @neg_rates: Negotatied rates - * @neg_ht_rates: Negotiated HT rates - */ -struct ath_rate_priv { - u8 rate_table_size; - u8 probe_rate; - u8 hw_maxretry_pktcnt; - u8 max_valid_rate; - u8 valid_rate_index[RATE_TABLE_SIZE]; - u8 ht_cap; - u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; - u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE]; - u8 rate_max_phy; - u8 per[RATE_TABLE_SIZE]; - u32 probe_time; - u32 per_down_time; - u32 probe_interval; - struct ath_rateset neg_rates; - struct ath_rateset neg_ht_rates; - const struct ath_rate_table *rate_table; - -#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) - struct dentry *debugfs_rcstats; - struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; -#endif -}; - -#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) -void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate); -void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, - int xretries, int retries, u8 per); -#else -static inline void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate) -{ -} -static inline void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, - int xretries, int retries, u8 per) -{ -} -#endif - -#ifdef CONFIG_ATH9K_LEGACY_RATE_CONTROL -int ath_rate_control_register(void); -void ath_rate_control_unregister(void); -#else -static inline int ath_rate_control_register(void) -{ - return 0; -} - -static inline void ath_rate_control_unregister(void) -{ -} -#endif - -#endif /* RC_H */ diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 82e340d3ec60..6c9accdb52e4 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -762,204 +762,6 @@ static struct ath_rxbuf *ath_get_next_rx_buf(struct ath_softc *sc, return bf; } -/* Assumes you've already done the endian to CPU conversion */ -static bool ath9k_rx_accept(struct ath_common *common, - struct ieee80211_hdr *hdr, - struct ieee80211_rx_status *rxs, - struct ath_rx_status *rx_stats, - bool *decrypt_error) -{ - struct ath_softc *sc = (struct ath_softc *) common->priv; - bool is_mc, is_valid_tkip, strip_mic, mic_error; - struct ath_hw *ah = common->ah; - __le16 fc; - - fc = hdr->frame_control; - - is_mc = !!is_multicast_ether_addr(hdr->addr1); - is_valid_tkip = rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID && - test_bit(rx_stats->rs_keyix, common->tkip_keymap); - strip_mic = is_valid_tkip && ieee80211_is_data(fc) && - ieee80211_has_protected(fc) && - !(rx_stats->rs_status & - (ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC | - ATH9K_RXERR_KEYMISS)); - - /* - * Key miss events are only relevant for pairwise keys where the - * descriptor does contain a valid key index. This has been observed - * mostly with CCMP encryption. - */ - if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID || - !test_bit(rx_stats->rs_keyix, common->ccmp_keymap)) - rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS; - - mic_error = is_valid_tkip && !ieee80211_is_ctl(fc) && - !ieee80211_has_morefrags(fc) && - !(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) && - (rx_stats->rs_status & ATH9K_RXERR_MIC); - - /* - * The rx_stats->rs_status will not be set until the end of the - * chained descriptors so it can be ignored if rs_more is set. The - * rs_more will be false at the last element of the chained - * descriptors. - */ - if (rx_stats->rs_status != 0) { - u8 status_mask; - - if (rx_stats->rs_status & ATH9K_RXERR_CRC) { - rxs->flag |= RX_FLAG_FAILED_FCS_CRC; - mic_error = false; - } - - if ((rx_stats->rs_status & ATH9K_RXERR_DECRYPT) || - (!is_mc && (rx_stats->rs_status & ATH9K_RXERR_KEYMISS))) { - *decrypt_error = true; - mic_error = false; - } - - /* - * Reject error frames with the exception of - * decryption and MIC failures. For monitor mode, - * we also ignore the CRC error. - */ - status_mask = ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | - ATH9K_RXERR_KEYMISS; - - if (ah->is_monitoring && (sc->rx.rxfilter & FIF_FCSFAIL)) - status_mask |= ATH9K_RXERR_CRC; - - if (rx_stats->rs_status & ~status_mask) - return false; - } - - /* - * For unicast frames the MIC error bit can have false positives, - * so all MIC error reports need to be validated in software. - * False negatives are not common, so skip software verification - * if the hardware considers the MIC valid. - */ - if (strip_mic) - rxs->flag |= RX_FLAG_MMIC_STRIPPED; - else if (is_mc && mic_error) - rxs->flag |= RX_FLAG_MMIC_ERROR; - - return true; -} - -static int ath9k_process_rate(struct ath_common *common, - struct ieee80211_hw *hw, - struct ath_rx_status *rx_stats, - struct ieee80211_rx_status *rxs) -{ - struct ieee80211_supported_band *sband; - enum ieee80211_band band; - unsigned int i = 0; - struct ath_softc __maybe_unused *sc = common->priv; - struct ath_hw *ah = sc->sc_ah; - - band = ah->curchan->chan->band; - sband = hw->wiphy->bands[band]; - - if (IS_CHAN_QUARTER_RATE(ah->curchan)) - rxs->flag |= RX_FLAG_5MHZ; - else if (IS_CHAN_HALF_RATE(ah->curchan)) - rxs->flag |= RX_FLAG_10MHZ; - - if (rx_stats->rs_rate & 0x80) { - /* HT rate */ - rxs->flag |= RX_FLAG_HT; - rxs->flag |= rx_stats->flag; - rxs->rate_idx = rx_stats->rs_rate & 0x7f; - return 0; - } - - for (i = 0; i < sband->n_bitrates; i++) { - if (sband->bitrates[i].hw_value == rx_stats->rs_rate) { - rxs->rate_idx = i; - return 0; - } - if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) { - rxs->flag |= RX_FLAG_SHORTPRE; - rxs->rate_idx = i; - return 0; - } - } - - /* - * No valid hardware bitrate found -- we should not get here - * because hardware has already validated this frame as OK. - */ - ath_dbg(common, ANY, - "unsupported hw bitrate detected 0x%02x using 1 Mbit\n", - rx_stats->rs_rate); - RX_STAT_INC(rx_rate_err); - return -EINVAL; -} - -static void ath9k_process_rssi(struct ath_common *common, - struct ieee80211_hw *hw, - struct ath_rx_status *rx_stats, - struct ieee80211_rx_status *rxs) -{ - struct ath_softc *sc = hw->priv; - struct ath_hw *ah = common->ah; - int last_rssi; - int rssi = rx_stats->rs_rssi; - int i, j; - - /* - * RSSI is not available for subframes in an A-MPDU. - */ - if (rx_stats->rs_moreaggr) { - rxs->flag |= RX_FLAG_NO_SIGNAL_VAL; - return; - } - - /* - * Check if the RSSI for the last subframe in an A-MPDU - * or an unaggregated frame is valid. - */ - if (rx_stats->rs_rssi == ATH9K_RSSI_BAD) { - rxs->flag |= RX_FLAG_NO_SIGNAL_VAL; - return; - } - - for (i = 0, j = 0; i < ARRAY_SIZE(rx_stats->rs_rssi_ctl); i++) { - s8 rssi; - - if (!(ah->rxchainmask & BIT(i))) - continue; - - rssi = rx_stats->rs_rssi_ctl[i]; - if (rssi != ATH9K_RSSI_BAD) { - rxs->chains |= BIT(j); - rxs->chain_signal[j] = ah->noise + rssi; - } - j++; - } - - /* - * Update Beacon RSSI, this is used by ANI. - */ - if (rx_stats->is_mybeacon && - ((ah->opmode == NL80211_IFTYPE_STATION) || - (ah->opmode == NL80211_IFTYPE_ADHOC))) { - ATH_RSSI_LPF(sc->last_rssi, rx_stats->rs_rssi); - last_rssi = sc->last_rssi; - - if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) - rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); - if (rssi < 0) - rssi = 0; - - ah->stats.avgbrssi = rssi; - } - - rxs->signal = ah->noise + rx_stats->rs_rssi; -} - static void ath9k_process_tsf(struct ath_rx_status *rs, struct ieee80211_rx_status *rxs, u64 tsf) @@ -1055,7 +857,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, * everything but the rate is checked here, the rate check is done * separately to avoid doing two lookups for a rate for each frame. */ - if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) + if (!ath9k_cmn_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error, sc->rx.rxfilter)) return -EINVAL; if (ath_is_mybeacon(common, hdr)) { @@ -1069,10 +871,18 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, if (WARN_ON(!ah->curchan)) return -EINVAL; - if (ath9k_process_rate(common, hw, rx_stats, rx_status)) + if (ath9k_cmn_process_rate(common, hw, rx_stats, rx_status)) { + /* + * No valid hardware bitrate found -- we should not get here + * because hardware has already validated this frame as OK. + */ + ath_dbg(common, ANY, "unsupported hw bitrate detected 0x%02x using 1 Mbit\n", + rx_stats->rs_rate); + RX_STAT_INC(rx_rate_err); return -EINVAL; + } - ath9k_process_rssi(common, hw, rx_stats, rx_status); + ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status); rx_status->band = ah->curchan->chan->band; rx_status->freq = ah->curchan->chan->center_freq; @@ -1092,57 +902,6 @@ corrupt: return -EINVAL; } -static void ath9k_rx_skb_postprocess(struct ath_common *common, - struct sk_buff *skb, - struct ath_rx_status *rx_stats, - struct ieee80211_rx_status *rxs, - bool decrypt_error) -{ - struct ath_hw *ah = common->ah; - struct ieee80211_hdr *hdr; - int hdrlen, padpos, padsize; - u8 keyix; - __le16 fc; - - /* see if any padding is done by the hw and remove it */ - hdr = (struct ieee80211_hdr *) skb->data; - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - fc = hdr->frame_control; - padpos = ieee80211_hdrlen(fc); - - /* The MAC header is padded to have 32-bit boundary if the - * packet payload is non-zero. The general calculation for - * padsize would take into account odd header lengths: - * padsize = (4 - padpos % 4) % 4; However, since only - * even-length headers are used, padding can only be 0 or 2 - * bytes and we can optimize this a bit. In addition, we must - * not try to remove padding from short control frames that do - * not have payload. */ - padsize = padpos & 3; - if (padsize && skb->len>=padpos+padsize+FCS_LEN) { - memmove(skb->data + padsize, skb->data, padpos); - skb_pull(skb, padsize); - } - - keyix = rx_stats->rs_keyix; - - if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error && - ieee80211_has_protected(fc)) { - rxs->flag |= RX_FLAG_DECRYPTED; - } else if (ieee80211_has_protected(fc) - && !decrypt_error && skb->len >= hdrlen + 4) { - keyix = skb->data[hdrlen + 3] >> 6; - - if (test_bit(keyix, common->keymap)) - rxs->flag |= RX_FLAG_DECRYPTED; - } - if (ah->sw_mgmt_crypto && - (rxs->flag & RX_FLAG_DECRYPTED) && - ieee80211_is_mgmt(fc)) - /* Use software decrypt for management frames. */ - rxs->flag &= ~RX_FLAG_DECRYPTED; -} - /* * Run the LNA combining algorithm only in these cases: * @@ -1292,8 +1051,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) skb_pull(skb, ah->caps.rx_status_len); if (!rs.rs_more) - ath9k_rx_skb_postprocess(common, hdr_skb, &rs, - rxs, decrypt_error); + ath9k_cmn_rx_skb_postprocess(common, hdr_skb, &rs, + rxs, decrypt_error); if (rs.rs_more) { RX_STAT_INC(rx_frags); diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c index b686a7498450..a65cfb91adca 100644 --- a/drivers/net/wireless/ath/ath9k/tx99.c +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -108,7 +108,7 @@ static int ath9k_tx99_init(struct ath_softc *sc) struct ath_tx_control txctl; int r; - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_err(common, "driver is in invalid state unable to use TX99"); return -EINVAL; diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 1b3230fa3651..2879887f5691 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -198,7 +198,7 @@ int ath9k_suspend(struct ieee80211_hw *hw, ath_cancel_work(sc); ath_stop_ani(sc); - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_dbg(common, ANY, "Device not present\n"); ret = -EINVAL; goto fail_wow; @@ -224,7 +224,7 @@ int ath9k_suspend(struct ieee80211_hw *hw, * STA. */ - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { ath_dbg(common, WOW, "None of the STA vifs are associated\n"); ret = 1; goto fail_wow; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 55897d508a76..87cbec47fb48 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1040,11 +1040,11 @@ static int ath_max_framelen(int usec, int mcs, bool ht40, bool sgi) int symbols, bits; int bytes = 0; + usec -= L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); symbols = sgi ? TIME_SYMBOLS_HALFGI(usec) : TIME_SYMBOLS(usec); bits = symbols * bits_per_symbol[mcs % 8][ht40] * streams; bits -= OFDM_PLCP_BITS; bytes = bits / 8; - bytes -= L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); if (bytes > 65532) bytes = 65532; @@ -1076,6 +1076,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_info *info, int len, bool rts) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct sk_buff *skb; struct ieee80211_tx_info *tx_info; struct ieee80211_tx_rate *rates; @@ -1145,7 +1146,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, } /* legacy rates */ - rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx]; + rate = &common->sbands[tx_info->band].bitrates[rates[i].idx]; if ((tx_info->band == IEEE80211_BAND_2GHZ) && !(rate->flags & IEEE80211_RATE_ERP_G)) phy = WLAN_RC_PHY_CCK; @@ -1698,7 +1699,7 @@ int ath_cabq_update(struct ath_softc *sc) ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi); - qi.tqi_readyTime = (cur_conf->beacon_interval * + qi.tqi_readyTime = (TU_TO_USEC(cur_conf->beacon_interval) * ATH_CABQ_READY_TIME) / 100; ath_txq_update(sc, qnum, &qi); @@ -1768,7 +1769,7 @@ bool ath_drain_all_txq(struct ath_softc *sc) int i; u32 npend = 0; - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) + if (test_bit(ATH_OP_INVALID, &common->op_flags)) return true; ath9k_hw_abort_tx_dma(ah); @@ -1816,11 +1817,12 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) */ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_atx_ac *ac, *last_ac; struct ath_atx_tid *tid, *last_tid; bool sent = false; - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags) || + if (test_bit(ATH_OP_HW_RESET, &common->op_flags) || list_empty(&txq->axq_acq)) return; @@ -2470,7 +2472,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) ath_txq_lock(sc, txq); for (;;) { - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) break; if (list_empty(&txq->axq_q)) { @@ -2553,7 +2555,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) int status; for (;;) { - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) break; status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts); @@ -2569,7 +2571,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) sc->beacon.tx_processed = true; sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK); - ath9k_csa_is_finished(sc); + ath9k_csa_update(sc); continue; } diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index 536bc46a2912..924135b8e575 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c @@ -572,7 +572,7 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len) static void carl9170_ba_check(struct ar9170 *ar, void *data, unsigned int len) { - struct ieee80211_bar *bar = (void *) data; + struct ieee80211_bar *bar = data; struct carl9170_bar_list_entry *entry; unsigned int queue; diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index e5e905910db4..415393dfb6fc 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -222,7 +222,7 @@ static const struct ieee80211_regdomain *ath_default_world_regdomain(void) static const struct ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg) { - switch (reg->regpair->regDmnEnum) { + switch (reg->regpair->reg_domain) { case 0x60: case 0x61: case 0x62: @@ -431,7 +431,7 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy, enum nl80211_reg_initiator initiator, struct ath_regulatory *reg) { - switch (reg->regpair->regDmnEnum) { + switch (reg->regpair->reg_domain) { case 0x60: case 0x63: case 0x66: @@ -560,7 +560,7 @@ static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg) printk(KERN_DEBUG "ath: EEPROM indicates we " "should expect a direct regpair map\n"); for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) - if (regDomainPairs[i].regDmnEnum == rd) + if (regDomainPairs[i].reg_domain == rd) return true; } printk(KERN_DEBUG @@ -617,7 +617,7 @@ ath_get_regpair(int regdmn) if (regdmn == NO_ENUMRD) return NULL; for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { - if (regDomainPairs[i].regDmnEnum == regdmn) + if (regDomainPairs[i].reg_domain == regdmn) return ®DomainPairs[i]; } return NULL; @@ -741,7 +741,7 @@ static int __ath_regd_init(struct ath_regulatory *reg) printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n", reg->alpha2[0], reg->alpha2[1]); printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n", - reg->regpair->regDmnEnum); + reg->regpair->reg_domain); return 0; } diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index ee25786b4447..73f12f196f14 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -44,6 +44,14 @@ static void wcn36xx_dxe_write_register(struct wcn36xx *wcn, int addr, int data) writel(data, wcn->mmio + addr); } +#define wcn36xx_dxe_write_register_x(wcn, reg, reg_data) \ +do { \ + if (wcn->chip_version == WCN36XX_CHIP_3680) \ + wcn36xx_dxe_write_register(wcn, reg ## _3680, reg_data); \ + else \ + wcn36xx_dxe_write_register(wcn, reg ## _3660, reg_data); \ +} while (0) \ + static void wcn36xx_dxe_read_register(struct wcn36xx *wcn, int addr, int *data) { *data = readl(wcn->mmio + addr); @@ -680,7 +688,7 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn) /* Setting interrupt path */ reg_data = WCN36XX_DXE_CCU_INT; - wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_REG_CCU_INT, reg_data); + wcn36xx_dxe_write_register_x(wcn, WCN36XX_DXE_REG_CCU_INT, reg_data); /***************************************/ /* Init descriptors for TX LOW channel */ diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.h b/drivers/net/wireless/ath/wcn36xx/dxe.h index c88562f85de1..35ee7e966bd2 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.h +++ b/drivers/net/wireless/ath/wcn36xx/dxe.h @@ -28,11 +28,11 @@ H2H_TEST_RX_TX = DMA2 */ /* DXE registers */ -#define WCN36XX_DXE_MEM_BASE 0x03000000 #define WCN36XX_DXE_MEM_REG 0x202000 #define WCN36XX_DXE_CCU_INT 0xA0011 -#define WCN36XX_DXE_REG_CCU_INT 0x200b10 +#define WCN36XX_DXE_REG_CCU_INT_3660 0x200b10 +#define WCN36XX_DXE_REG_CCU_INT_3680 0x2050dc /* TODO This must calculated properly but not hardcoded */ #define WCN36XX_DXE_CTRL_TX_L 0x328a44 diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h index 3c2ef0c32f72..a1f1127d7808 100644 --- a/drivers/net/wireless/ath/wcn36xx/hal.h +++ b/drivers/net/wireless/ath/wcn36xx/hal.h @@ -4384,11 +4384,13 @@ enum place_holder_in_cap_bitmap { MAX_FEATURE_SUPPORTED = 128, }; +#define WCN36XX_HAL_CAPS_SIZE 4 + struct wcn36xx_hal_feat_caps_msg { struct wcn36xx_hal_msg_header header; - u32 feat_caps[4]; + u32 feat_caps[WCN36XX_HAL_CAPS_SIZE]; } __packed; /* status codes to help debug rekey failures */ diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index e64a6784079e..4ab5370ab7a6 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -17,6 +17,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> +#include <linux/firmware.h> #include <linux/platform_device.h> #include "wcn36xx.h" @@ -177,6 +178,60 @@ static inline u8 get_sta_index(struct ieee80211_vif *vif, sta_priv->sta_index; } +static const char * const wcn36xx_caps_names[] = { + "MCC", /* 0 */ + "P2P", /* 1 */ + "DOT11AC", /* 2 */ + "SLM_SESSIONIZATION", /* 3 */ + "DOT11AC_OPMODE", /* 4 */ + "SAP32STA", /* 5 */ + "TDLS", /* 6 */ + "P2P_GO_NOA_DECOUPLE_INIT_SCAN",/* 7 */ + "WLANACTIVE_OFFLOAD", /* 8 */ + "BEACON_OFFLOAD", /* 9 */ + "SCAN_OFFLOAD", /* 10 */ + "ROAM_OFFLOAD", /* 11 */ + "BCN_MISS_OFFLOAD", /* 12 */ + "STA_POWERSAVE", /* 13 */ + "STA_ADVANCED_PWRSAVE", /* 14 */ + "AP_UAPSD", /* 15 */ + "AP_DFS", /* 16 */ + "BLOCKACK", /* 17 */ + "PHY_ERR", /* 18 */ + "BCN_FILTER", /* 19 */ + "RTT", /* 20 */ + "RATECTRL", /* 21 */ + "WOW" /* 22 */ +}; + +static const char *wcn36xx_get_cap_name(enum place_holder_in_cap_bitmap x) +{ + if (x >= ARRAY_SIZE(wcn36xx_caps_names)) + return "UNKNOWN"; + return wcn36xx_caps_names[x]; +} + +static void wcn36xx_feat_caps_info(struct wcn36xx *wcn) +{ + int i; + + for (i = 0; i < MAX_FEATURE_SUPPORTED; i++) { + if (get_feat_caps(wcn->fw_feat_caps, i)) + wcn36xx_info("FW Cap %s\n", wcn36xx_get_cap_name(i)); + } +} + +static void wcn36xx_detect_chip_version(struct wcn36xx *wcn) +{ + if (get_feat_caps(wcn->fw_feat_caps, DOT11AC)) { + wcn36xx_info("Chip is 3680\n"); + wcn->chip_version = WCN36XX_CHIP_3680; + } else { + wcn36xx_info("Chip is 3660\n"); + wcn->chip_version = WCN36XX_CHIP_3660; + } +} + static int wcn36xx_start(struct ieee80211_hw *hw) { struct wcn36xx *wcn = hw->priv; @@ -223,6 +278,16 @@ static int wcn36xx_start(struct ieee80211_hw *hw) goto out_free_smd_buf; } + if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) { + ret = wcn36xx_smd_feature_caps_exchange(wcn); + if (ret) + wcn36xx_warn("Exchange feature caps failed\n"); + else + wcn36xx_feat_caps_info(wcn); + } + + wcn36xx_detect_chip_version(wcn); + /* DMA channel initialization */ ret = wcn36xx_dxe_init(wcn); if (ret) { @@ -232,11 +297,6 @@ static int wcn36xx_start(struct ieee80211_hw *hw) wcn36xx_debugfs_init(wcn); - if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) { - ret = wcn36xx_smd_feature_caps_exchange(wcn); - if (ret) - wcn36xx_warn("Exchange feature caps failed\n"); - } INIT_LIST_HEAD(&wcn->vif_list); return 0; @@ -648,6 +708,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, bss_conf->enable_beacon); if (bss_conf->enable_beacon) { + vif_priv->dtim_period = bss_conf->dtim_period; vif_priv->bss_index = 0xff; wcn36xx_smd_config_bss(wcn, vif, NULL, vif->addr, false); @@ -992,6 +1053,7 @@ static int wcn36xx_remove(struct platform_device *pdev) struct wcn36xx *wcn = hw->priv; wcn36xx_dbg(WCN36XX_DBG_MAC, "platform remove\n"); + release_firmware(wcn->nv); mutex_destroy(&wcn->hal_mutex); ieee80211_unregister_hw(hw); diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 750626b0e22d..7bf0ef8a1f56 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -195,9 +195,11 @@ static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn, static int wcn36xx_smd_send_and_wait(struct wcn36xx *wcn, size_t len) { int ret = 0; + unsigned long start; wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "HAL >>> ", wcn->hal_buf, len); init_completion(&wcn->hal_rsp_compl); + start = jiffies; ret = wcn->ctrl_ops->tx(wcn->hal_buf, len); if (ret) { wcn36xx_err("HAL TX failed\n"); @@ -205,10 +207,13 @@ static int wcn36xx_smd_send_and_wait(struct wcn36xx *wcn, size_t len) } if (wait_for_completion_timeout(&wcn->hal_rsp_compl, msecs_to_jiffies(HAL_MSG_TIMEOUT)) <= 0) { - wcn36xx_err("Timeout while waiting SMD response\n"); + wcn36xx_err("Timeout! No SMD response in %dms\n", + HAL_MSG_TIMEOUT); ret = -ETIME; goto out; } + wcn36xx_dbg(WCN36XX_DBG_SMD, "SMD command completed in %dms", + jiffies_to_msecs(jiffies - start)); out: return ret; } @@ -246,21 +251,22 @@ static int wcn36xx_smd_rsp_status_check(void *buf, size_t len) int wcn36xx_smd_load_nv(struct wcn36xx *wcn) { - const struct firmware *nv; struct nv_data *nv_d; struct wcn36xx_hal_nv_img_download_req_msg msg_body; int fw_bytes_left; int ret; u16 fm_offset = 0; - ret = request_firmware(&nv, WLAN_NV_FILE, wcn->dev); - if (ret) { - wcn36xx_err("Failed to load nv file %s: %d\n", - WLAN_NV_FILE, ret); - goto out_free_nv; + if (!wcn->nv) { + ret = request_firmware(&wcn->nv, WLAN_NV_FILE, wcn->dev); + if (ret) { + wcn36xx_err("Failed to load nv file %s: %d\n", + WLAN_NV_FILE, ret); + goto out; + } } - nv_d = (struct nv_data *)nv->data; + nv_d = (struct nv_data *)wcn->nv->data; INIT_HAL_MSG(msg_body, WCN36XX_HAL_DOWNLOAD_NV_REQ); msg_body.header.len += WCN36XX_NV_FRAGMENT_SIZE; @@ -270,7 +276,7 @@ int wcn36xx_smd_load_nv(struct wcn36xx *wcn) mutex_lock(&wcn->hal_mutex); do { - fw_bytes_left = nv->size - fm_offset - 4; + fw_bytes_left = wcn->nv->size - fm_offset - 4; if (fw_bytes_left > WCN36XX_NV_FRAGMENT_SIZE) { msg_body.last_fragment = 0; msg_body.nv_img_buffer_size = WCN36XX_NV_FRAGMENT_SIZE; @@ -308,10 +314,7 @@ int wcn36xx_smd_load_nv(struct wcn36xx *wcn) out_unlock: mutex_unlock(&wcn->hal_mutex); -out_free_nv: - release_firmware(nv); - - return ret; +out: return ret; } static int wcn36xx_smd_start_rsp(struct wcn36xx *wcn, void *buf, size_t len) @@ -899,11 +902,12 @@ static int wcn36xx_smd_config_sta_rsp(struct wcn36xx *wcn, sta_priv->sta_index = params->sta_index; sta_priv->dpu_desc_index = params->dpu_index; + sta_priv->ucast_dpu_sign = params->uc_ucast_sig; wcn36xx_dbg(WCN36XX_DBG_HAL, - "hal config sta rsp status %d sta_index %d bssid_index %d p2p %d\n", + "hal config sta rsp status %d sta_index %d bssid_index %d uc_ucast_sig %d p2p %d\n", params->status, params->sta_index, params->bssid_index, - params->p2p); + params->uc_ucast_sig, params->p2p); return 0; } @@ -1118,7 +1122,7 @@ static int wcn36xx_smd_config_bss_rsp(struct wcn36xx *wcn, priv_vif->sta->bss_dpu_desc_index = params->dpu_desc_index; } - priv_vif->ucast_dpu_signature = params->ucast_dpu_signature; + priv_vif->self_ucast_dpu_sign = params->ucast_dpu_signature; return 0; } @@ -1637,12 +1641,12 @@ int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn, ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); if (ret) { - wcn36xx_err("Sending hal_exit_bmps failed\n"); + wcn36xx_err("Sending hal_keep_alive failed\n"); goto out; } ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); if (ret) { - wcn36xx_err("hal_exit_bmps response failed err=%d\n", ret); + wcn36xx_err("hal_keep_alive response failed err=%d\n", ret); goto out; } out: @@ -1682,8 +1686,7 @@ out: return ret; } -static inline void set_feat_caps(u32 *bitmap, - enum place_holder_in_cap_bitmap cap) +void set_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap) { int arr_idx, bit_idx; @@ -1697,8 +1700,7 @@ static inline void set_feat_caps(u32 *bitmap, bitmap[arr_idx] |= (1 << bit_idx); } -static inline int get_feat_caps(u32 *bitmap, - enum place_holder_in_cap_bitmap cap) +int get_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap) { int arr_idx, bit_idx; int ret = 0; @@ -1714,8 +1716,7 @@ static inline int get_feat_caps(u32 *bitmap, return ret; } -static inline void clear_feat_caps(u32 *bitmap, - enum place_holder_in_cap_bitmap cap) +void clear_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap) { int arr_idx, bit_idx; @@ -1731,8 +1732,8 @@ static inline void clear_feat_caps(u32 *bitmap, int wcn36xx_smd_feature_caps_exchange(struct wcn36xx *wcn) { - struct wcn36xx_hal_feat_caps_msg msg_body; - int ret = 0; + struct wcn36xx_hal_feat_caps_msg msg_body, *rsp; + int ret = 0, i; mutex_lock(&wcn->hal_mutex); INIT_HAL_MSG(msg_body, WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_REQ); @@ -1746,12 +1747,15 @@ int wcn36xx_smd_feature_caps_exchange(struct wcn36xx *wcn) wcn36xx_err("Sending hal_feature_caps_exchange failed\n"); goto out; } - ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); - if (ret) { - wcn36xx_err("hal_feature_caps_exchange response failed err=%d\n", - ret); + if (wcn->hal_rsp_len != sizeof(*rsp)) { + wcn36xx_err("Invalid hal_feature_caps_exchange response"); goto out; } + + rsp = (struct wcn36xx_hal_feat_caps_msg *) wcn->hal_buf; + + for (i = 0; i < WCN36XX_HAL_CAPS_SIZE; i++) + wcn->fw_feat_caps[i] = rsp->feat_caps[i]; out: mutex_unlock(&wcn->hal_mutex); return ret; diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h index e7c39019c6f1..008d03423dbf 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.h +++ b/drivers/net/wireless/ath/wcn36xx/smd.h @@ -24,7 +24,7 @@ #define WCN36XX_HAL_BUF_SIZE 4096 -#define HAL_MSG_TIMEOUT 200 +#define HAL_MSG_TIMEOUT 500 #define WCN36XX_SMSM_WLAN_TX_ENABLE 0x00000400 #define WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY 0x00000200 /* The PNO version info be contained in the rsp msg */ @@ -112,6 +112,9 @@ int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn, int wcn36xx_smd_dump_cmd_req(struct wcn36xx *wcn, u32 arg1, u32 arg2, u32 arg3, u32 arg4, u32 arg5); int wcn36xx_smd_feature_caps_exchange(struct wcn36xx *wcn); +void set_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap); +int get_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap); +void clear_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap); int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index b2b60e30caaf..32bb26a0db2a 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -57,8 +57,7 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) RX_FLAG_MMIC_STRIPPED | RX_FLAG_DECRYPTED; - wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x status->vendor_radiotap_len=%x\n", - status.flag, status.vendor_radiotap_len); + wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x\n", status.flag); memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); @@ -132,6 +131,7 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, struct ieee80211_vif, drv_priv); + bd->dpu_sign = sta_priv->ucast_dpu_sign; if (vif->type == NL80211_IFTYPE_STATION) { bd->sta_index = sta_priv->bss_sta_index; bd->dpu_desc_idx = sta_priv->bss_dpu_desc_index; @@ -145,10 +145,9 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, __vif_priv = get_vif_by_addr(wcn, hdr->addr2); bd->sta_index = __vif_priv->self_sta_index; bd->dpu_desc_idx = __vif_priv->self_dpu_desc_index; + bd->dpu_sign = __vif_priv->self_ucast_dpu_sign; } - bd->dpu_sign = __vif_priv->ucast_dpu_signature; - if (ieee80211_is_nullfunc(hdr->frame_control) || (sta_priv && !sta_priv->is_data_encrypted)) bd->dpu_ne = 1; diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index 8fa5cbace5ab..f0fb81dfd17b 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -125,10 +125,10 @@ struct wcn36xx_vif { enum wcn36xx_power_state pw_state; u8 bss_index; - u8 ucast_dpu_signature; /* Returned from WCN36XX_HAL_ADD_STA_SELF_RSP */ u8 self_sta_index; u8 self_dpu_desc_index; + u8 self_ucast_dpu_sign; }; /** @@ -159,6 +159,7 @@ struct wcn36xx_sta { u16 tid; u8 sta_index; u8 dpu_desc_index; + u8 ucast_dpu_sign; u8 bss_sta_index; u8 bss_dpu_desc_index; bool is_data_encrypted; @@ -171,10 +172,14 @@ struct wcn36xx { struct device *dev; struct list_head vif_list; + const struct firmware *nv; + u8 fw_revision; u8 fw_version; u8 fw_minor; u8 fw_major; + u32 fw_feat_caps[WCN36XX_HAL_CAPS_SIZE]; + u32 chip_version; /* extra byte for the NULL termination */ u8 crm_version[WCN36XX_HAL_VERSION_LENGTH + 1]; @@ -222,6 +227,9 @@ struct wcn36xx { }; +#define WCN36XX_CHIP_3660 0 +#define WCN36XX_CHIP_3680 1 + static inline bool wcn36xx_is_fw_version(struct wcn36xx *wcn, u8 major, u8 minor, diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile index 990dd42ae79e..c7a3465fd02a 100644 --- a/drivers/net/wireless/ath/wil6210/Makefile +++ b/drivers/net/wireless/ath/wil6210/Makefile @@ -9,6 +9,7 @@ wil6210-y += wmi.o wil6210-y += interrupt.o wil6210-y += txrx.o wil6210-y += debug.o +wil6210-y += rx_reorder.o wil6210-$(CONFIG_WIL6210_TRACING) += trace.o # for tracing framework to find trace.h diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 5b340769d5bb..4806a49cb61b 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -104,41 +104,125 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type) return -EOPNOTSUPP; } -static int wil_cfg80211_get_station(struct wiphy *wiphy, - struct net_device *ndev, - u8 *mac, struct station_info *sinfo) +static int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, + struct station_info *sinfo) { - struct wil6210_priv *wil = wiphy_to_wil(wiphy); - int rc; struct wmi_notify_req_cmd cmd = { - .cid = 0, + .cid = cid, .interval_usec = 0, }; + struct { + struct wil6210_mbox_hdr_wmi wmi; + struct wmi_notify_req_done_event evt; + } __packed reply; + struct wil_net_stats *stats = &wil->sta[cid].stats; + int rc; - if (memcmp(mac, wil->dst_addr[0], ETH_ALEN)) - return -ENOENT; - - /* WMI_NOTIFY_REQ_DONE_EVENTID handler fills wil->stats.bf_mcs */ rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd), - WMI_NOTIFY_REQ_DONE_EVENTID, NULL, 0, 20); + WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply), 20); if (rc) return rc; + wil_dbg_wmi(wil, "Link status for CID %d: {\n" + " MCS %d TSF 0x%016llx\n" + " BF status 0x%08x SNR 0x%08x SQI %d%%\n" + " Tx Tpt %d goodput %d Rx goodput %d\n" + " Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n", + cid, le16_to_cpu(reply.evt.bf_mcs), + le64_to_cpu(reply.evt.tsf), reply.evt.status, + le32_to_cpu(reply.evt.snr_val), + reply.evt.sqi, + le32_to_cpu(reply.evt.tx_tpt), + le32_to_cpu(reply.evt.tx_goodput), + le32_to_cpu(reply.evt.rx_goodput), + le16_to_cpu(reply.evt.my_rx_sector), + le16_to_cpu(reply.evt.my_tx_sector), + le16_to_cpu(reply.evt.other_rx_sector), + le16_to_cpu(reply.evt.other_tx_sector)); + sinfo->generation = wil->sinfo_gen; - sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->filled = STATION_INFO_RX_BYTES | + STATION_INFO_TX_BYTES | + STATION_INFO_RX_PACKETS | + STATION_INFO_TX_PACKETS | + STATION_INFO_RX_BITRATE | + STATION_INFO_TX_BITRATE | + STATION_INFO_RX_DROP_MISC | + STATION_INFO_TX_FAILED; + sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; - sinfo->txrate.mcs = wil->stats.bf_mcs; - sinfo->filled |= STATION_INFO_RX_BITRATE; + sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs); sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; - sinfo->rxrate.mcs = wil->stats.last_mcs_rx; + sinfo->rxrate.mcs = stats->last_mcs_rx; + sinfo->rx_bytes = stats->rx_bytes; + sinfo->rx_packets = stats->rx_packets; + sinfo->rx_dropped_misc = stats->rx_dropped; + sinfo->tx_bytes = stats->tx_bytes; + sinfo->tx_packets = stats->tx_packets; + sinfo->tx_failed = stats->tx_errors; if (test_bit(wil_status_fwconnected, &wil->status)) { sinfo->filled |= STATION_INFO_SIGNAL; - sinfo->signal = 12; /* TODO: provide real value */ + sinfo->signal = reply.evt.sqi; } - return 0; + return rc; +} + +static int wil_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *ndev, + u8 *mac, struct station_info *sinfo) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + + int cid = wil_find_cid(wil, mac); + + wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid); + if (cid < 0) + return cid; + + rc = wil_cid_fill_sinfo(wil, cid, sinfo); + + return rc; +} + +/* + * Find @idx-th active STA for station dump. + */ +static int wil_find_cid_by_idx(struct wil6210_priv *wil, int idx) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { + if (wil->sta[i].status == wil_sta_unused) + continue; + if (idx == 0) + return i; + idx--; + } + + return -ENOENT; +} + +static int wil_cfg80211_dump_station(struct wiphy *wiphy, + struct net_device *dev, int idx, + u8 *mac, struct station_info *sinfo) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + int cid = wil_find_cid_by_idx(wil, idx); + + if (cid < 0) + return -ENOENT; + + memcpy(mac, wil->sta[cid].addr, ETH_ALEN); + wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid); + + rc = wil_cid_fill_sinfo(wil, cid, sinfo); + + return rc; } static int wil_cfg80211_change_iface(struct wiphy *wiphy, @@ -181,6 +265,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, u16 chnl[4]; } __packed cmd; uint i, n; + int rc; if (wil->scan_request) { wil_err(wil, "Already scanning\n"); @@ -198,7 +283,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, /* FW don't support scan after connection attempt */ if (test_bit(wil_status_dontscan, &wil->status)) { - wil_err(wil, "Scan after connect attempt not supported\n"); + wil_err(wil, "Can't scan now\n"); return -EBUSY; } @@ -221,8 +306,13 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, request->channels[i]->center_freq); } - return wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + + rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0])); + + if (rc) + wil->scan_request = NULL; + + return rc; } static int wil_cfg80211_connect(struct wiphy *wiphy, @@ -237,6 +327,10 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, int ch; int rc = 0; + if (test_bit(wil_status_fwconnecting, &wil->status) || + test_bit(wil_status_fwconnected, &wil->status)) + return -EALREADY; + bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, sme->ssid, sme->ssid_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); @@ -318,10 +412,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, memcpy(conn.bssid, bss->bssid, ETH_ALEN); memcpy(conn.dst_mac, bss->bssid, ETH_ALEN); - /* - * FW don't support scan after connection attempt - */ - set_bit(wil_status_dontscan, &wil->status); + set_bit(wil_status_fwconnecting, &wil->status); rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn)); @@ -330,7 +421,6 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, mod_timer(&wil->connect_timer, jiffies + msecs_to_jiffies(2000)); } else { - clear_bit(wil_status_dontscan, &wil->status); clear_bit(wil_status_fwconnecting, &wil->status); } @@ -352,6 +442,40 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy, return rc; } +static int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, + u64 *cookie) +{ + const u8 *buf = params->buf; + size_t len = params->len; + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + struct ieee80211_mgmt *mgmt_frame = (void *)buf; + struct wmi_sw_tx_req_cmd *cmd; + struct { + struct wil6210_mbox_hdr_wmi wmi; + struct wmi_sw_tx_complete_event evt; + } __packed evt; + + cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN); + cmd->len = cpu_to_le16(len); + memcpy(cmd->payload, buf, len); + + rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len, + WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); + if (rc == 0) + rc = evt.evt.status; + + kfree(cmd); + + return rc; +} + static int wil_cfg80211_set_channel(struct wiphy *wiphy, struct cfg80211_chan_def *chandef) { @@ -402,6 +526,41 @@ static int wil_cfg80211_set_default_key(struct wiphy *wiphy, return 0; } +static int wil_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, + u64 *cookie) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + + /* TODO: handle duration */ + wil_info(wil, "%s(%d, %d ms)\n", __func__, chan->center_freq, duration); + + rc = wmi_set_channel(wil, chan->hw_value); + if (rc) + return rc; + + rc = wmi_rxon(wil, true); + + return rc; +} + +static int wil_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + + wil_info(wil, "%s()\n", __func__); + + rc = wmi_rxon(wil, false); + + return rc; +} + static int wil_fix_bcon(struct wil6210_priv *wil, struct cfg80211_beacon_data *bcon) { @@ -450,18 +609,20 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, if (wil_fix_bcon(wil, bcon)) wil_dbg_misc(wil, "Fixed bcon\n"); + mutex_lock(&wil->mutex); + rc = wil_reset(wil); if (rc) - return rc; + goto out; /* Rx VRING. */ rc = wil_rx_init(wil); if (rc) - return rc; + goto out; rc = wmi_set_ssid(wil, info->ssid_len, info->ssid); if (rc) - return rc; + goto out; /* MAC address - pre-requisite for other commands */ wmi_set_mac_address(wil, ndev->dev_addr); @@ -485,11 +646,13 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype, channel->hw_value); if (rc) - return rc; + goto out; netif_carrier_on(ndev); +out: + mutex_unlock(&wil->mutex); return rc; } @@ -499,17 +662,36 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, int rc = 0; struct wil6210_priv *wil = wiphy_to_wil(wiphy); + mutex_lock(&wil->mutex); + rc = wmi_pcp_stop(wil); + mutex_unlock(&wil->mutex); return rc; } +static int wil_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, u8 *mac) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + + mutex_lock(&wil->mutex); + wil6210_disconnect(wil, mac); + mutex_unlock(&wil->mutex); + + return 0; +} + static struct cfg80211_ops wil_cfg80211_ops = { .scan = wil_cfg80211_scan, .connect = wil_cfg80211_connect, .disconnect = wil_cfg80211_disconnect, .change_virtual_intf = wil_cfg80211_change_iface, .get_station = wil_cfg80211_get_station, + .dump_station = wil_cfg80211_dump_station, + .remain_on_channel = wil_remain_on_channel, + .cancel_remain_on_channel = wil_cancel_remain_on_channel, + .mgmt_tx = wil_cfg80211_mgmt_tx, .set_monitor_channel = wil_cfg80211_set_channel, .add_key = wil_cfg80211_add_key, .del_key = wil_cfg80211_del_key, @@ -517,6 +699,7 @@ static struct cfg80211_ops wil_cfg80211_ops = { /* AP mode */ .start_ap = wil_cfg80211_start_ap, .stop_ap = wil_cfg80211_stop_ap, + .del_station = wil_cfg80211_del_station, }; static void wil_wiphy_init(struct wiphy *wiphy) @@ -542,7 +725,7 @@ static void wil_wiphy_init(struct wiphy *wiphy) wiphy->bands[IEEE80211_BAND_60GHZ] = &wil_band_60ghz; /* TODO: figure this out */ - wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; wiphy->cipher_suites = wil_cipher_suites; wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites); diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 1caa31992a7e..ecdabe4adec3 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -26,9 +26,11 @@ /* Nasty hack. Better have per device instances */ static u32 mem_addr; static u32 dbg_txdesc_index; +static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, - const char *name, struct vring *vring) + const char *name, struct vring *vring, + char _s, char _h) { void __iomem *x = wmi_addr(wil, vring->hwtail); @@ -50,8 +52,8 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, volatile struct vring_tx_desc *d = &vring->va[i].tx; if ((i % 64) == 0 && (i != 0)) seq_printf(s, "\n"); - seq_printf(s, "%s", (d->dma.status & BIT(0)) ? - "S" : (vring->ctx[i].skb ? "H" : "h")); + seq_printf(s, "%c", (d->dma.status & BIT(0)) ? + _s : (vring->ctx[i].skb ? _h : 'h')); } seq_printf(s, "\n"); } @@ -63,14 +65,19 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) uint i; struct wil6210_priv *wil = s->private; - wil_print_vring(s, wil, "rx", &wil->vring_rx); + wil_print_vring(s, wil, "rx", &wil->vring_rx, 'S', '_'); for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { struct vring *vring = &(wil->vring_tx[i]); if (vring->va) { + int cid = wil->vring2cid_tid[i][0]; + int tid = wil->vring2cid_tid[i][1]; char name[10]; snprintf(name, sizeof(name), "tx_%2d", i); - wil_print_vring(s, wil, name, vring); + + seq_printf(s, "\n%pM CID %d TID %d\n", + wil->sta[cid].addr, cid, tid); + wil_print_vring(s, wil, name, vring, '_', 'H'); } } @@ -390,25 +397,78 @@ static const struct file_operations fops_reset = { .write = wil_write_file_reset, .open = simple_open, }; -/*---------Tx descriptor------------*/ +static void wil_seq_hexdump(struct seq_file *s, void *p, int len, + const char *prefix) +{ + char printbuf[16 * 3 + 2]; + int i = 0; + while (i < len) { + int l = min(len - i, 16); + hex_dump_to_buffer(p + i, l, 16, 1, printbuf, + sizeof(printbuf), false); + seq_printf(s, "%s%s\n", prefix, printbuf); + i += l; + } +} + +static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb) +{ + int i = 0; + int len = skb_headlen(skb); + void *p = skb->data; + int nr_frags = skb_shinfo(skb)->nr_frags; + + seq_printf(s, " len = %d\n", len); + wil_seq_hexdump(s, p, len, " : "); + + if (nr_frags) { + seq_printf(s, " nr_frags = %d\n", nr_frags); + for (i = 0; i < nr_frags; i++) { + const struct skb_frag_struct *frag = + &skb_shinfo(skb)->frags[i]; + + len = skb_frag_size(frag); + p = skb_frag_address_safe(frag); + seq_printf(s, " [%2d] : len = %d\n", i, len); + wil_seq_hexdump(s, p, len, " : "); + } + } +} + +/*---------Tx/Rx descriptor------------*/ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; - struct vring *vring = &(wil->vring_tx[0]); + struct vring *vring; + bool tx = (dbg_vring_index < WIL6210_MAX_TX_RINGS); + if (tx) + vring = &(wil->vring_tx[dbg_vring_index]); + else + vring = &wil->vring_rx; if (!vring->va) { - seq_printf(s, "No Tx VRING\n"); + if (tx) + seq_printf(s, "No Tx[%2d] VRING\n", dbg_vring_index); + else + seq_puts(s, "No Rx VRING\n"); return 0; } if (dbg_txdesc_index < vring->size) { + /* use struct vring_tx_desc for Rx as well, + * only field used, .dma.length, is the same + */ volatile struct vring_tx_desc *d = &(vring->va[dbg_txdesc_index].tx); volatile u32 *u = (volatile u32 *)d; struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb; - seq_printf(s, "Tx[%3d] = {\n", dbg_txdesc_index); + if (tx) + seq_printf(s, "Tx[%2d][%3d] = {\n", dbg_vring_index, + dbg_txdesc_index); + else + seq_printf(s, "Rx[%3d] = {\n", dbg_txdesc_index); seq_printf(s, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n", u[0], u[1], u[2], u[3]); seq_printf(s, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n", @@ -416,31 +476,19 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) seq_printf(s, " SKB = %p\n", skb); if (skb) { - char printbuf[16 * 3 + 2]; - int i = 0; - int len = le16_to_cpu(d->dma.length); - void *p = skb->data; - - if (len != skb_headlen(skb)) { - seq_printf(s, "!!! len: desc = %d skb = %d\n", - len, skb_headlen(skb)); - len = min_t(int, len, skb_headlen(skb)); - } - - seq_printf(s, " len = %d\n", len); - - while (i < len) { - int l = min(len - i, 16); - hex_dump_to_buffer(p + i, l, 16, 1, printbuf, - sizeof(printbuf), false); - seq_printf(s, " : %s\n", printbuf); - i += l; - } + skb_get(skb); + wil_seq_print_skb(s, skb); + kfree_skb(skb); } seq_printf(s, "}\n"); } else { - seq_printf(s, "TxDesc index (%d) >= size (%d)\n", - dbg_txdesc_index, vring->size); + if (tx) + seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n", + dbg_vring_index, dbg_txdesc_index, + vring->size); + else + seq_printf(s, "RxDesc index (%d) >= size (%d)\n", + dbg_txdesc_index, vring->size); } return 0; @@ -570,6 +618,69 @@ static const struct file_operations fops_temp = { .llseek = seq_lseek, }; +/*---------Station matrix------------*/ +static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) +{ + int i; + u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size; + seq_printf(s, "0x%03x [", r->head_seq_num); + for (i = 0; i < r->buf_size; i++) { + if (i == index) + seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|'); + else + seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_'); + } + seq_puts(s, "]\n"); +} + +static int wil_sta_debugfs_show(struct seq_file *s, void *data) +{ + struct wil6210_priv *wil = s->private; + int i, tid; + + for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { + struct wil_sta_info *p = &wil->sta[i]; + char *status = "unknown"; + switch (p->status) { + case wil_sta_unused: + status = "unused "; + break; + case wil_sta_conn_pending: + status = "pending "; + break; + case wil_sta_connected: + status = "connected"; + break; + } + seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status, + (p->data_port_open ? " data_port_open" : "")); + + if (p->status == wil_sta_connected) { + for (tid = 0; tid < WIL_STA_TID_NUM; tid++) { + struct wil_tid_ampdu_rx *r = p->tid_rx[tid]; + if (r) { + seq_printf(s, "[%2d] ", tid); + wil_print_rxtid(s, r); + } + } + } + } + + return 0; +} + +static int wil_sta_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, wil_sta_debugfs_show, inode->i_private); +} + +static const struct file_operations fops_sta = { + .open = wil_sta_seq_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek, +}; + /*----------------*/ int wil6210_debugfs_init(struct wil6210_priv *wil) { @@ -581,9 +692,13 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox); debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring); - debugfs_create_file("txdesc", S_IRUGO, dbg, wil, &fops_txdesc); - debugfs_create_u32("txdesc_index", S_IRUGO | S_IWUSR, dbg, + debugfs_create_file("stations", S_IRUGO, dbg, wil, &fops_sta); + debugfs_create_file("desc", S_IRUGO, dbg, wil, &fops_txdesc); + debugfs_create_u32("desc_index", S_IRUGO | S_IWUSR, dbg, &dbg_txdesc_index); + debugfs_create_u32("vring_index", S_IRUGO | S_IWUSR, dbg, + &dbg_vring_index); + debugfs_create_file("bf", S_IRUGO, dbg, wil, &fops_bf); debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid); debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg, diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 10919f95a83c..5824cd41e4ba 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -195,8 +195,12 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) { wil_dbg_irq(wil, "RX done\n"); isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE; - wil_dbg_txrx(wil, "NAPI schedule\n"); - napi_schedule(&wil->napi_rx); + if (test_bit(wil_status_reset_done, &wil->status)) { + wil_dbg_txrx(wil, "NAPI(Rx) schedule\n"); + napi_schedule(&wil->napi_rx); + } else { + wil_err(wil, "Got Rx interrupt while in reset\n"); + } } if (isr) @@ -226,10 +230,15 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) { wil_dbg_irq(wil, "TX done\n"); - napi_schedule(&wil->napi_tx); isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE; /* clear also all VRING interrupts */ isr &= ~(BIT(25) - 1UL); + if (test_bit(wil_status_reset_done, &wil->status)) { + wil_dbg_txrx(wil, "NAPI(Tx) schedule\n"); + napi_schedule(&wil->napi_tx); + } else { + wil_err(wil, "Got Tx interrupt while in reset\n"); + } } if (isr) @@ -319,6 +328,7 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie) if (isr & ISR_MISC_FW_ERROR) { wil_notify_fw_error(wil); isr &= ~ISR_MISC_FW_ERROR; + wil_fw_error_recovery(wil); } if (isr & ISR_MISC_MBOX_EVT) { @@ -493,6 +503,23 @@ free0: return rc; } +/* can't use wil_ioread32_and_clear because ICC value is not ser yet */ +static inline void wil_clear32(void __iomem *addr) +{ + u32 x = ioread32(addr); + + iowrite32(x, addr); +} + +void wil6210_clear_irq(struct wil6210_priv *wil) +{ + wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) + + offsetof(struct RGF_ICR, ICR)); + wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) + + offsetof(struct RGF_ICR, ICR)); + wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + + offsetof(struct RGF_ICR, ICR)); +} int wil6210_init_irq(struct wil6210_priv *wil, int irq) { diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index fd30cddd5882..95f4efe9ef37 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -16,8 +16,14 @@ #include <linux/moduleparam.h> #include <linux/if_arp.h> +#include <linux/etherdevice.h> #include "wil6210.h" +#include "txrx.h" + +static bool no_fw_recovery; +module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(no_fw_recovery, " disable FW error recovery"); /* * Due to a hardware issue, @@ -52,29 +58,74 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, __raw_writel(*s++, d++); } -static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid) +static void wil_disconnect_cid(struct wil6210_priv *wil, int cid) { uint i; - struct net_device *ndev = wil_to_ndev(wil); + struct wil_sta_info *sta = &wil->sta[cid]; - wil_dbg_misc(wil, "%s()\n", __func__); + sta->data_port_open = false; + if (sta->status != wil_sta_unused) { + wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING); + sta->status = wil_sta_unused; + } - wil_link_off(wil); - if (test_bit(wil_status_fwconnected, &wil->status)) { - clear_bit(wil_status_fwconnected, &wil->status); - cfg80211_disconnected(ndev, - WLAN_STATUS_UNSPECIFIED_FAILURE, - NULL, 0, GFP_KERNEL); - } else if (test_bit(wil_status_fwconnecting, &wil->status)) { - cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_KERNEL); + for (i = 0; i < WIL_STA_TID_NUM; i++) { + struct wil_tid_ampdu_rx *r = sta->tid_rx[i]; + sta->tid_rx[i] = NULL; + wil_tid_ampdu_rx_free(wil, r); + } + for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { + if (wil->vring2cid_tid[i][0] == cid) + wil_vring_fini_tx(wil, i); } - clear_bit(wil_status_fwconnecting, &wil->status); - for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) - wil_vring_fini_tx(wil, i); + memset(&sta->stats, 0, sizeof(sta->stats)); +} - clear_bit(wil_status_dontscan, &wil->status); +static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid) +{ + int cid = -ENOENT; + struct net_device *ndev = wil_to_ndev(wil); + struct wireless_dev *wdev = wil->wdev; + + might_sleep(); + if (bssid) { + cid = wil_find_cid(wil, bssid); + wil_dbg_misc(wil, "%s(%pM, CID %d)\n", __func__, bssid, cid); + } else { + wil_dbg_misc(wil, "%s(all)\n", __func__); + } + + if (cid >= 0) /* disconnect 1 peer */ + wil_disconnect_cid(wil, cid); + else /* disconnect all */ + for (cid = 0; cid < WIL6210_MAX_CID; cid++) + wil_disconnect_cid(wil, cid); + + /* link state */ + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + wil_link_off(wil); + if (test_bit(wil_status_fwconnected, &wil->status)) { + clear_bit(wil_status_fwconnected, &wil->status); + cfg80211_disconnected(ndev, + WLAN_STATUS_UNSPECIFIED_FAILURE, + NULL, 0, GFP_KERNEL); + } else if (test_bit(wil_status_fwconnecting, &wil->status)) { + cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); + } + clear_bit(wil_status_fwconnecting, &wil->status); + break; + default: + /* AP-like interface and monitor: + * never scan, always connected + */ + if (bssid) + cfg80211_del_sta(ndev, bssid, GFP_KERNEL); + break; + } } static void wil_disconnect_worker(struct work_struct *work) @@ -82,7 +133,9 @@ static void wil_disconnect_worker(struct work_struct *work) struct wil6210_priv *wil = container_of(work, struct wil6210_priv, disconnect_worker); + mutex_lock(&wil->mutex); _wil6210_disconnect(wil, NULL); + mutex_unlock(&wil->mutex); } static void wil_connect_timer_fn(ulong x) @@ -97,12 +150,55 @@ static void wil_connect_timer_fn(ulong x) schedule_work(&wil->disconnect_worker); } +static void wil_fw_error_worker(struct work_struct *work) +{ + struct wil6210_priv *wil = container_of(work, + struct wil6210_priv, fw_error_worker); + struct wireless_dev *wdev = wil->wdev; + + wil_dbg_misc(wil, "fw error worker\n"); + + if (no_fw_recovery) + return; + + mutex_lock(&wil->mutex); + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_MONITOR: + wil_info(wil, "fw error recovery started...\n"); + wil_reset(wil); + + /* need to re-allocate Rx ring after reset */ + wil_rx_init(wil); + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + /* recovery in these modes is done by upper layers */ + break; + default: + break; + } + mutex_unlock(&wil->mutex); +} + +static int wil_find_free_vring(struct wil6210_priv *wil) +{ + int i; + for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { + if (!wil->vring_tx[i].va) + return i; + } + return -EINVAL; +} + static void wil_connect_worker(struct work_struct *work) { int rc; struct wil6210_priv *wil = container_of(work, struct wil6210_priv, connect_worker); int cid = wil->pending_connect_cid; + int ringid = wil_find_free_vring(wil); if (cid < 0) { wil_err(wil, "No connection pending\n"); @@ -111,16 +207,22 @@ static void wil_connect_worker(struct work_struct *work) wil_dbg_wmi(wil, "Configure for connection CID %d\n", cid); - rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE, cid, 0); + rc = wil_vring_init_tx(wil, ringid, WIL6210_TX_RING_SIZE, cid, 0); wil->pending_connect_cid = -1; - if (rc == 0) + if (rc == 0) { + wil->sta[cid].status = wil_sta_connected; wil_link_on(wil); + } else { + wil->sta[cid].status = wil_sta_unused; + } } int wil_priv_init(struct wil6210_priv *wil) { wil_dbg_misc(wil, "%s()\n", __func__); + memset(wil->sta, 0, sizeof(wil->sta)); + mutex_init(&wil->mutex); mutex_init(&wil->wmi_mutex); @@ -132,6 +234,7 @@ int wil_priv_init(struct wil6210_priv *wil) INIT_WORK(&wil->connect_worker, wil_connect_worker); INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker); INIT_WORK(&wil->wmi_event_worker, wmi_event_worker); + INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker); INIT_LIST_HEAD(&wil->pending_wmi_ev); spin_lock_init(&wil->wmi_ev_lock); @@ -158,7 +261,10 @@ void wil6210_disconnect(struct wil6210_priv *wil, void *bssid) void wil_priv_deinit(struct wil6210_priv *wil) { cancel_work_sync(&wil->disconnect_worker); + cancel_work_sync(&wil->fw_error_worker); + mutex_lock(&wil->mutex); wil6210_disconnect(wil, NULL); + mutex_unlock(&wil->mutex); wmi_event_flush(wil); destroy_workqueue(wil->wmi_wq_conn); destroy_workqueue(wil->wmi_wq); @@ -166,40 +272,78 @@ void wil_priv_deinit(struct wil6210_priv *wil) static void wil_target_reset(struct wil6210_priv *wil) { + int delay = 0; + u32 hw_state; + u32 rev_id; + wil_dbg_misc(wil, "Resetting...\n"); + /* register read */ +#define R(a) ioread32(wil->csr + HOSTADDR(a)) /* register write */ #define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a)) /* register set = read, OR, write */ -#define S(a, v) iowrite32(ioread32(wil->csr + HOSTADDR(a)) | v, \ - wil->csr + HOSTADDR(a)) +#define S(a, v) W(a, R(a) | v) + /* register clear = read, AND with inverted, write */ +#define C(a, v) W(a, R(a) & ~v) + wil->hw_version = R(RGF_USER_FW_REV_ID); + rev_id = wil->hw_version & 0xff; /* hpal_perst_from_pad_src_n_mask */ S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6)); /* car_perst_rst_src_n_mask */ S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7)); + wmb(); /* order is important here */ W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */ W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */ + wmb(); /* order is important here */ W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F); W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000170); W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00); + wmb(); /* order is important here */ W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); + wmb(); /* order is important here */ W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080); + if (rev_id == 1) { + W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080); + } else { + W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8)); + W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); + } W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); + wmb(); /* order is important here */ + + /* wait until device ready */ + do { + msleep(1); + hw_state = R(RGF_USER_HW_MACHINE_STATE); + if (delay++ > 100) { + wil_err(wil, "Reset not completed, hw_state 0x%08x\n", + hw_state); + return; + } + } while (hw_state != HW_MACHINE_BOOT_DONE); + + if (rev_id == 2) + W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8)); + + C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); + wmb(); /* order is important here */ - wil_dbg_misc(wil, "Reset completed\n"); + wil_dbg_misc(wil, "Reset completed in %d ms\n", delay); +#undef R #undef W #undef S +#undef C } void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) @@ -234,11 +378,24 @@ int wil_reset(struct wil6210_priv *wil) { int rc; + WARN_ON(!mutex_is_locked(&wil->mutex)); + cancel_work_sync(&wil->disconnect_worker); wil6210_disconnect(wil, NULL); + wil->status = 0; /* prevent NAPI from being scheduled */ + if (test_bit(wil_status_napi_en, &wil->status)) { + napi_synchronize(&wil->napi_rx); + } + + if (wil->scan_request) { + wil_dbg_misc(wil, "Abort scan_request 0x%p\n", + wil->scan_request); + cfg80211_scan_done(wil->scan_request, true); + wil->scan_request = NULL; + } + wil6210_disable_irq(wil); - wil->status = 0; wmi_event_flush(wil); @@ -248,6 +405,8 @@ int wil_reset(struct wil6210_priv *wil) /* TODO: put MAC in reset */ wil_target_reset(wil); + wil_rx_fini(wil); + /* init after reset */ wil->pending_connect_cid = -1; reinit_completion(&wil->wmi_ready); @@ -261,6 +420,11 @@ int wil_reset(struct wil6210_priv *wil) return rc; } +void wil_fw_error_recovery(struct wil6210_priv *wil) +{ + wil_dbg_misc(wil, "starting fw error recovery\n"); + schedule_work(&wil->fw_error_worker); +} void wil_link_on(struct wil6210_priv *wil) { @@ -288,6 +452,8 @@ static int __wil_up(struct wil6210_priv *wil) struct wireless_dev *wdev = wil->wdev; int rc; + WARN_ON(!mutex_is_locked(&wil->mutex)); + rc = wil_reset(wil); if (rc) return rc; @@ -329,6 +495,7 @@ static int __wil_up(struct wil6210_priv *wil) napi_enable(&wil->napi_rx); napi_enable(&wil->napi_tx); + set_bit(wil_status_napi_en, &wil->status); return 0; } @@ -346,6 +513,9 @@ int wil_up(struct wil6210_priv *wil) static int __wil_down(struct wil6210_priv *wil) { + WARN_ON(!mutex_is_locked(&wil->mutex)); + + clear_bit(wil_status_napi_en, &wil->status); napi_disable(&wil->napi_rx); napi_disable(&wil->napi_tx); @@ -370,3 +540,19 @@ int wil_down(struct wil6210_priv *wil) return rc; } + +int wil_find_cid(struct wil6210_priv *wil, const u8 *mac) +{ + int i; + int rc = -ENOENT; + + for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { + if ((wil->sta[i].status != wil_sta_unused) && + ether_addr_equal(wil->sta[i].addr, mac)) { + rc = i; + break; + } + } + + return rc; +} diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 717178f09aa8..fdcaeb820e75 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -127,8 +127,9 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) ndev->netdev_ops = &wil_netdev_ops; ndev->ieee80211_ptr = wdev; - ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM; - ndev->features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM; + ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM | + NETIF_F_SG | NETIF_F_GRO; + ndev->features |= ndev->hw_features; SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); wdev->netdev = ndev; diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index eeceab39cda2..f1e1bb338d68 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -41,39 +41,41 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) switch (use_msi) { case 3: case 1: + wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi); + break; case 0: + wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n"); break; default: - wil_err(wil, "Invalid use_msi=%d, default to 1\n", - use_msi); + wil_err(wil, "Invalid use_msi=%d, default to 1\n", use_msi); use_msi = 1; } - wil->n_msi = use_msi; - if (wil->n_msi) { - wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi); - rc = pci_enable_msi_block(pdev, wil->n_msi); - if (rc && (wil->n_msi == 3)) { - wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); - wil->n_msi = 1; - rc = pci_enable_msi_block(pdev, wil->n_msi); - } - if (rc) { - wil_err(wil, "pci_enable_msi failed, use INTx\n"); - wil->n_msi = 0; - } - } else { - wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n"); + + if (use_msi == 3 && pci_enable_msi_range(pdev, 3, 3) < 0) { + wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); + use_msi = 1; + } + + if (use_msi == 1 && pci_enable_msi(pdev)) { + wil_err(wil, "pci_enable_msi failed, use INTx\n"); + use_msi = 0; } + wil->n_msi = use_msi; + rc = wil6210_init_irq(wil, pdev->irq); if (rc) goto stop_master; /* need reset here to obtain MAC */ + mutex_lock(&wil->mutex); rc = wil_reset(wil); + mutex_unlock(&wil->mutex); if (rc) goto release_irq; + wil_info(wil, "HW version: 0x%08x\n", wil->hw_version); + return 0; release_irq: @@ -151,6 +153,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_drvdata(pdev, wil); wil->pdev = pdev; + wil6210_clear_irq(wil); /* FW should raise IRQ when ready */ rc = wil_if_pcie_enable(wil); if (rc) { diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c new file mode 100644 index 000000000000..d04629fe053f --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -0,0 +1,177 @@ +#include "wil6210.h" +#include "txrx.h" + +#define SEQ_MODULO 0x1000 +#define SEQ_MASK 0xfff + +static inline int seq_less(u16 sq1, u16 sq2) +{ + return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1); +} + +static inline u16 seq_inc(u16 sq) +{ + return (sq + 1) & SEQ_MASK; +} + +static inline u16 seq_sub(u16 sq1, u16 sq2) +{ + return (sq1 - sq2) & SEQ_MASK; +} + +static inline int reorder_index(struct wil_tid_ampdu_rx *r, u16 seq) +{ + return seq_sub(seq, r->ssn) % r->buf_size; +} + +static void wil_release_reorder_frame(struct wil6210_priv *wil, + struct wil_tid_ampdu_rx *r, + int index) +{ + struct net_device *ndev = wil_to_ndev(wil); + struct sk_buff *skb = r->reorder_buf[index]; + + if (!skb) + goto no_frame; + + /* release the frame from the reorder ring buffer */ + r->stored_mpdu_num--; + r->reorder_buf[index] = NULL; + wil_netif_rx_any(skb, ndev); + +no_frame: + r->head_seq_num = seq_inc(r->head_seq_num); +} + +static void wil_release_reorder_frames(struct wil6210_priv *wil, + struct wil_tid_ampdu_rx *r, + u16 hseq) +{ + int index; + + while (seq_less(r->head_seq_num, hseq)) { + index = reorder_index(r, r->head_seq_num); + wil_release_reorder_frame(wil, r, index); + } +} + +static void wil_reorder_release(struct wil6210_priv *wil, + struct wil_tid_ampdu_rx *r) +{ + int index = reorder_index(r, r->head_seq_num); + + while (r->reorder_buf[index]) { + wil_release_reorder_frame(wil, r, index); + index = reorder_index(r, r->head_seq_num); + } +} + +void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) +{ + struct net_device *ndev = wil_to_ndev(wil); + struct vring_rx_desc *d = wil_skb_rxdesc(skb); + int tid = wil_rxdesc_tid(d); + int cid = wil_rxdesc_cid(d); + int mid = wil_rxdesc_mid(d); + u16 seq = wil_rxdesc_seq(d); + struct wil_sta_info *sta = &wil->sta[cid]; + struct wil_tid_ampdu_rx *r = sta->tid_rx[tid]; + u16 hseq; + int index; + + wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x\n", + mid, cid, tid, seq); + + if (!r) { + wil_netif_rx_any(skb, ndev); + return; + } + + hseq = r->head_seq_num; + + spin_lock(&r->reorder_lock); + + /* frame with out of date sequence number */ + if (seq_less(seq, r->head_seq_num)) { + dev_kfree_skb(skb); + goto out; + } + + /* + * If frame the sequence number exceeds our buffering window + * size release some previous frames to make room for this one. + */ + if (!seq_less(seq, r->head_seq_num + r->buf_size)) { + hseq = seq_inc(seq_sub(seq, r->buf_size)); + /* release stored frames up to new head to stack */ + wil_release_reorder_frames(wil, r, hseq); + } + + /* Now the new frame is always in the range of the reordering buffer */ + + index = reorder_index(r, seq); + + /* check if we already stored this frame */ + if (r->reorder_buf[index]) { + dev_kfree_skb(skb); + goto out; + } + + /* + * If the current MPDU is in the right order and nothing else + * is stored we can process it directly, no need to buffer it. + * If it is first but there's something stored, we may be able + * to release frames after this one. + */ + if (seq == r->head_seq_num && r->stored_mpdu_num == 0) { + r->head_seq_num = seq_inc(r->head_seq_num); + wil_netif_rx_any(skb, ndev); + goto out; + } + + /* put the frame in the reordering buffer */ + r->reorder_buf[index] = skb; + r->reorder_time[index] = jiffies; + r->stored_mpdu_num++; + wil_reorder_release(wil, r); + +out: + spin_unlock(&r->reorder_lock); +} + +struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, + int size, u16 ssn) +{ + struct wil_tid_ampdu_rx *r = kzalloc(sizeof(*r), GFP_KERNEL); + if (!r) + return NULL; + + r->reorder_buf = + kcalloc(size, sizeof(struct sk_buff *), GFP_KERNEL); + r->reorder_time = + kcalloc(size, sizeof(unsigned long), GFP_KERNEL); + if (!r->reorder_buf || !r->reorder_time) { + kfree(r->reorder_buf); + kfree(r->reorder_time); + kfree(r); + return NULL; + } + + spin_lock_init(&r->reorder_lock); + r->ssn = ssn; + r->head_seq_num = ssn; + r->buf_size = size; + r->stored_mpdu_num = 0; + return r; +} + +void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, + struct wil_tid_ampdu_rx *r) +{ + if (!r) + return; + wil_release_reorder_frames(wil, r, r->head_seq_num + r->buf_size); + kfree(r->reorder_buf); + kfree(r->reorder_time); + kfree(r); +} diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 0b0975d88b43..c8c547457eb4 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -104,6 +104,23 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring) return 0; } +static void wil_txdesc_unmap(struct device *dev, struct vring_tx_desc *d, + struct wil_ctx *ctx) +{ + dma_addr_t pa = wil_desc_addr(&d->dma.addr); + u16 dmalen = le16_to_cpu(d->dma.length); + switch (ctx->mapped_as) { + case wil_mapped_as_single: + dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE); + break; + case wil_mapped_as_page: + dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE); + break; + default: + break; + } +} + static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring, int tx) { @@ -122,15 +139,7 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring, ctx = &vring->ctx[vring->swtail]; *d = *_d; - pa = wil_desc_addr(&d->dma.addr); - dmalen = le16_to_cpu(d->dma.length); - if (vring->ctx[vring->swtail].mapped_as_page) { - dma_unmap_page(dev, pa, dmalen, - DMA_TO_DEVICE); - } else { - dma_unmap_single(dev, pa, dmalen, - DMA_TO_DEVICE); - } + wil_txdesc_unmap(dev, d, ctx); if (ctx->skb) dev_kfree_skb_any(ctx->skb); vring->swtail = wil_vring_next_tail(vring); @@ -344,6 +353,9 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, u16 dmalen; u8 ftype; u8 ds_bits; + int cid; + struct wil_net_stats *stats; + BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb)); @@ -383,8 +395,10 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb_headlen(skb), false); - - wil->stats.last_mcs_rx = wil_rxdesc_mcs(d); + cid = wil_rxdesc_cid(d); + stats = &wil->sta[cid].stats; + stats->last_mcs_rx = wil_rxdesc_mcs(d); + wil->stats.last_mcs_rx = stats->last_mcs_rx; /* use radiotap header only if required */ if (ndev->type == ARPHRD_IEEE80211_RADIOTAP) @@ -472,21 +486,28 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count) * Pass Rx packet to the netif. Update statistics. * Called in softirq context (NAPI poll). */ -static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) +void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) { - int rc; + gro_result_t rc; + struct wil6210_priv *wil = ndev_to_wil(ndev); unsigned int len = skb->len; + struct vring_rx_desc *d = wil_skb_rxdesc(skb); + int cid = wil_rxdesc_cid(d); + struct wil_net_stats *stats = &wil->sta[cid].stats; skb_orphan(skb); - rc = netif_receive_skb(skb); + rc = napi_gro_receive(&wil->napi_rx, skb); - if (likely(rc == NET_RX_SUCCESS)) { + if (unlikely(rc == GRO_DROP)) { + ndev->stats.rx_dropped++; + stats->rx_dropped++; + wil_dbg_txrx(wil, "Rx drop %d bytes\n", len); + } else { ndev->stats.rx_packets++; + stats->rx_packets++; ndev->stats.rx_bytes += len; - - } else { - ndev->stats.rx_dropped++; + stats->rx_bytes += len; } } @@ -515,12 +536,18 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota) skb->ip_summed = CHECKSUM_UNNECESSARY; skb->pkt_type = PACKET_OTHERHOST; skb->protocol = htons(ETH_P_802_2); - + wil_netif_rx_any(skb, ndev); } else { + struct ethhdr *eth = (void *)skb->data; + skb->protocol = eth_type_trans(skb, ndev); + + if (is_unicast_ether_addr(eth->h_dest)) + wil_rx_reorder(wil, skb); + else + wil_netif_rx_any(skb, ndev); } - wil_netif_rx_any(skb, ndev); } wil_rx_refill(wil, v->size); } @@ -530,6 +557,11 @@ int wil_rx_init(struct wil6210_priv *wil) struct vring *vring = &wil->vring_rx; int rc; + if (vring->va) { + wil_err(wil, "Rx ring already allocated\n"); + return -EINVAL; + } + vring->size = WIL6210_RX_RING_SIZE; rc = wil_vring_alloc(wil, vring); if (rc) @@ -570,7 +602,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, .ring_size = cpu_to_le16(size), }, .ringid = id, - .cidxtid = (cid & 0xf) | ((tid & 0xf) << 4), + .cidxtid = mk_cidxtid(cid, tid), .encap_trans_type = WMI_VRING_ENC_TYPE_802_3, .mac_ctrl = 0, .to_resolution = 0, @@ -586,6 +618,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, struct wmi_vring_cfg_done_event cmd; } __packed reply; struct vring *vring = &wil->vring_tx[id]; + struct vring_tx_data *txdata = &wil->vring_tx_data[id]; if (vring->va) { wil_err(wil, "Tx ring [%d] already allocated\n", id); @@ -593,11 +626,15 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, goto out; } + memset(txdata, 0, sizeof(*txdata)); vring->size = size; rc = wil_vring_alloc(wil, vring); if (rc) goto out; + wil->vring2cid_tid[id][0] = cid; + wil->vring2cid_tid[id][1] = tid; + cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa); rc = wmi_call(wil, WMI_VRING_CFG_CMDID, &cmd, sizeof(cmd), @@ -613,6 +650,8 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, } vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); + txdata->enabled = 1; + return 0; out_free: wil_vring_free(wil, vring, 1); @@ -625,23 +664,116 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id) { struct vring *vring = &wil->vring_tx[id]; + WARN_ON(!mutex_is_locked(&wil->mutex)); + if (!vring->va) return; + /* make sure NAPI won't touch this vring */ + wil->vring_tx_data[id].enabled = 0; + if (test_bit(wil_status_napi_en, &wil->status)) + napi_synchronize(&wil->napi_tx); + wil_vring_free(wil, vring, 1); } static struct vring *wil_find_tx_vring(struct wil6210_priv *wil, struct sk_buff *skb) { - struct vring *v = &wil->vring_tx[0]; + int i; + struct ethhdr *eth = (void *)skb->data; + int cid = wil_find_cid(wil, eth->h_dest); + + if (cid < 0) + return NULL; - if (v->va) - return v; + if (!wil->sta[cid].data_port_open && + (skb->protocol != cpu_to_be16(ETH_P_PAE))) + return NULL; + + /* TODO: fix for multiple TID */ + for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) { + if (wil->vring2cid_tid[i][0] == cid) { + struct vring *v = &wil->vring_tx[i]; + wil_dbg_txrx(wil, "%s(%pM) -> [%d]\n", + __func__, eth->h_dest, i); + if (v->va) { + return v; + } else { + wil_dbg_txrx(wil, "vring[%d] not valid\n", i); + return NULL; + } + } + } return NULL; } +static void wil_set_da_for_vring(struct wil6210_priv *wil, + struct sk_buff *skb, int vring_index) +{ + struct ethhdr *eth = (void *)skb->data; + int cid = wil->vring2cid_tid[vring_index][0]; + memcpy(eth->h_dest, wil->sta[cid].addr, ETH_ALEN); +} + +static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, + struct sk_buff *skb); +/* + * Find 1-st vring and return it; set dest address for this vring in skb + * duplicate skb and send it to other active vrings + */ +static struct vring *wil_tx_bcast(struct wil6210_priv *wil, + struct sk_buff *skb) +{ + struct vring *v, *v2; + struct sk_buff *skb2; + int i; + u8 cid; + + /* find 1-st vring eligible for data */ + for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { + v = &wil->vring_tx[i]; + if (!v->va) + continue; + + cid = wil->vring2cid_tid[i][0]; + if (!wil->sta[cid].data_port_open) + continue; + + goto found; + } + + wil_err(wil, "Tx while no vrings active?\n"); + + return NULL; + +found: + wil_dbg_txrx(wil, "BCAST -> ring %d\n", i); + wil_set_da_for_vring(wil, skb, i); + + /* find other active vrings and duplicate skb for each */ + for (i++; i < WIL6210_MAX_TX_RINGS; i++) { + v2 = &wil->vring_tx[i]; + if (!v2->va) + continue; + cid = wil->vring2cid_tid[i][0]; + if (!wil->sta[cid].data_port_open) + continue; + + skb2 = skb_copy(skb, GFP_ATOMIC); + if (skb2) { + wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i); + wil_set_da_for_vring(wil, skb2, i); + wil_tx_vring(wil, v2, skb2); + } else { + wil_err(wil, "skb_copy failed\n"); + } + } + + return v; +} + static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len, int vring_index) { @@ -667,6 +799,13 @@ static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len, return 0; } +static inline +void wil_tx_desc_set_nr_frags(struct vring_tx_desc *d, int nr_frags) +{ + d->mac.d[2] |= ((nr_frags + 1) << + MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS); +} + static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil, struct vring_tx_desc *d, struct sk_buff *skb) @@ -731,8 +870,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, wil_dbg_txrx(wil, "%s()\n", __func__); - if (avail < vring->size/8) - netif_tx_stop_all_queues(wil_to_ndev(wil)); if (avail < 1 + nr_frags) { wil_err(wil, "Tx ring full. No space for %d fragments\n", 1 + nr_frags); @@ -740,9 +877,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, } _d = &(vring->va[i].tx); - /* FIXME FW can accept only unicast frames for the peer */ - memcpy(skb->data, wil->dst_addr[vring_index], ETH_ALEN); - pa = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); @@ -753,6 +887,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, if (unlikely(dma_mapping_error(dev, pa))) return -EINVAL; + vring->ctx[i].mapped_as = wil_mapped_as_single; /* 1-st segment */ wil_tx_desc_map(d, pa, skb_headlen(skb), vring_index); /* Process TCP/UDP checksum offloading */ @@ -762,8 +897,8 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, goto dma_error; } - d->mac.d[2] |= ((nr_frags + 1) << - MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS); + vring->ctx[i].nr_frags = nr_frags; + wil_tx_desc_set_nr_frags(d, nr_frags); if (nr_frags) *_d = *d; @@ -778,8 +913,13 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(dev, pa))) goto dma_error; + vring->ctx[i].mapped_as = wil_mapped_as_page; wil_tx_desc_map(d, pa, len, vring_index); - vring->ctx[i].mapped_as_page = 1; + /* no need to check return code - + * if it succeeded for 1-st descriptor, + * it will succeed here too + */ + wil_tx_desc_offload_cksum_set(wil, d, skb); *_d = *d; } /* for the last seg only */ @@ -808,7 +948,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, /* unmap what we have mapped */ nr_frags = f + 1; /* frags mapped + one for skb head */ for (f = 0; f < nr_frags; f++) { - u16 dmalen; struct wil_ctx *ctx; i = (swhead + f) % vring->size; @@ -816,12 +955,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, _d = &(vring->va[i].tx); *d = *_d; _d->dma.status = TX_DMA_STATUS_DU; - pa = wil_desc_addr(&d->dma.addr); - dmalen = le16_to_cpu(d->dma.length); - if (ctx->mapped_as_page) - dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE); - else - dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE); + wil_txdesc_unmap(dev, d, ctx); if (ctx->skb) dev_kfree_skb_any(ctx->skb); @@ -836,12 +970,17 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct wil6210_priv *wil = ndev_to_wil(ndev); + struct ethhdr *eth = (void *)skb->data; struct vring *vring; + static bool pr_once_fw; int rc; wil_dbg_txrx(wil, "%s()\n", __func__); if (!test_bit(wil_status_fwready, &wil->status)) { - wil_err(wil, "FW not ready\n"); + if (!pr_once_fw) { + wil_err(wil, "FW not ready\n"); + pr_once_fw = true; + } goto drop; } if (!test_bit(wil_status_fwconnected, &wil->status)) { @@ -852,16 +991,25 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) wil_err(wil, "Xmit in monitor mode not supported\n"); goto drop; } + pr_once_fw = false; /* find vring */ - vring = wil_find_tx_vring(wil, skb); + if (is_unicast_ether_addr(eth->h_dest)) { + vring = wil_find_tx_vring(wil, skb); + } else { + vring = wil_tx_bcast(wil, skb); + } if (!vring) { - wil_err(wil, "No Tx VRING available\n"); + wil_err(wil, "No Tx VRING found for %pM\n", eth->h_dest); goto drop; } /* set up vring entry */ rc = wil_tx_vring(wil, vring, skb); + /* do we still have enough room in the vring? */ + if (wil_vring_avail_tx(vring) < vring->size/8) + netif_tx_stop_all_queues(wil_to_ndev(wil)); + switch (rc) { case 0: /* statistics will be updated on the tx_complete */ @@ -891,64 +1039,82 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) struct net_device *ndev = wil_to_ndev(wil); struct device *dev = wil_to_dev(wil); struct vring *vring = &wil->vring_tx[ringid]; + struct vring_tx_data *txdata = &wil->vring_tx_data[ringid]; int done = 0; + int cid = wil->vring2cid_tid[ringid][0]; + struct wil_net_stats *stats = &wil->sta[cid].stats; + volatile struct vring_tx_desc *_d; if (!vring->va) { wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid); return 0; } + if (!txdata->enabled) { + wil_info(wil, "Tx irq[%d]: vring disabled\n", ringid); + return 0; + } + wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid); while (!wil_vring_is_empty(vring)) { - volatile struct vring_tx_desc *_d = - &vring->va[vring->swtail].tx; - struct vring_tx_desc dd, *d = ⅆ - dma_addr_t pa; - u16 dmalen; + int new_swtail; struct wil_ctx *ctx = &vring->ctx[vring->swtail]; - struct sk_buff *skb = ctx->skb; - - *d = *_d; + /** + * For the fragmented skb, HW will set DU bit only for the + * last fragment. look for it + */ + int lf = (vring->swtail + ctx->nr_frags) % vring->size; + /* TODO: check we are not past head */ - if (!(d->dma.status & TX_DMA_STATUS_DU)) + _d = &vring->va[lf].tx; + if (!(_d->dma.status & TX_DMA_STATUS_DU)) break; - dmalen = le16_to_cpu(d->dma.length); - trace_wil6210_tx_done(ringid, vring->swtail, dmalen, - d->dma.error); - wil_dbg_txrx(wil, - "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", - vring->swtail, dmalen, d->dma.status, - d->dma.error); - wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4, - (const void *)d, sizeof(*d), false); - - pa = wil_desc_addr(&d->dma.addr); - if (ctx->mapped_as_page) - dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE); - else - dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE); - - if (skb) { - if (d->dma.error == 0) { - ndev->stats.tx_packets++; - ndev->stats.tx_bytes += skb->len; - } else { - ndev->stats.tx_errors++; - } + new_swtail = (lf + 1) % vring->size; + while (vring->swtail != new_swtail) { + struct vring_tx_desc dd, *d = ⅆ + u16 dmalen; + struct wil_ctx *ctx = &vring->ctx[vring->swtail]; + struct sk_buff *skb = ctx->skb; + _d = &vring->va[vring->swtail].tx; + + *d = *_d; + + dmalen = le16_to_cpu(d->dma.length); + trace_wil6210_tx_done(ringid, vring->swtail, dmalen, + d->dma.error); + wil_dbg_txrx(wil, + "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", + vring->swtail, dmalen, d->dma.status, + d->dma.error); + wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4, + (const void *)d, sizeof(*d), false); + + wil_txdesc_unmap(dev, d, ctx); + + if (skb) { + if (d->dma.error == 0) { + ndev->stats.tx_packets++; + stats->tx_packets++; + ndev->stats.tx_bytes += skb->len; + stats->tx_bytes += skb->len; + } else { + ndev->stats.tx_errors++; + stats->tx_errors++; + } - dev_kfree_skb_any(skb); + dev_kfree_skb_any(skb); + } + memset(ctx, 0, sizeof(*ctx)); + /* There is no need to touch HW descriptor: + * - ststus bit TX_DMA_STATUS_DU is set by design, + * so hardware will not try to process this desc., + * - rest of descriptor will be initialized on Tx. + */ + vring->swtail = wil_vring_next_tail(vring); + done++; } - memset(ctx, 0, sizeof(*ctx)); - /* - * There is no need to touch HW descriptor: - * - ststus bit TX_DMA_STATUS_DU is set by design, - * so hardware will not try to process this desc., - * - rest of descriptor will be initialized on Tx. - */ - vring->swtail = wil_vring_next_tail(vring); - done++; } if (wil_vring_avail_tx(vring) > vring->size/4) netif_tx_wake_all_queues(wil_to_ndev(wil)); diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index b3828279204c..bc5706a4f007 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -436,4 +436,11 @@ static inline struct vring_rx_desc *wil_skb_rxdesc(struct sk_buff *skb) return (void *)skb->cb; } +void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev); +void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb); +struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, + int size, u16 ssn); +void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, + struct wil_tid_ampdu_rx *r); + #endif /* WIL6210_TXRX_H */ diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 1f91eaf95bbe..2a2dec75f026 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -74,23 +74,21 @@ struct RGF_ICR { } __packed; /* registers - FW addresses */ -#define RGF_USER_USER_SCRATCH_PAD (0x8802bc) -#define RGF_USER_USER_ICR (0x880b4c) /* struct RGF_ICR */ - #define BIT_USER_USER_ICR_SW_INT_2 BIT(18) -#define RGF_USER_CLKS_CTL_SW_RST_MASK_0 (0x880b14) -#define RGF_USER_MAC_CPU_0 (0x8801fc) +#define RGF_USER_HW_MACHINE_STATE (0x8801dc) + #define HW_MACHINE_BOOT_DONE (0x3fffffd) #define RGF_USER_USER_CPU_0 (0x8801e0) +#define RGF_USER_MAC_CPU_0 (0x8801fc) +#define RGF_USER_USER_SCRATCH_PAD (0x8802bc) +#define RGF_USER_FW_REV_ID (0x880a8c) /* chip revision */ +#define RGF_USER_CLKS_CTL_0 (0x880abc) + #define BIT_USER_CLKS_RST_PWGD BIT(11) /* reset on "power good" */ #define RGF_USER_CLKS_CTL_SW_RST_VEC_0 (0x880b04) #define RGF_USER_CLKS_CTL_SW_RST_VEC_1 (0x880b08) #define RGF_USER_CLKS_CTL_SW_RST_VEC_2 (0x880b0c) #define RGF_USER_CLKS_CTL_SW_RST_VEC_3 (0x880b10) - -#define RGF_DMA_PSEUDO_CAUSE (0x881c68) -#define RGF_DMA_PSEUDO_CAUSE_MASK_SW (0x881c6c) -#define RGF_DMA_PSEUDO_CAUSE_MASK_FW (0x881c70) - #define BIT_DMA_PSEUDO_CAUSE_RX BIT(0) - #define BIT_DMA_PSEUDO_CAUSE_TX BIT(1) - #define BIT_DMA_PSEUDO_CAUSE_MISC BIT(2) +#define RGF_USER_CLKS_CTL_SW_RST_MASK_0 (0x880b14) +#define RGF_USER_USER_ICR (0x880b4c) /* struct RGF_ICR */ + #define BIT_USER_USER_ICR_SW_INT_2 BIT(18) #define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */ #define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0) @@ -105,13 +103,22 @@ struct RGF_ICR { /* Interrupt moderation control */ #define RGF_DMA_ITR_CNT_TRSH (0x881c5c) #define RGF_DMA_ITR_CNT_DATA (0x881c60) -#define RGF_DMA_ITR_CNT_CRL (0x881C64) +#define RGF_DMA_ITR_CNT_CRL (0x881c64) #define BIT_DMA_ITR_CNT_CRL_EN BIT(0) #define BIT_DMA_ITR_CNT_CRL_EXT_TICK BIT(1) #define BIT_DMA_ITR_CNT_CRL_FOREVER BIT(2) #define BIT_DMA_ITR_CNT_CRL_CLR BIT(3) #define BIT_DMA_ITR_CNT_CRL_REACH_TRSH BIT(4) +#define RGF_DMA_PSEUDO_CAUSE (0x881c68) +#define RGF_DMA_PSEUDO_CAUSE_MASK_SW (0x881c6c) +#define RGF_DMA_PSEUDO_CAUSE_MASK_FW (0x881c70) + #define BIT_DMA_PSEUDO_CAUSE_RX BIT(0) + #define BIT_DMA_PSEUDO_CAUSE_TX BIT(1) + #define BIT_DMA_PSEUDO_CAUSE_MISC BIT(2) + +#define RGF_PCIE_LOS_COUNTER_CTL (0x882dc4) + /* popular locations */ #define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD) #define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \ @@ -125,6 +132,31 @@ struct RGF_ICR { /* Hardware definitions end */ +/** + * mk_cidxtid - construct @cidxtid field + * @cid: CID value + * @tid: TID value + * + * @cidxtid field encoded as bits 0..3 - CID; 4..7 - TID + */ +static inline u8 mk_cidxtid(u8 cid, u8 tid) +{ + return ((tid & 0xf) << 4) | (cid & 0xf); +} + +/** + * parse_cidxtid - parse @cidxtid field + * @cid: store CID value here + * @tid: store TID value here + * + * @cidxtid field encoded as bits 0..3 - CID; 4..7 - TID + */ +static inline void parse_cidxtid(u8 cidxtid, u8 *cid, u8 *tid) +{ + *cid = cidxtid & 0xf; + *tid = (cidxtid >> 4) & 0xf; +} + struct wil6210_mbox_ring { u32 base; u16 entry_size; /* max. size of mbox entry, incl. all headers */ @@ -184,12 +216,19 @@ struct pending_wmi_event { } __packed event; }; +enum { /* for wil_ctx.mapped_as */ + wil_mapped_as_none = 0, + wil_mapped_as_single = 1, + wil_mapped_as_page = 2, +}; + /** * struct wil_ctx - software context for Vring descriptor */ struct wil_ctx { struct sk_buff *skb; - u8 mapped_as_page:1; + u8 nr_frags; + u8 mapped_as; }; union vring_desc; @@ -204,6 +243,14 @@ struct vring { struct wil_ctx *ctx; /* ctx[size] - software context */ }; +/** + * Additional data for Tx Vring + */ +struct vring_tx_data { + int enabled; + +}; + enum { /* for wil6210_priv.status */ wil_status_fwready = 0, wil_status_fwconnecting, @@ -211,10 +258,51 @@ enum { /* for wil6210_priv.status */ wil_status_dontscan, wil_status_reset_done, wil_status_irqen, /* FIXME: interrupts enabled - for debug */ + wil_status_napi_en, /* NAPI enabled protected by wil->mutex */ }; struct pci_dev; +/** + * struct tid_ampdu_rx - TID aggregation information (Rx). + * + * @reorder_buf: buffer to reorder incoming aggregated MPDUs + * @reorder_time: jiffies when skb was added + * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) + * @reorder_timer: releases expired frames from the reorder buffer. + * @last_rx: jiffies of last rx activity + * @head_seq_num: head sequence number in reordering buffer. + * @stored_mpdu_num: number of MPDUs in reordering buffer + * @ssn: Starting Sequence Number expected to be aggregated. + * @buf_size: buffer size for incoming A-MPDUs + * @timeout: reset timer value (in TUs). + * @dialog_token: dialog token for aggregation session + * @rcu_head: RCU head used for freeing this struct + * @reorder_lock: serializes access to reorder buffer, see below. + * + * This structure's lifetime is managed by RCU, assignments to + * the array holding it must hold the aggregation mutex. + * + * The @reorder_lock is used to protect the members of this + * struct, except for @timeout, @buf_size and @dialog_token, + * which are constant across the lifetime of the struct (the + * dialog token being used only for debugging). + */ +struct wil_tid_ampdu_rx { + spinlock_t reorder_lock; /* see above */ + struct sk_buff **reorder_buf; + unsigned long *reorder_time; + struct timer_list session_timer; + struct timer_list reorder_timer; + unsigned long last_rx; + u16 head_seq_num; + u16 stored_mpdu_num; + u16 ssn; + u16 buf_size; + u16 timeout; + u8 dialog_token; +}; + struct wil6210_stats { u64 tsf; u32 snr; @@ -226,6 +314,43 @@ struct wil6210_stats { u16 peer_tx_sector; }; +enum wil_sta_status { + wil_sta_unused = 0, + wil_sta_conn_pending = 1, + wil_sta_connected = 2, +}; + +#define WIL_STA_TID_NUM (16) + +struct wil_net_stats { + unsigned long rx_packets; + unsigned long tx_packets; + unsigned long rx_bytes; + unsigned long tx_bytes; + unsigned long tx_errors; + unsigned long rx_dropped; + u16 last_mcs_rx; +}; + +/** + * struct wil_sta_info - data for peer + * + * Peer identified by its CID (connection ID) + * NIC performs beam forming for each peer; + * if no beam forming done, frame exchange is not + * possible. + */ +struct wil_sta_info { + u8 addr[ETH_ALEN]; + enum wil_sta_status status; + struct wil_net_stats stats; + bool data_port_open; /* can send any data, not only EAPOL */ + /* Rx BACK */ + struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM]; + unsigned long tid_rx_timer_expired[BITS_TO_LONGS(WIL_STA_TID_NUM)]; + unsigned long tid_rx_stop_requested[BITS_TO_LONGS(WIL_STA_TID_NUM)]; +}; + struct wil6210_priv { struct pci_dev *pdev; int n_msi; @@ -233,6 +358,7 @@ struct wil6210_priv { void __iomem *csr; ulong status; u32 fw_version; + u32 hw_version; u8 n_mids; /* number of additional MIDs as reported by FW */ /* profile */ u32 monitor_flags; @@ -253,6 +379,7 @@ struct wil6210_priv { struct workqueue_struct *wmi_wq_conn; /* for connect worker */ struct work_struct connect_worker; struct work_struct disconnect_worker; + struct work_struct fw_error_worker; /* for FW error recovery */ struct timer_list connect_timer; int pending_connect_cid; struct list_head pending_wmi_ev; @@ -267,7 +394,9 @@ struct wil6210_priv { /* DMA related */ struct vring vring_rx; struct vring vring_tx[WIL6210_MAX_TX_RINGS]; - u8 dst_addr[WIL6210_MAX_TX_RINGS][ETH_ALEN]; + struct vring_tx_data vring_tx_data[WIL6210_MAX_TX_RINGS]; + u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */ + struct wil_sta_info sta[WIL6210_MAX_CID]; /* scan */ struct cfg80211_scan_request *scan_request; @@ -329,11 +458,13 @@ void wil_if_remove(struct wil6210_priv *wil); int wil_priv_init(struct wil6210_priv *wil); void wil_priv_deinit(struct wil6210_priv *wil); int wil_reset(struct wil6210_priv *wil); +void wil_fw_error_recovery(struct wil6210_priv *wil); void wil_link_on(struct wil6210_priv *wil); void wil_link_off(struct wil6210_priv *wil); int wil_up(struct wil6210_priv *wil); int wil_down(struct wil6210_priv *wil); void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); +int wil_find_cid(struct wil6210_priv *wil, const u8 *mac); void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr); void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr); @@ -357,8 +488,11 @@ int wmi_echo(struct wil6210_priv *wil); int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie); int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring); int wmi_p2p_cfg(struct wil6210_priv *wil, int channel); +int wmi_rxon(struct wil6210_priv *wil, bool on); int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r); +int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason); +void wil6210_clear_irq(struct wil6210_priv *wil); int wil6210_init_irq(struct wil6210_priv *wil, int irq); void wil6210_fini_irq(struct wil6210_priv *wil, int irq); void wil6210_disable_irq(struct wil6210_priv *wil); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 063963ee422a..2ba56eef0c45 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -307,14 +307,14 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) u32 freq = ieee80211_channel_to_frequency(ch_no, IEEE80211_BAND_60GHZ); struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq); - /* TODO convert LE to CPU */ - s32 signal = 0; /* TODO */ + s32 signal = data->info.sqi; __le16 fc = rx_mgmt_frame->frame_control; u32 d_len = le32_to_cpu(data->info.len); u16 d_status = le16_to_cpu(data->info.status); - wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d\n", - data->info.channel, data->info.mcs, data->info.snr); + wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d SQI %d%%\n", + data->info.channel, data->info.mcs, data->info.snr, + data->info.sqi); wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len, le16_to_cpu(fc)); wil_dbg_wmi(wil, "qid %d mid %d cid %d\n", @@ -384,6 +384,11 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) evt->assoc_req_len, evt->assoc_resp_len); return; } + if (evt->cid >= WIL6210_MAX_CID) { + wil_err(wil, "Connect CID invalid : %d\n", evt->cid); + return; + } + ch = evt->channel + 1; wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n", evt->bssid, ch, evt->cid); @@ -439,7 +444,8 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) /* FIXME FW can transmit only ucast frames to peer */ /* FIXME real ring_id instead of hard coded 0 */ - memcpy(wil->dst_addr[0], evt->bssid, ETH_ALEN); + memcpy(wil->sta[evt->cid].addr, evt->bssid, ETH_ALEN); + wil->sta[evt->cid].status = wil_sta_conn_pending; wil->pending_connect_cid = evt->cid; queue_work(wil->wmi_wq_conn, &wil->connect_worker); @@ -456,7 +462,9 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, wil->sinfo_gen++; + mutex_lock(&wil->mutex); wil6210_disconnect(wil, evt->bssid); + mutex_unlock(&wil->mutex); } static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) @@ -476,11 +484,11 @@ static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector); wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector); wil_dbg_wmi(wil, "Link status, MCS %d TSF 0x%016llx\n" - "BF status 0x%08x SNR 0x%08x\n" + "BF status 0x%08x SNR 0x%08x SQI %d%%\n" "Tx Tpt %d goodput %d Rx goodput %d\n" "Sectors(rx:tx) my %d:%d peer %d:%d\n", wil->stats.bf_mcs, wil->stats.tsf, evt->status, - wil->stats.snr, le32_to_cpu(evt->tx_tpt), + wil->stats.snr, evt->sqi, le32_to_cpu(evt->tx_tpt), le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput), wil->stats.my_rx_sector, wil->stats.my_tx_sector, wil->stats.peer_rx_sector, wil->stats.peer_tx_sector); @@ -499,10 +507,16 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, int sz = eapol_len + ETH_HLEN; struct sk_buff *skb; struct ethhdr *eth; + int cid; + struct wil_net_stats *stats = NULL; wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len, evt->src_mac); + cid = wil_find_cid(wil, evt->src_mac); + if (cid >= 0) + stats = &wil->sta[cid].stats; + if (eapol_len > 196) { /* TODO: revisit size limit */ wil_err(wil, "EAPOL too large\n"); return; @@ -513,6 +527,7 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, wil_err(wil, "Failed to allocate skb\n"); return; } + eth = (struct ethhdr *)skb_put(skb, ETH_HLEN); memcpy(eth->h_dest, ndev->dev_addr, ETH_ALEN); memcpy(eth->h_source, evt->src_mac, ETH_ALEN); @@ -521,9 +536,15 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, skb->protocol = eth_type_trans(skb, ndev); if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) { ndev->stats.rx_packets++; - ndev->stats.rx_bytes += skb->len; + ndev->stats.rx_bytes += sz; + if (stats) { + stats->rx_packets++; + stats->rx_bytes += sz; + } } else { ndev->stats.rx_dropped++; + if (stats) + stats->rx_dropped++; } } @@ -531,9 +552,16 @@ static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len) { struct net_device *ndev = wil_to_ndev(wil); struct wmi_data_port_open_event *evt = d; + u8 cid = evt->cid; - wil_dbg_wmi(wil, "Link UP for CID %d\n", evt->cid); + wil_dbg_wmi(wil, "Link UP for CID %d\n", cid); + if (cid >= ARRAY_SIZE(wil->sta)) { + wil_err(wil, "Link UP for invalid CID %d\n", cid); + return; + } + + wil->sta[cid].data_port_open = true; netif_carrier_on(ndev); } @@ -541,10 +569,17 @@ static void wmi_evt_linkdown(struct wil6210_priv *wil, int id, void *d, int len) { struct net_device *ndev = wil_to_ndev(wil); struct wmi_wbe_link_down_event *evt = d; + u8 cid = evt->cid; wil_dbg_wmi(wil, "Link DOWN for CID %d, reason %d\n", - evt->cid, le32_to_cpu(evt->reason)); + cid, le32_to_cpu(evt->reason)); + + if (cid >= ARRAY_SIZE(wil->sta)) { + wil_err(wil, "Link DOWN for invalid CID %d\n", cid); + return; + } + wil->sta[cid].data_port_open = false; netif_carrier_off(ndev); } @@ -552,10 +587,42 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d, int len) { struct wmi_vring_ba_status_event *evt = d; + struct wil_sta_info *sta; + uint i, cid; + + /* TODO: use Rx BA status, not Tx one */ wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n", - evt->ringid, evt->status ? "N/A" : "OK", evt->agg_wsize, - __le16_to_cpu(evt->ba_timeout)); + evt->ringid, + evt->status == WMI_BA_AGREED ? "OK" : "N/A", + evt->agg_wsize, __le16_to_cpu(evt->ba_timeout)); + + if (evt->ringid >= WIL6210_MAX_TX_RINGS) { + wil_err(wil, "invalid ring id %d\n", evt->ringid); + return; + } + + cid = wil->vring2cid_tid[evt->ringid][0]; + if (cid >= WIL6210_MAX_CID) { + wil_err(wil, "invalid CID %d for vring %d\n", cid, evt->ringid); + return; + } + + sta = &wil->sta[cid]; + if (sta->status == wil_sta_unused) { + wil_err(wil, "CID %d unused\n", cid); + return; + } + + wil_dbg_wmi(wil, "BACK for CID %d %pM\n", cid, sta->addr); + for (i = 0; i < WIL_STA_TID_NUM; i++) { + struct wil_tid_ampdu_rx *r = sta->tid_rx[i]; + sta->tid_rx[i] = NULL; + wil_tid_ampdu_rx_free(wil, r); + if ((evt->status == WMI_BA_AGREED) && evt->agg_wsize) + sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil, + evt->agg_wsize, 0); + } } static const struct { @@ -893,6 +960,38 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) return rc; } +/** + * wmi_rxon - turn radio on/off + * @on: turn on if true, off otherwise + * + * Only switch radio. Channel should be set separately. + * No timeout for rxon - radio turned on forever unless some other call + * turns it off + */ +int wmi_rxon(struct wil6210_priv *wil, bool on) +{ + int rc; + struct { + struct wil6210_mbox_hdr_wmi wmi; + struct wmi_listen_started_event evt; + } __packed reply; + + wil_info(wil, "%s(%s)\n", __func__, on ? "on" : "off"); + + if (on) { + rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0, + WMI_LISTEN_STARTED_EVENTID, + &reply, sizeof(reply), 100); + if ((rc == 0) && (reply.evt.status != WMI_FW_STATUS_SUCCESS)) + rc = -EINVAL; + } else { + rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0, + WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 20); + } + + return rc; +} + int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) { struct wireless_dev *wdev = wil->wdev; @@ -906,6 +1005,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) }, .mid = 0, /* TODO - what is it? */ .decap_trans_type = WMI_DECAP_TYPE_802_3, + .reorder_type = WMI_RX_SW_REORDER, }; struct { struct wil6210_mbox_hdr_wmi wmi; @@ -973,6 +1073,18 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r) return 0; } +int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason) +{ + struct wmi_disconnect_sta_cmd cmd = { + .disconnect_reason = cpu_to_le16(reason), + }; + memcpy(cmd.dst_mac, mac, ETH_ALEN); + + wil_dbg_wmi(wil, "%s(%pM, reason %d)\n", __func__, mac, reason); + + return wmi_send(wil, WMI_DISCONNECT_STA_CMDID, &cmd, sizeof(cmd)); +} + void wmi_event_flush(struct wil6210_priv *wil) { struct pending_wmi_event *evt, *t; |