From 26ebbccfb73f59edd67a41b18706f36f1b1edae1 Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Tue, 25 Feb 2014 09:29:54 +0200 Subject: ath10k: implement drv_get_tsf for ibss merging Implement the get TSF by simply returning 0 so that IBSS merging is happening. Otherwise, IBSS nodes that have similar SSID naming won't merge. This is simply fooling the mac80211 that the TSF in the received beacon is higher than the local TSF. Signed-off-by: Chun-Yeow Yeoh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index e17f5d732b5a..301d960c0e98 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4060,6 +4060,16 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw, 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 = { .tx = ath10k_tx, .start = ath10k_start, @@ -4085,6 +4095,7 @@ static const struct ieee80211_ops ath10k_ops = { .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, -- cgit v1.2.2 From 9ba4c787aac4923855fac596cebb2b8c42e488fb Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 25 Feb 2014 09:29:57 +0200 Subject: ath10k: add more details to some debug messages Makes it easier to determine why some failures happened. Signed-off-by: Ben Greear Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 3 ++- drivers/net/wireless/ath/ath10k/txrx.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 301d960c0e98..31932940c64d 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3539,7 +3539,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); diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index ec6f82521b0e..8271df2eb21d 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -378,7 +378,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; } -- cgit v1.2.2 From d960c369c8adddf79b0188aad1dbdafa22f68d97 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 25 Feb 2014 09:29:57 +0200 Subject: ath10k: fix 4addr rx The nwifi header is padded to 4 bytes. This wasn't a problem until one tried to (at least) rx 4addr frames. This finally allows managed iface to be used in a bridge. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 4767c24bf819..040a85418599 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -632,6 +632,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) { @@ -681,7 +687,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); @@ -768,7 +774,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 */ -- cgit v1.2.2 From 76f900244f084ae684c282f7aac938419d6afb2e Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 25 Feb 2014 09:29:57 +0200 Subject: ath10k: fix sta_rc_update for non-ap iftype The arsta structure wasn't initialized for non-ap interfaces. This should fix related warnings/crashes. Reported-By: Ben Greear Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 31932940c64d..27466d83ea86 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3179,6 +3179,13 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, 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)) @@ -3208,10 +3215,6 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, "mac vdev %d peer create %pM (new sta) num_peers %d\n", arvif->vdev_id, sta->addr, ar->num_peers); - memset(arsta, 0, sizeof(*arsta)); - arsta->arvif = arvif; - INIT_WORK(&arsta->update_wk, ath10k_sta_rc_update_wk); - ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr); if (ret) ath10k_warn("Failed to add peer %pM for vdev %d when adding a new sta: %i\n", -- cgit v1.2.2 From e72698f8a95f16ca764b62b609c50e3423e2a584 Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Wed, 26 Feb 2014 18:42:05 +0200 Subject: ath10k: set the mactime of ieee80211_rx_status Retrieve the mactime of ieee80211_rx_status based on received data frame. The value is obtained from the htt_rx_indication_ppdu structure and only available in 32-bit. kvalo: white space fixes Signed-off-by: Chun-Yeow Yeoh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt.h | 2 ++ drivers/net/wireless/ath/ath10k/htt_rx.c | 1 + drivers/net/wireless/ath/ath10k/txrx.c | 6 ++++++ 3 files changed, 9 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index b93ae355bc08..02c009d227a4 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -1181,6 +1181,8 @@ struct htt_rx_info { u32 info1; u32 info2; } rate; + + u32 tsf; bool fcs_err; bool amsdu_more; bool mic_err; diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 040a85418599..fcd00f639e13 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -996,6 +996,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, 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); diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 8271df2eb21d..dcf7efdc1825 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -258,6 +258,12 @@ 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 flag 0x%x fcs-err %i\n", info->skb, -- cgit v1.2.2 From 2f0f112111f5d635699026d1d6a2fe144eabb489 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Wed, 26 Feb 2014 18:42:09 +0200 Subject: ath10k: enable spectrum management support Indicate spectrum management support in hardware flags, while we already handle power set (IEEE80211_CONF_CHANGE_POWER) in the ath10k driver. This enable 802.11h support for station mode. Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 27466d83ea86..0423af2100e9 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4457,7 +4457,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. */ -- cgit v1.2.2 From 9f81f72556107a38ebf523ea1d38ef85dfa35d09 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Fri, 17 Jan 2014 20:04:14 +0100 Subject: ath10k: bitrate_mask add force_sgi support Add force SGI support. Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/mac.c | 35 +++++++++++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 1fc26fe057e8..d1c5e7a49e72 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -288,6 +288,7 @@ struct ath10k_vif { u8 fixed_rate; u8 fixed_nss; + u8 force_sgi; }; struct ath10k_vif_iter { diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 0423af2100e9..239357fb4175 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3909,7 +3909,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; @@ -3918,12 +3919,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); @@ -3949,6 +3954,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; @@ -3963,6 +3981,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, @@ -3971,7 +3994,13 @@ 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, -- cgit v1.2.2 From a80ddb003a24d10a87e3fbfc2d8e46c54698b585 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Tue, 25 Feb 2014 07:56:39 +0100 Subject: ath10k: skip management frames in HTT path After we pass frames with INV_PEER to upper layer in commit 716ae53c56cf ("ath10k: pass frames with invalid peer status to upper layer") we could pass some management frames (in case INVALID_PEER and MGMT_CTRL) twice to upper layer, once via WMI and once via HTT. Next we could handle assoc request twice. This patch remove such regression. Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index fcd00f639e13..23d909555e58 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -852,6 +852,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; @@ -946,7 +960,8 @@ 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; -- cgit v1.2.2 From 767d34fc67af3939b8ec09804e2b60a1daf94945 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 27 Feb 2014 18:50:03 +0200 Subject: ath10k: remove DMA mapping wrappers There's no real benefit from using them. DMA-API already provides debugging. Some skbuffs are already mapped directly with DMA-API since wrapper arguments were insufficient and extending them would be pointless. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 27 --------------------------- drivers/net/wireless/ath/ath10k/htc.c | 11 ++++++++--- drivers/net/wireless/ath/ath10k/htt_tx.c | 12 ++++++++---- drivers/net/wireless/ath/ath10k/mac.c | 4 +++- drivers/net/wireless/ath/ath10k/txrx.c | 5 +---- drivers/net/wireless/ath/ath10k/wmi.c | 17 ++++++++++++++--- 6 files changed, 34 insertions(+), 42 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index d1c5e7a49e72..be7d75040aad 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -62,7 +62,6 @@ struct ath10k; struct ath10k_skb_cb { dma_addr_t paddr; - bool is_mapped; bool is_aborted; u8 vdev_id; @@ -87,32 +86,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; diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index edc57ab505c8..69f1f4696c25 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,8 @@ 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 device *dev = htc->ar->dev; int credits = 0; int ret; @@ -157,7 +161,8 @@ 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; @@ -169,7 +174,7 @@ int ath10k_htc_send(struct ath10k_htc *htc, 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); diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index acaa046dc93b..f5960c593810 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -334,7 +334,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; @@ -358,7 +360,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: @@ -437,7 +439,9 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) skb_cb->htt.pad_len = 0; } - 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_pull_txfrag; @@ -509,7 +513,7 @@ int ath10k_htt_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_pull_txfrag: skb_pull(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len); err_free_txdesc: diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 239357fb4175..9230ad5e0f87 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -839,7 +839,9 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, spin_lock_bh(&arvif->ar->data_lock); if (arvif->beacon) { - ath10k_skb_unmap(arvif->ar->dev, 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; diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index dcf7efdc1825..fe69899f1a22 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -51,7 +51,6 @@ 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; 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,9 +64,7 @@ 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); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 91e501b5499e..478e7f669e79 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1360,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"); @@ -1435,16 +1435,27 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) ath10k_warn("SWBA overrun on vdev %d\n", arvif->vdev_id); - ath10k_skb_unmap(ar->dev, 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); } - ath10k_skb_map(ar->dev, bcn); + 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); } } -- cgit v1.2.2 From 7676a88876b0e72b46c0e51cabcf47b416730509 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 27 Feb 2014 18:50:04 +0200 Subject: ath10k: remove is_aborted from skb_cb The flag wasn't used anymore. No need to keep it. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 1 - drivers/net/wireless/ath/ath10k/pci.c | 20 -------------------- 2 files changed, 21 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index be7d75040aad..ab7009126c78 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -62,7 +62,6 @@ struct ath10k; struct ath10k_skb_cb { dma_addr_t paddr; - bool is_aborted; u8 vdev_id; struct { diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 34f09106f423..d97397563944 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -63,7 +63,6 @@ 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_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); @@ -993,22 +992,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); @@ -1339,7 +1322,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); @@ -1424,7 +1406,6 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info) continue; } - ATH10K_SKB_CB(netbuf)->is_aborted = true; ar_pci->msg_callbacks_current.tx_completion(ar, netbuf, id); @@ -1482,7 +1463,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) -- cgit v1.2.2 From 726346fc713498a84c4d591fce9f1fbe38bf2a44 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 27 Feb 2014 18:50:04 +0200 Subject: ath10k: replace send_head() with tx_sg() PCI is capable of handling scatter-gather lists. This can be used to avoid copying memory. Change the name of the callback while at to reflect its purpose. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 12 ++--- drivers/net/wireless/ath/ath10k/ce.h | 7 +++ drivers/net/wireless/ath/ath10k/hif.h | 25 ++++++----- drivers/net/wireless/ath/ath10k/htc.c | 10 ++++- drivers/net/wireless/ath/ath10k/pci.c | 84 +++++++++++++++++++++++------------ 5 files changed, 92 insertions(+), 46 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index d44d618b05f9..a0b1a8cc3393 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; diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 67dbde6a5c74..322e929437de 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -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/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 #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 69f1f4696c25..64ab8d642f5f 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -125,6 +125,7 @@ int ath10k_htc_send(struct ath10k_htc *htc, { 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; @@ -166,8 +167,13 @@ int ath10k_htc_send(struct ath10k_htc *htc, 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; diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index d97397563944..713c18e8a1a8 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -714,6 +714,9 @@ 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) { + if (transfer_context == NULL) + continue; + compl = get_free_compl(pipe_info); if (!compl) break; @@ -781,39 +784,64 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) ath10k_pci_process_ce(ar); } -/* 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) @@ -2249,7 +2277,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, -- cgit v1.2.2 From a16942e63008875a6a057ea2973becd261ed0c4e Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 27 Feb 2014 18:50:04 +0200 Subject: ath10k: bypass htc for htt tx path Going through full htc tx path for htt tx is a waste of resources. By skipping it it's possible to easily submit scatter-gather to the pci hif for reduced host cpu load and improved performance. The new approach uses dma pool to store the following metadata for each tx request: * msdu fragment list * htc header * htt tx command The htt tx command contains a msdu prefetch. Instead of copying it original mapped msdu address is used to submit a second scatter-gather item to hif to make a complete htt tx command. The htt tx command itself hands over dma mapped pointers to msdus and completion of the command itself doesn't mean the frame has been sent and can be unmapped/freed. This is why htc tx completion is skipped for htt tx as all tx related resources are freed upon htt tx completion indication event (which also implicitly means htt tx command itself was completed). Since now each htt tx request effectively consists of 2 copy engine items CE_HTT_H2T_MSG_SRC_NENTRIES is updated to allow maximum of TARGET_10X_NUM_MSDU_DESC msdus being queued. This keeps the tx path resource management simple. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 4 +- drivers/net/wireless/ath/ath10k/ce.h | 2 +- drivers/net/wireless/ath/ath10k/core.h | 5 +- drivers/net/wireless/ath/ath10k/htc.c | 4 +- drivers/net/wireless/ath/ath10k/htt.h | 9 ++ drivers/net/wireless/ath/ath10k/htt_tx.c | 190 ++++++++++++++++--------------- drivers/net/wireless/ath/ath10k/pci.c | 12 +- drivers/net/wireless/ath/ath10k/txrx.c | 6 +- 8 files changed, 123 insertions(+), 109 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index a0b1a8cc3393..a79499c82350 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -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 322e929437de..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 diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index ab7009126c78..0e71979d837c 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -67,9 +67,8 @@ struct ath10k_skb_cb { struct { u8 tid; bool is_offchan; - - u8 frag_len; - u8 pad_len; + struct ath10k_htt_txbuf *txbuf; + u32 txbuf_paddr; } __packed htt; struct { diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 64ab8d642f5f..7f1bccd3597f 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -202,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 02c009d227a4..2b76cb5d77a4 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -20,6 +20,7 @@ #include #include +#include #include "htc.h" #include "rx_desc.h" @@ -1188,6 +1189,13 @@ struct htt_rx_info { 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; @@ -1269,6 +1277,7 @@ 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 */ diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index f5960c593810..20b7a446a9f8 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; } @@ -139,6 +147,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; } @@ -350,8 +359,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) @@ -377,19 +385,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) @@ -408,105 +416,109 @@ 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; - } - - 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_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; - } + 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; 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_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); - } + goto err_free_txbuf; - ath10k_dbg(ATH10K_DBG_HTT, "tx-msdu 0x%llx\n", - (unsigned long long) ATH10K_SKB_CB(msdu)->paddr); - ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "tx-msdu: ", - msdu->data, msdu->len); + if (likely(use_frags)) { + frags = skb_cb->htt.txbuf->frags; - skb_put(txdesc, desc_len); - cmd = (struct htt_cmd *)txdesc->data; + 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; + + flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI, + HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); - tid = ATH10K_SKB_CB(msdu)->htt.tid; + frags_paddr = skb_cb->htt.txbuf_paddr; + } else { + flags0 |= SM(ATH10K_HW_TXRX_MGMT, + HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); - ath10k_dbg(ATH10K_DBG_HTT, "htt data tx using tid %hhu\n", tid); + frags_paddr = skb_cb->paddr; + } + + /* 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; @@ -514,10 +526,10 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) err_unmap_msdu: dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); -err_pull_txfrag: - skb_pull(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len); -err_free_txdesc: - dev_kfree_skb_any(txdesc); +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/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 713c18e8a1a8..2305d583019b 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -714,6 +714,7 @@ 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) { + /* no need to call tx completion for NULL pointers */ if (transfer_context == NULL) continue; @@ -1423,16 +1424,9 @@ 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; - } ar_pci->msg_callbacks_current.tx_completion(ar, netbuf, diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index fe69899f1a22..2993ca772c56 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -66,8 +66,10 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, 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); -- cgit v1.2.2 From 6c5151a9ffa9f796f2d707617cecb6b6b241dff8 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 27 Feb 2014 18:50:04 +0200 Subject: ath10k: batch htt tx/rx completions HTT Rx endpoint processes both frame rx indications and frame tx completion indications. Those completions typically come in batches and may be mixed so it makes sense to defer processing hoping to get a bunch of them and take advantage of hot caches. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt.h | 7 ++ drivers/net/wireless/ath/ath10k/htt_rx.c | 118 ++++++++++++++++++++----------- 2 files changed, 85 insertions(+), 40 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 2b76cb5d77a4..654867fc1ae7 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -1283,6 +1283,12 @@ struct ath10k_htt { * 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 @@ -1354,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 23d909555e58..b7150de984e7 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) { @@ -237,6 +237,10 @@ void ath10k_htt_rx_detach(struct ath10k_htt *htt) del_timer_sync(&htt->rx_ring.refill_retry_timer); tasklet_kill(&htt->rx_replenish_task); + tasklet_kill(&htt->txrx_compl_task); + + skb_queue_purge(&htt->tx_compl_q); + skb_queue_purge(&htt->rx_compl_q); while (sw_rd_idx != __le32_to_cpu(*(htt->rx_ring.alloc_idx.vaddr))) { struct sk_buff *skb = @@ -529,6 +533,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; @@ -1138,6 +1148,43 @@ 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; + + 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; @@ -1156,10 +1203,10 @@ 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: + skb_queue_tail(&htt->rx_compl_q, skb); + 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, @@ -1194,44 +1241,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; @@ -1271,3 +1291,21 @@ 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; + + while ((skb = skb_dequeue(&htt->tx_compl_q))) { + ath10k_htt_rx_frm_tx_compl(htt->ar, skb); + dev_kfree_skb_any(skb); + } + + 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); + } +} -- cgit v1.2.2 From 45967089d2685d2327c9710fe796d499d90ae844 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 27 Feb 2014 18:50:05 +0200 Subject: ath10k: reduce htt tx/rx spinlock overhead It is inefficient to grab irqsave spinlocks for skb lists for each queue/dequeue action. Using rx_ring.lock and tx_lock allows to use less heavy bh spinlock functions and moving locking upwards allows to toggle spinlocks less often. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 24 +++++++++++++++++++----- drivers/net/wireless/ath/ath10k/htt_tx.c | 5 ++--- drivers/net/wireless/ath/ath10k/txrx.c | 4 ++-- 3 files changed, 23 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index b7150de984e7..8e708dfb63e3 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -274,7 +274,7 @@ 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"); @@ -287,7 +287,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; } @@ -311,6 +310,8 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, struct sk_buff *msdu; struct htt_rx_desc *rx_desc; + lockdep_assert_held(&htt->rx_ring.lock); + if (ath10k_htt_rx_ring_elems(htt) == 0) ath10k_warn("htt rx ring is empty!\n"); @@ -918,6 +919,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); @@ -1055,8 +1058,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"); @@ -1158,6 +1164,8 @@ static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar, __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; @@ -1204,7 +1212,9 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) break; } case HTT_T2H_MSG_TYPE_RX_IND: - skb_queue_tail(&htt->rx_compl_q, skb); + 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: { @@ -1298,14 +1308,18 @@ static void ath10k_htt_txrx_compl_task(unsigned long ptr) struct htt_resp *resp; struct sk_buff *skb; - while ((skb = skb_dequeue(&htt->tx_compl_q))) { + 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); - while ((skb = skb_dequeue(&htt->rx_compl_q))) { + 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 20b7a446a9f8..7a3e2e40dd5c 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -125,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; @@ -140,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) diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 2993ca772c56..0541dd939ce9 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -52,6 +52,8 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, struct ath10k_skb_cb *skb_cb; struct sk_buff *msdu; + lockdep_assert_held(&htt->tx_lock); + ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n", tx_done->msdu_id, !!tx_done->discard, !!tx_done->no_ack); @@ -91,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[] = { -- cgit v1.2.2 From 2f5280da40222fc2d61aa9425c681f615965c003 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 27 Feb 2014 18:50:05 +0200 Subject: ath10k: remove pci completion list One of the premises was to guarantee serialized completion handling for upper layers (HTC/WMI/HTT). Since quite some time now it is no longer necessary. The other premise was to batch up tx/rx completions to take advantage of hot caches. However frame tx/rx completion indications come in on a single pipe already so they are already batched up. More meaningful batching is done in HTT itself. This means PCI completion is no longer necessary to keep around. It just wastes memory, cycles and SLOC. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 275 +++------------------------------- drivers/net/wireless/ath/ath10k/pci.h | 28 ---- 2 files changed, 24 insertions(+), 279 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 2305d583019b..9d242d801d9d 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -58,7 +58,6 @@ 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); @@ -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; @@ -718,27 +694,8 @@ static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state) if (transfer_context == NULL) continue; - 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; - - /* - * 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. */ @@ -747,42 +704,40 @@ 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); - ath10k_pci_process_ce(ar); + if (unlikely(max_nbytes < nbytes)) { + ath10k_warn("rxed more than expected (nbytes %d, max %d)", + nbytes, max_nbytes); + dev_kfree_skb_any(skb); + continue; + } + + skb_put(skb, nbytes); + cb->rx_completion(ar, skb, pipe_info->pipe_num); + } } static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, @@ -931,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); @@ -1021,131 +930,6 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar) tasklet_kill(&ar_pci->pipe_info[i].intr); } -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, @@ -1317,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); @@ -1351,9 +1129,6 @@ err_stop: ath10k_ce_disable_interrupts(ar); ath10k_pci_free_irq(ar); ath10k_pci_kill_tasklet(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 @@ -1494,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 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; -- cgit v1.2.2 From 8d60ee87a7040973705247c9c8dfa11be1115709 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 27 Feb 2014 18:50:05 +0200 Subject: ath10k: minimize coherent dma accesses It doesn't make much sense to calculate the ring size fill count because it already is memoized in a separate variable. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 8e708dfb63e3..36a3871097a2 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -225,12 +225,6 @@ 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; @@ -276,8 +270,10 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt) 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]; @@ -312,9 +308,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, 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_confused) { ath10k_warn("htt is confused. refusing rx\n"); return 0; -- cgit v1.2.2 From 69244e5656b9d78964f11158680140e7994789d5 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Thu, 27 Feb 2014 18:50:00 +0200 Subject: ath10k: add vdev-id, return code to error codes When using multiple vdevs (stations, aps, etc), it is nice to be able to associate log messages with specific interfaces. So, add vdev-id to most logging messages. Add return code as well, where it was missing. kvalo: unify some of the messages to follow the same style Signed-off-by: Ben Greear Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 201 +++++++++++++++++++--------------- 1 file changed, 115 insertions(+), 86 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 9230ad5e0f87..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); @@ -349,7 +351,8 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif) ret = ath10k_wmi_pdev_set_param(ar, param, ATH10K_KICKOUT_THRESHOLD); if (ret) { - ath10k_warn("Failed to set kickout threshold: %d\n", ret); + ath10k_warn("Failed to set kickout threshold on vdev %i: %d\n", + arvif->vdev_id, ret); return ret; } @@ -357,8 +360,8 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif) ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, ATH10K_KEEPALIVE_MIN_IDLE); if (ret) { - ath10k_warn("Failed to set keepalive minimum idle time : %d\n", - ret); + ath10k_warn("Failed to set keepalive minimum idle time on vdev %i : %d\n", + arvif->vdev_id, ret); return ret; } @@ -366,8 +369,8 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif) ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, ATH10K_KEEPALIVE_MAX_IDLE); if (ret) { - ath10k_warn("Failed to set keepalive maximum idle time: %d\n", - ret); + ath10k_warn("Failed to set keepalive maximum idle time on vdev %i: %d\n", + arvif->vdev_id, ret); return ret; } @@ -375,8 +378,8 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif) ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, ATH10K_KEEPALIVE_MAX_UNRESPONSIVE); if (ret) { - ath10k_warn("Failed to set keepalive maximum unresponsive time: %d\n", - ret); + ath10k_warn("Failed to set keepalive maximum unresponsive time on vdev %i: %d\n", + arvif->vdev_id, ret); return ret; } @@ -529,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; } @@ -553,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; } @@ -597,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; } @@ -621,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; } @@ -644,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; @@ -682,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; } @@ -711,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; } @@ -864,8 +880,8 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, 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; } @@ -945,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 { @@ -1198,8 +1214,8 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar, WMI_AP_PS_PEER_PARAM_UAPSD, uapsd); if (ret) { - ath10k_warn("failed to set ap ps peer param uapsd: %d\n", - ret); + ath10k_warn("failed to set ap ps peer param uapsd for vdev %i: %d\n", + arvif->vdev_id, ret); return ret; } @@ -1208,8 +1224,8 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar, WMI_AP_PS_PEER_PARAM_MAX_SP, max_sp); if (ret) { - ath10k_warn("failed to set ap ps peer param max sp: %d\n", - ret); + ath10k_warn("failed to set ap ps peer param max sp for vdev %i: %d\n", + arvif->vdev_id, ret); return ret; } @@ -1220,8 +1236,8 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar, 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: %d\n", - ret); + ath10k_warn("failed to set ap ps peer param ageout time for vdev %i: %d\n", + arvif->vdev_id, ret); return ret; } } @@ -1413,8 +1429,8 @@ 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; } @@ -1426,8 +1442,8 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, 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; } @@ -1436,14 +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: %d\n", ret); + ath10k_warn("failed to setup peer SMPS for vdev %i: %d\n", + arvif->vdev_id, ret); return; } @@ -1516,34 +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: %d\n", 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, %d\n", - sta->addr, ret); + ath10k_warn("could not set qos params for STA %pM for vdev %i: %d\n", + sta->addr, arvif->vdev_id, ret); return ret; } @@ -1559,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; } @@ -2526,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; } @@ -2537,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; } @@ -2546,21 +2567,23 @@ 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; } ret = ath10k_mac_set_kickout(arvif); if (ret) { - ath10k_warn("Failed to set kickout parameters: %d\n", - ret); + ath10k_warn("Failed to set vdev %i kickout parameters: %d\n", + arvif->vdev_id, ret); goto err_peer_delete; } } @@ -2571,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; } @@ -2580,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; } @@ -2589,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; } } @@ -2653,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; @@ -2752,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) { @@ -2765,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) { @@ -2780,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 && @@ -2801,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) { @@ -2817,8 +2845,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ret = ath10k_vdev_start(arvif); if (ret) { - ath10k_warn("failed to start vdev: %d\n", - ret); + ath10k_warn("failed to start vdev %i: %d\n", + arvif->vdev_id, ret); goto exit; } @@ -2853,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) { @@ -2872,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) { @@ -2891,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) { @@ -3023,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, @@ -3084,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; } @@ -3231,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); @@ -3248,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 || @@ -3262,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); @@ -4407,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; } @@ -4547,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; } -- cgit v1.2.2 From bfa353689ae9bff3aa1cfe146defff17032a4a02 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 3 Mar 2014 14:07:09 -0800 Subject: ath10k: support msdu chaining Consolidate the list of msdu skbs into the msdu-head skb, delete the rest of the skbs, pass the msdu-head skb on up the stack as normal. Tested with high-speed TCP and UDP traffic on modified firmware that supports raw-rx. Signed-off-by: Ben Greear Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 59 +++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 36a3871097a2..cdcbe2de95f9 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -398,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; @@ -425,7 +426,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, msdu->next = next; msdu = next; - msdu_chaining = 1; } last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) & @@ -901,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) { @@ -991,10 +1042,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, continue; } - /* FIXME: we do not support chaining yet. - * this needs investigation */ - if (msdu_chaining) { - ath10k_warn("htt rx msdu_chaining is true\n"); + if (msdu_chaining && + (ath10k_unchain_msdu(msdu_head) < 0)) { ath10k_htt_rx_free_msdu_chain(msdu_head); continue; } -- cgit v1.2.2 From 70dd77b4c50da518b57b8b9b125a8c9aabe9bc1a Mon Sep 17 00:00:00 2001 From: Marek Puzyniak Date: Wed, 5 Mar 2014 13:10:33 +0100 Subject: ath10k: do not overwrite max_antenna_gain Seems like we have an old bug, where we incidently overwrites the max_antenna_gain we pass to firmware, with zero value. End of all we are artifically reducing the output power. This patch removes the excessive assignment on max_antenna_gain, which is being provided by regulatory domain, and consequently improves the tx power. Signed-off-by: Marek Puzyniak Signed-off-by: Bartosz Markowski Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 478e7f669e79..cb1f7b5bcf4c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3393,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; -- cgit v1.2.2 From 3b3e0efb5c72c4fc940af50b33626b8a78a907dc Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 9 Mar 2014 11:02:54 +0100 Subject: ath9k: fix ready time of the multicast buffer queue qi->tqi_readyTime is written directly to registers that expect microseconds as unit instead of TU. When setting the CABQ ready time, cur_conf->beacon_interval is in TU, so convert it to microseconds before passing it to ath9k_hw. This should hopefully fix some Tx DMA issues with buffered multicast frames in AP mode. Cc: stable@vger.kernel.org Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index fafacfed44ea..3e7966b4b61e 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1699,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); -- cgit v1.2.2 From abee4c8414a621795bc7d4302061209a0b5d04c1 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 9 Mar 2014 11:27:49 +0100 Subject: ath9k: clean up and enhance ANI debugfs file Unify scnprintf calls and include the current OFDM/CCK immunity level. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.c | 58 ++++++++++++++++------------------ 1 file changed, 28 insertions(+), 30 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index f8924efdad55..86abb3404dc7 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -139,43 +139,41 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf, 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; -- cgit v1.2.2 From afdc05f09df633546da70c92f5d1557687331789 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 10 Mar 2014 19:56:33 +0100 Subject: ath9k_hw: remove ANI function restrictions for AP mode The primary purpose of this piece of code was to selectively disable OFDM weak signal detection. The checks for this are elsewhere, and an earlier commit relaxed the restrictions for older chips, which are more sensitive to interference. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ani.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index 2ce5079007b6..6d47783f2e5b 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -318,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, -- cgit v1.2.2 From 28327fd096248ad1153e455ca8ffa205927b4b89 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 11 Mar 2014 16:10:33 +0100 Subject: ath9k_hw: set ANI cycpwr_thr1 as absolute values instead of relative The table was copied from the ANI implementation of AR9300. It assumes that the INI values contain a baseline value that is usable as reference from which to increase/decrease based on the noise immunity value. On older chips, the differences are bigger and especially AR5008/AR9001 are configured to much more sensitive values than what is useful. Improve ANI behavior by reverting to the absolute values used in the previous implementation (expressed as a simple formula instead of the old table). Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar5008_phy.c | 44 ++++------------------------- 1 file changed, 6 insertions(+), 38 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index ff415e863ee9..504e189728cd 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 */ @@ -1073,41 +1069,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 +1092,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++; -- cgit v1.2.2 From 9301ca90b6f447eca020ca6a66bf656b0a985d4d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 11 Mar 2014 16:10:34 +0100 Subject: ath9k_hw: set ANI firstep as absolute values instead of relative On older chips, the INI value differ in similar ways as cycpwr_thr1, so convert it to absolute values as well. Since the ANI algorithm is different here compared to the old implementation (fewer steps, controlled at a different point in time), it makes sense to use values similar to what would be applied for newer chips, just without relying on INI defaults. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar5008_phy.c | 41 ++++------------------------- 1 file changed, 5 insertions(+), 36 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 504e189728cd..3b3e91057a4c 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -917,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:{ @@ -1004,42 +1004,11 @@ 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 * 2; 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; - + AR_PHY_FIND_SIG_FIRSTEP, value); REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW, - AR_PHY_FIND_SIG_FIRSTEP_LOW, value2); + AR_PHY_FIND_SIG_FIRSTEP_LOW, value); if (level != aniState->firstepLevel) { ath_dbg(common, ANI, @@ -1056,7 +1025,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++; -- cgit v1.2.2 From b499abdc76d8b9780cb8918b8755e0437f741d80 Mon Sep 17 00:00:00 2001 From: John Greene Date: Tue, 11 Mar 2014 14:08:34 -0400 Subject: ath5k: add missing dma_map_error call Trivial patch to address this trace. Now calls dma_mapping_error and return -ENOSPC if a problem found. WARNING: at lib/dma-debug.c:933 check_unmap+0x47b/0x960() Hardware name: Aspire 5515 ath5k 0000:02:00.0: DMA-API: device driver failed to check map error[device address=0x00000000874fcd42] [size=45 bytes] [mapped as single] Modules linked in: bnep bluetooth ebtable_filter ebtables ip6table_filter ip6_tables be2iscsi iscsi_boot_sysfs bnx2i cnic uio cxgb4i cxgb4 cxgb3i cxgb3 mdio libcxgbi ib_iser rdma_cm ib_addr iw_cm ib_cm ib_sa ib_mad ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi arc4 snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_seq snd_seq_device ath5k ath snd_pcm sparse_keymap snd_page_alloc mac80211 snd_timer sp5100_tco snd edac_core k8temp soundcore edac_mce_amd i2c_piix4 cfg80211 rfkill shpchp vhost_net tun macvtap macvlan kvm_amd kvm uinput dm_crypt ata_generic pata_acpi radeon i2c_algo_bit pata_atiixp drm_kms_helper ttm drm r8169 mii i2c_core wmi video sunrpc Pid: 820, comm: firewalld Not tainted 3.9.0-0.rc3.git1.4.fc19.x86_64 #1 Call Trace: [] warn_slowpath_common+0x70/0xa0 [] warn_slowpath_fmt+0x4c/0x50 [] check_unmap+0x47b/0x960 [] ? native_sched_clock+0x15/0x80 [] ? sched_clock+0x9/0x10 [] debug_dma_unmap_page+0x5f/0x70 [] ath5k_tasklet_tx+0x157/0x3f0 [ath5k] [] ? sched_clock_local+0x1d/0x80 [] ? tasklet_action+0x56/0x210 [] tasklet_action+0x97/0x210 [] __do_softirq+0xff/0x400 [] irq_exit+0xb5/0xc0 [] do_IRQ+0x56/0xc0 [] common_interrupt+0x72/0x72 [] ? dput+0x111/0x310 [] ? dput+0x37/0x310 [] link_path_walk+0x528/0x910 [] path_openat+0x94/0x530 [] do_filp_open+0x38/0x80 [] open_exec+0x4a/0x130 [] load_elf_binary+0x7f3/0x18e0 [] ? sched_clock+0x9/0x10 [] ? sched_clock_local+0x1d/0x80 [] ? sched_clock_cpu+0xa8/0x100 [] ? trace_hardirqs_off+0xd/0x10 [] ? local_clock+0x5f/0x70 [] ? lock_release_holdtime.part.28+0xf/0x190 [] ? elf_core_dump+0x1980/0x1980 [] search_binary_handler+0x1a1/0x4f0 [] ? search_binary_handler+0x67/0x4f0 [] do_execve_common.isra.26+0x64c/0x710 [] ? do_execve_common.isra.26+0x112/0x710 [] sys_execve+0x36/0x50 [] stub_execve+0x69/0xa0 Signed-off-by: John Greene Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless/ath') 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)); -- cgit v1.2.2 From 1b5c8d60d2257fd66ad789872845efd5c98bb26b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Mar 2014 10:22:38 -0700 Subject: ath9k: Convert uses of __constant_ to The use of __constant_ has been unnecessary for quite awhile now. Make these uses consistent with the rest of the kernel. Signed-off-by: Joe Perches Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index b8daff78b9d1..d7625ecb6387 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) -- cgit v1.2.2 From fd0ab793353862257dee56e07aed79dc195bc1c8 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:44 +0100 Subject: ath9k: move struct ath_beacon_config to common Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 9 --------- drivers/net/wireless/ath/ath9k/common.h | 9 +++++++++ 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index f995c374a9b4..b54bcae61ba1 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -408,15 +408,6 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw, #define TSF_TO_TU(_h,_l) \ ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) -struct ath_beacon_config { - int beacon_interval; - u16 dtim_period; - u16 bmiss_timeout; - u8 dtim_count; - bool enable_beacon; - bool ibss_creator; -}; - struct ath_beacon { enum { OK, /* no change needed */ diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index 4c449e35bd65..26aafb394a5c 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -44,6 +44,15 @@ #define ATH_EP_RND(x, mul) \ (((x) + ((mul)/2)) / (mul)) +struct ath_beacon_config { + int beacon_interval; + u16 dtim_period; + u16 bmiss_timeout; + u8 dtim_count; + bool enable_beacon; + bool ibss_creator; +}; + bool ath9k_cmn_rx_accept(struct ath_common *common, struct ieee80211_hdr *hdr, struct ieee80211_rx_status *rxs, -- cgit v1.2.2 From 3c4816d9a324f06c481dcc36c8dc1168f5d785c5 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:45 +0100 Subject: ath9k_htc: use common ath_beacon_config Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc.h | 10 +++---- drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 40 ++++++++++++------------- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 2 +- 3 files changed, 25 insertions(+), 27 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 3baf9ceae601..ed41db550e18 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -406,12 +406,9 @@ 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 { struct ieee80211_vif *bslot[ATH9K_HTC_MAX_BCN_VIF]; - u16 beacon_interval; - u16 dtim_period; - u16 bmiss_timeout; - u32 bmiss_cnt; + u32 bmisscnt; }; struct ath_btcoex { @@ -489,7 +486,8 @@ struct ath9k_htc_priv { struct ath9k_hw_cal_data caldata; 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; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index a00ddb9e737e..89290500b2cf 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -64,7 +64,7 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, - struct htc_beacon_config *bss_conf) + struct ath_beacon_config *bss_conf) { struct ath_common *common = ath9k_hw_common(priv->ah); struct ath9k_beacon_state bs; @@ -162,7 +162,7 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, } static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, - struct htc_beacon_config *bss_conf) + struct ath_beacon_config *bss_conf) { struct ath_common *common = ath9k_hw_common(priv->ah); enum ath9k_int imask = 0; @@ -211,13 +211,13 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, 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; + priv->beacon.bmisscnt = 0; 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) + struct ath_beacon_config *bss_conf) { struct ath_common *common = ath9k_hw_common(priv->ah); enum ath9k_int imask = 0; @@ -257,7 +257,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, 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; + priv->beacon.bmisscnt = 0; htc_imask = cpu_to_be32(imask); WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); } @@ -279,7 +279,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); @@ -340,7 +340,7 @@ 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))) { @@ -423,8 +423,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); @@ -432,16 +432,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; } @@ -460,13 +460,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", @@ -480,7 +480,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", @@ -496,7 +496,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) @@ -528,7 +528,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; @@ -583,7 +583,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; @@ -619,7 +619,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 b22fb64403d9..b8a022015f76 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -520,7 +520,7 @@ 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; ath9k_cmn_init_channels_rates(common); ath9k_cmn_init_crypto(ah); -- cgit v1.2.2 From a099874ed9db31e8ac0d8173394e54081d518635 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:46 +0100 Subject: ath9k_htc: move beaconq to struct htc_beacon Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc.h | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 8 ++++---- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index ed41db550e18..69022b08d4d1 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -409,6 +409,7 @@ static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, struct htc_beacon { struct ieee80211_vif *bslot[ATH9K_HTC_MAX_BCN_VIF]; u32 bmisscnt; + u32 beaconq; }; struct ath_btcoex { @@ -512,7 +513,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 89290500b2cf..09ad141b38b6 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,11 +54,11 @@ 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); } } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index b8a022015f76..6eb19b8352ba 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -405,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; } -- cgit v1.2.2 From 88a4f56ef09d6f38beee79e9abff7cb7f867dc52 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:47 +0100 Subject: ath9k_htc: use ath_beacon_conf.enable_beacon to reduce difference between ath9k and ath9k_htc Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc.h | 1 - drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 4 ++-- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 69022b08d4d1..d5a10882bd74 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -439,7 +439,6 @@ static inline void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv) #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) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 09ad141b38b6..4540eacee093 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -199,7 +199,7 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, } while (nexttbtt < tsftu); } - if (test_bit(OP_ENABLE_BEACON, &priv->op_flags)) + if (bss_conf->enable_beacon) imask |= ATH9K_INT_SWBA; ath_dbg(common, CONFIG, @@ -247,7 +247,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, else priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; - if (test_bit(OP_ENABLE_BEACON, &priv->op_flags)) + if (bss_conf->enable_beacon) imask |= ATH9K_INT_SWBA; ath_dbg(common, CONFIG, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 90dad4172b0a..40733d03e1a2 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1529,7 +1529,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); } @@ -1543,7 +1543,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); } } -- cgit v1.2.2 From eefa01ddd57893c7f4482024029fec323c8e1b89 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Thu, 27 Feb 2014 11:40:46 +0100 Subject: ath9k: move sc_flags to ath_common we will need it for ath9k_htc, may be other drivers too Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 10 ++++++++ drivers/net/wireless/ath/ath9k/ahb.c | 7 ++--- drivers/net/wireless/ath/ath9k/ath9k.h | 10 -------- drivers/net/wireless/ath/ath9k/beacon.c | 18 +++++++------ drivers/net/wireless/ath/ath9k/debug.c | 2 +- drivers/net/wireless/ath/ath9k/link.c | 16 +++++++----- drivers/net/wireless/ath/ath9k/main.c | 45 ++++++++++++++++++--------------- drivers/net/wireless/ath/ath9k/mci.c | 2 +- drivers/net/wireless/ath/ath9k/pci.c | 8 +++--- drivers/net/wireless/ath/ath9k/tx99.c | 2 +- drivers/net/wireless/ath/ath9k/wow.c | 4 +-- drivers/net/wireless/ath/ath9k/xmit.c | 9 ++++--- 12 files changed, 73 insertions(+), 60 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index d239acc26125..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, @@ -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; diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 2dff2765769b..a5684c38dcd9 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -82,6 +82,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 +125,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 +142,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/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index b54bcae61ba1..7f87f338d7c7 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -688,15 +688,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) @@ -726,7 +717,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; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 02eb4f10332b..637267187929 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -328,7 +328,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; @@ -524,7 +524,7 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc, u64 tsf; /* No need to configure beacon if we are not associated */ - 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, BEACON, "STA is not yet associated..skipping beacon config\n"); return; @@ -629,7 +629,7 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc, * 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, @@ -649,7 +649,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"); @@ -700,6 +700,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; @@ -712,7 +714,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; } @@ -751,13 +753,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); } } diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 86abb3404dc7..780ff1bee6f6 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -208,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); 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/main.c b/drivers/net/wireless/ath/ath9k/main.c index 42a18037004e..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); } @@ -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); @@ -1590,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; /* @@ -1625,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) @@ -1657,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; @@ -1897,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; @@ -2070,13 +2073,15 @@ 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, 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/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 3e7966b4b61e..f76e6b9bb8e6 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1769,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); @@ -1817,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; @@ -2471,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)) { @@ -2554,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); -- cgit v1.2.2 From 92c3f7ef2c59de5c6b58504d330a59f8e8d78e88 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:49 +0100 Subject: ath9k_htc: use common->op_flags Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc.h | 3 --- drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 3 +-- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 26 ++++++++++++++----------- drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 3 ++- 5 files changed, 19 insertions(+), 18 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index d5a10882bd74..707c5b418dc6 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -437,11 +437,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_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 { diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 4540eacee093..9ff9e6e5df06 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -343,7 +343,7 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, 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; } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 6eb19b8352ba..4b3b4dd49a42 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -459,8 +459,6 @@ 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; @@ -485,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); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 40733d03e1a2..6e17c08422c0 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); @@ -1670,10 +1672,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); @@ -1683,10 +1686,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 47b2bfcd8223..e8149e3dbdd5 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -924,9 +924,10 @@ 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)); + ath9k_hw_startpcureceive(priv->ah, test_bit(ATH_OP_SCANNING, &common->op_flags)); } static inline void convert_htc_flag(struct ath_rx_status *rx_stats, -- cgit v1.2.2 From c35ccb38d49fb08c6fe84553905a7e2d2b7c4407 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:50 +0100 Subject: ath9k_htc: add ATH_OP_PRIM_STA_VIF we will need it to make common-beacon code work. Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 6e17c08422c0..b82a7c43eb6e 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1478,6 +1478,7 @@ static void ath9k_htc_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) 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); } } @@ -1510,6 +1511,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)) -- cgit v1.2.2 From ed51fe314f9e9335333d4ab8bd91ad9da17c9925 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:51 +0100 Subject: ath9k: remove unused bc_tstamp Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 7f87f338d7c7..d8dddce75da7 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -417,7 +417,6 @@ struct ath_beacon { u32 beaconq; u32 bmisscnt; - u32 bc_tstamp; struct ieee80211_vif *bslot[ATH_BCBUF]; int slottime; int slotupdate; -- cgit v1.2.2 From cc24c86f7cc5de8938c32f15cd59bd425d21bb60 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:52 +0100 Subject: ath9k_htc: sync beacon slot code with ath9k we will need it for common-beacon Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc.h | 8 ++++++++ drivers/net/wireless/ath/ath9k/htc_drv_init.c | 1 + drivers/net/wireless/ath/ath9k/htc_drv_main.c | 19 +++++++++++++++---- 3 files changed, 24 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 707c5b418dc6..124dfedb0fd1 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -407,9 +407,17 @@ static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, #define MIN_SWBA_RESPONSE 10 /* in TUs */ 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]; u32 bmisscnt; u32 beaconq; + int slottime; + int slotupdate; }; struct ath_btcoex { diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 4b3b4dd49a42..8a3bd5fe3a54 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -520,6 +520,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) priv->beacon.bslot[i] = NULL; + priv->beacon.slottime = ATH9K_SLOT_TIME_9; ath9k_cmn_init_channels_rates(common); ath9k_cmn_init_crypto(ah); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index b82a7c43eb6e..f46cd0250e48 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1500,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); @@ -1575,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) -- cgit v1.2.2 From df728780d2ae2a47ffb9ce6486f0eb190d3371a6 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:53 +0100 Subject: ath9k: remove unused beacon_qi Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index d8dddce75da7..aa4f14444997 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -420,7 +420,6 @@ struct ath_beacon { 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; -- cgit v1.2.2 From c7303263a0ab2af8f7b6344db7e861c67bd7d29c Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:54 +0100 Subject: ath9k|ath9k_htc: move IEEE80211_MS_TO_TU to common Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/common.h | 2 ++ drivers/net/wireless/ath/ath9k/htc.h | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index aa4f14444997..44d74495c4de 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -403,7 +403,6 @@ 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)) diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index 26aafb394a5c..8deed82f741b 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -44,6 +44,8 @@ #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; diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 124dfedb0fd1..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)) -- cgit v1.2.2 From a2030b9dbce8db1261a0a7985217361a992a8949 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:55 +0100 Subject: ath9k-common: add nexttbtt and intval to ath_beacon_config Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/common.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index 8deed82f741b..eccc718e2b20 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -53,6 +53,8 @@ struct ath_beacon_config { u8 dtim_count; bool enable_beacon; bool ibss_creator; + u32 nexttbtt; + u32 intval; }; bool ath9k_cmn_rx_accept(struct ath_common *common, -- cgit v1.2.2 From cbbdf2ae2d67b333d7a4db5ce8b7391b3de1256d Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:56 +0100 Subject: ath9k: move ath9k_beacon_config_sta to common-beacon Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/Makefile | 3 +- drivers/net/wireless/ath/ath9k/beacon.c | 80 +--------------- drivers/net/wireless/ath/ath9k/common-beacon.c | 126 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/common-beacon.h | 21 +++++ drivers/net/wireless/ath/ath9k/common.h | 1 + 5 files changed, 153 insertions(+), 78 deletions(-) create mode 100644 drivers/net/wireless/ath/ath9k/common-beacon.c create mode 100644 drivers/net/wireless/ath/ath9k/common-beacon.h (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index b58fe99ef745..8e1c7b0fe76c 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -52,7 +52,8 @@ obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o ath9k_common-y:= common.o \ - common-init.o + common-init.o \ + common-beacon.o ath9k_htc-y += htc_hst.o \ hif_usb.o \ diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 637267187929..9333fa1c031f 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -505,87 +505,13 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc, ath9k_beacon_init(sc, nexttbtt, 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; - u32 nexttbtt = 0, 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"); + 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; - - /* - * 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. - */ - 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), - 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); - - /* Set the computed STA beacon timers */ ath9k_hw_disable_interrupts(ah); ath9k_hw_set_sta_beacon_timers(ah, &bs); @@ -777,7 +703,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..35cc9fddfb35 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-beacon.c @@ -0,0 +1,126 @@ +/* + * 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); 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..51cbcb5c4b9f --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-beacon.h @@ -0,0 +1,21 @@ +/* + * 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); diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index eccc718e2b20..ca38116838f0 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -22,6 +22,7 @@ #include "hw-ops.h" #include "common-init.h" +#include "common-beacon.h" /* Common header for Atheros 802.11n base driver cores */ -- cgit v1.2.2 From f84224402bddea8e2762869f4eaebc3b46be2aa0 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:57 +0100 Subject: ath9k_htc: use ath9k_cmn_beacon_config_sta Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 84 +------------------------ 1 file changed, 2 insertions(+), 82 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 9ff9e6e5df06..fc16c10549b1 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -62,97 +62,17 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) } } - 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; - int dtimperiod, dtimcount; - int bmiss_timeout; - u32 nexttbtt = 0, intval, tsftu; __be32 htc_imask = 0; - u64 tsf; - int num_beacons, offset, dtim_dec_count; int ret __attribute__ ((unused)); 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; - - /* - * 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. - */ - 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), - 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, 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 (ath9k_cmn_beacon_config_sta(priv->ah, bss_conf, &bs) == -EPERM) + return; WMI_CMD(WMI_DISABLE_INTR_CMDID); ath9k_hw_set_sta_beacon_timers(priv->ah, &bs); -- cgit v1.2.2 From 4c9a1f32600b9181558737dede31403c1ca05291 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:58 +0100 Subject: ath9k: move ath9k_beacon_config_adhoc to common Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/beacon.c | 21 ++------------------- drivers/net/wireless/ath/ath9k/common-beacon.c | 25 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/common-beacon.h | 2 ++ 3 files changed, 29 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 9333fa1c031f..01322a41e0fc 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -526,29 +526,12 @@ 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 diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.c b/drivers/net/wireless/ath/ath9k/common-beacon.c index 35cc9fddfb35..45bc899cbeb0 100644 --- a/drivers/net/wireless/ath/ath9k/common-beacon.c +++ b/drivers/net/wireless/ath/ath9k/common-beacon.c @@ -124,3 +124,28 @@ int ath9k_cmn_beacon_config_sta(struct ath_hw *ah, 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); diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.h b/drivers/net/wireless/ath/ath9k/common-beacon.h index 51cbcb5c4b9f..d8e7c0db08a9 100644 --- a/drivers/net/wireless/ath/ath9k/common-beacon.h +++ b/drivers/net/wireless/ath/ath9k/common-beacon.h @@ -19,3 +19,5 @@ 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); -- cgit v1.2.2 From 7f5c4c8320f853e17ec1c6dbb78d3753ba76a6cd Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:59 +0100 Subject: ath9k_htc: add ath9k_htc_beacon_init (but not use it) Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index fc16c10549b1..b9b03c1b4010 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -62,6 +62,28 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) } } +/* + * 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_hw *ah = priv->ah; + int ret __attribute__ ((unused)); + __be32 htc_imask = 0; + u8 cmd_rsp; + + WMI_CMD(WMI_DISABLE_INTR_CMDID); + 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_sta(struct ath9k_htc_priv *priv, struct ath_beacon_config *bss_conf) { -- cgit v1.2.2 From 4a4495a5fdf3f5d2e98446c94146dcaefb06a69b Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:16:00 +0100 Subject: ath9k_htc: use ath9k_htc_beacon_init in ath9k_htc_beacon_config_ap Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 31 +++++++++---------------- 1 file changed, 11 insertions(+), 20 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index b9b03c1b4010..b23231fea02c 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -107,22 +107,19 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, struct ath_beacon_config *bss_conf) { struct ath_common *common = ath9k_hw_common(priv->ah); - enum ath9k_int imask = 0; - u32 nexttbtt, intval, tsftu; - __be32 htc_imask = 0; + u32 tsftu; int ret __attribute__ ((unused)); - u8 cmd_rsp; u64 tsf; - intval = bss_conf->beacon_interval; - intval /= ATH9K_HTC_MAX_BCN_VIF; - nexttbtt = intval; + bss_conf->intval = bss_conf->beacon_interval; + bss_conf->intval /= ATH9K_HTC_MAX_BCN_VIF; + bss_conf->nexttbtt = bss_conf->intval; /* * To reduce beacon misses under heavy TX load, * set the beacon response time to a larger value. */ - if (intval > DEFAULT_SWBA_RESPONSE) + if (bss_conf->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; @@ -137,25 +134,19 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, tsf = ath9k_hw_gettsf64(priv->ah); tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE; do { - nexttbtt += intval; - } while (nexttbtt < tsftu); + bss_conf->nexttbtt += bss_conf->intval; + } while (bss_conf->nexttbtt < tsftu); } if (bss_conf->enable_beacon) - imask |= ATH9K_INT_SWBA; + priv->ah->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); + bss_conf->beacon_interval, bss_conf->nexttbtt, + priv->ah->config.sw_beacon_response_time, priv->ah->imask); - ath9k_htc_beaconq_config(priv); - - WMI_CMD(WMI_DISABLE_INTR_CMDID); - ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); - priv->beacon.bmisscnt = 0; - htc_imask = cpu_to_be32(imask); - WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); + ath9k_htc_beacon_init(priv, bss_conf, false); } static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, -- cgit v1.2.2 From f7197924d5187201e1a6e1617ad7a8c81f333330 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:16:01 +0100 Subject: ath9k_htc: use ath9k_htc_beacon_init in ath9k_htc_beacon_config_adhoc Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 31 ++++++++++--------------- 1 file changed, 12 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index b23231fea02c..81237155a1e0 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -152,16 +152,13 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, struct ath_beacon_config *bss_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; + struct ath_hw *ah = priv->ah; + struct ath_common *common = ath9k_hw_common(ah); + u32 tsftu; u64 tsf; - intval = bss_conf->beacon_interval; - nexttbtt = intval; + bss_conf->intval = bss_conf->beacon_interval; + bss_conf->nexttbtt = bss_conf->intval; /* * Pull nexttbtt forward to reflect the current TSF. @@ -169,30 +166,26 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, tsf = ath9k_hw_gettsf64(priv->ah); tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE; do { - nexttbtt += intval; - } while (nexttbtt < tsftu); + bss_conf->nexttbtt += bss_conf->intval; + } while (bss_conf->nexttbtt < tsftu); /* * Only one IBSS interfce is allowed. */ - if (intval > DEFAULT_SWBA_RESPONSE) + if (bss_conf->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 (bss_conf->enable_beacon) - imask |= ATH9K_INT_SWBA; + ah->imask = ATH9K_INT_SWBA; 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); + bss_conf->beacon_interval, bss_conf->nexttbtt, + priv->ah->config.sw_beacon_response_time, ah->imask); - WMI_CMD(WMI_DISABLE_INTR_CMDID); - ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); - priv->beacon.bmisscnt = 0; - htc_imask = cpu_to_be32(imask); - WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); + ath9k_htc_beacon_init(priv, bss_conf, bss_conf->ibss_creator); } void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, -- cgit v1.2.2 From 12f53c308ecbe2b76798a5091f8452eeed0a732b Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:16:02 +0100 Subject: ath9k_htc: use ath9k_cmn_beacon_config_adhoc Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 35 +++++-------------------- 1 file changed, 7 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 81237155a1e0..50937d014542 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -150,42 +150,21 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, } static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, - struct ath_beacon_config *bss_conf) + struct ath_beacon_config *conf) { struct ath_hw *ah = priv->ah; - struct ath_common *common = ath9k_hw_common(ah); - u32 tsftu; - u64 tsf; - - bss_conf->intval = bss_conf->beacon_interval; - bss_conf->nexttbtt = bss_conf->intval; - - /* - * Pull nexttbtt forward to reflect the current TSF. - */ - tsf = ath9k_hw_gettsf64(priv->ah); - tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE; - do { - bss_conf->nexttbtt += bss_conf->intval; - } while (bss_conf->nexttbtt < tsftu); + ah->imask = 0; + ath9k_cmn_beacon_config_adhoc(ah, conf); /* * Only one IBSS interfce is allowed. */ - if (bss_conf->intval > DEFAULT_SWBA_RESPONSE) - priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; + if (conf->intval >= TU_TO_USEC(DEFAULT_SWBA_RESPONSE)) + ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; else - priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; - - if (bss_conf->enable_beacon) - ah->imask = ATH9K_INT_SWBA; - - ath_dbg(common, CONFIG, - "IBSS Beacon config, intval: %d, nexttbtt: %u, resp_time: %d, imask: 0x%x\n", - bss_conf->beacon_interval, bss_conf->nexttbtt, - priv->ah->config.sw_beacon_response_time, ah->imask); + ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; - ath9k_htc_beacon_init(priv, bss_conf, bss_conf->ibss_creator); + ath9k_htc_beacon_init(priv, conf, conf->ibss_creator); } void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, -- cgit v1.2.2 From fa7b52fadbbbec855fb13ccc508128f6d234e08d Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:16:03 +0100 Subject: ath9k: move ath9k_beacon_config_ap common Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/beacon.c | 21 ++----------------- drivers/net/wireless/ath/ath9k/common-beacon.c | 29 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/common-beacon.h | 3 +++ 3 files changed, 34 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 01322a41e0fc..e1887438f8c5 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -483,26 +483,9 @@ 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); } static void ath9k_beacon_config_sta(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.c b/drivers/net/wireless/ath/ath9k/common-beacon.c index 45bc899cbeb0..775d1d20ce0b 100644 --- a/drivers/net/wireless/ath/ath9k/common-beacon.c +++ b/drivers/net/wireless/ath/ath9k/common-beacon.c @@ -149,3 +149,32 @@ void ath9k_cmn_beacon_config_adhoc(struct ath_hw *ah, 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 index d8e7c0db08a9..3665d27f0dc7 100644 --- a/drivers/net/wireless/ath/ath9k/common-beacon.h +++ b/drivers/net/wireless/ath/ath9k/common-beacon.h @@ -21,3 +21,6 @@ int ath9k_cmn_beacon_config_sta(struct ath_hw *ah, 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); -- cgit v1.2.2 From 6a77dd33fcfbfcf48f77fed599a0ce763e65a894 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:16:04 +0100 Subject: ath9k: remove unused ath9k_get_next_tbtt Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/beacon.c | 27 --------------------------- 1 file changed, 27 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index e1887438f8c5..471e0f624e81 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -447,33 +447,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 -- cgit v1.2.2 From 4b2d841f5bc3143f5a019b6a441c19bf2986bdf4 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:16:05 +0100 Subject: ath9k_htc: use ath9k_cmn_beacon_config_ap Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 43 +++++-------------------- 1 file changed, 8 insertions(+), 35 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 50937d014542..cbaf4e0429f0 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -104,49 +104,22 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, } static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, - struct ath_beacon_config *bss_conf) + struct ath_beacon_config *conf) { - struct ath_common *common = ath9k_hw_common(priv->ah); - u32 tsftu; - int ret __attribute__ ((unused)); - u64 tsf; - - bss_conf->intval = bss_conf->beacon_interval; - bss_conf->intval /= ATH9K_HTC_MAX_BCN_VIF; - bss_conf->nexttbtt = bss_conf->intval; + struct ath_hw *ah = priv->ah; + ah->imask = 0; + ath9k_cmn_beacon_config_ap(ah, conf, ATH9K_HTC_MAX_BCN_VIF); /* * To reduce beacon misses under heavy TX load, * set the beacon response time to a larger value. */ - if (bss_conf->intval > DEFAULT_SWBA_RESPONSE) - priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; + if (conf->intval >= TU_TO_USEC(DEFAULT_SWBA_RESPONSE)) + 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 { - bss_conf->nexttbtt += bss_conf->intval; - } while (bss_conf->nexttbtt < tsftu); - } - - if (bss_conf->enable_beacon) - priv->ah->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, bss_conf->nexttbtt, - priv->ah->config.sw_beacon_response_time, priv->ah->imask); + ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; - ath9k_htc_beacon_init(priv, bss_conf, false); + ath9k_htc_beacon_init(priv, conf, false); } static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, -- cgit v1.2.2 From 5f667642f4b290b04d88d5ca926fba81fed6180d Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:16:06 +0100 Subject: ath9k_htc: move DEFAULT_SWBA_RESPONSE check to ath9k_htc_beacon_init ... to remove some more dups. Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index cbaf4e0429f0..e8b6ec3c1dbb 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -74,6 +74,11 @@ static void ath9k_htc_beacon_init(struct ath9k_htc_priv *priv, __be32 htc_imask = 0; u8 cmd_rsp; + 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); if (reset_tsf) ath9k_hw_reset_tsf(ah); @@ -110,15 +115,6 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, ah->imask = 0; ath9k_cmn_beacon_config_ap(ah, conf, ATH9K_HTC_MAX_BCN_VIF); - /* - * To reduce beacon misses under heavy TX load, - * set the beacon response time to a larger value. - */ - 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; - ath9k_htc_beacon_init(priv, conf, false); } @@ -129,14 +125,6 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, ah->imask = 0; ath9k_cmn_beacon_config_adhoc(ah, conf); - /* - * Only one IBSS interfce is allowed. - */ - 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; - ath9k_htc_beacon_init(priv, conf, conf->ibss_creator); } -- cgit v1.2.2 From c08148bb7540c4547691c8fbe6db80edaf26cf10 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 17 Mar 2014 15:02:46 +0530 Subject: ath9k: Add QCA953x WMAC platform support Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ahb.c | 4 ++++ drivers/net/wireless/ath/ath9k/hw.c | 1 + 2 files changed, 5 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index a5684c38dcd9..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, + }, {}, }; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 2509c2ff0828..177cd16dfcec 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3048,6 +3048,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 */ -- cgit v1.2.2 From c90d4f7bc5b8595b86753d3c0b64259c3972b341 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 17 Mar 2014 15:02:47 +0530 Subject: ath9k: Disable AR_INTR_SYNC_HOST1_FATAL for QCA953x Along with AR9340 and AR955x, this is also needed for the QCA953x SoC. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 2 +- drivers/net/wireless/ath/ath9k/mac.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 177cd16dfcec..0992f7c70e1a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -882,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)) { 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; -- cgit v1.2.2 From d65b1278e314dc4023a70f338156d7b07941d93a Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 17 Mar 2014 15:02:48 +0530 Subject: ath9k: Fix temperature compensation The registers for temperature compensation need to be programmed only for active chains. Use the TX chainmask to make sure that this is done properly for QCA953x. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 59 +++++++++++++++----------- 1 file changed, 35 insertions(+), 24 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index d7625ecb6387..235053ba7737 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -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, -- cgit v1.2.2 From a70abea5f556778f6a670b08a278d60e0c993a3f Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:05 +0200 Subject: wil6210: Helpers to deal with 'cidxtid' fields Encode/decode helpers Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/txrx.c | 2 +- drivers/net/wireless/ath/wil6210/wil6210.h | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 092081e209da..7afaa5e5c42e 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -588,7 +588,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, diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 980dccc82b32..273d00f86130 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -125,6 +125,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 */ -- cgit v1.2.2 From e58c9f7043d9b85f867b361d0fa82451ddcf9846 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:06 +0200 Subject: wil6210: Block data till "data port open" reported When connection established, as reported by WMI_CONNECT_EVENTID, 4-way handshaking required for the secure connection is not done yet. It is indicated by another WMI event. Wait for it and only then allow data traffic. In case of non-secure connection, FW reports "data port open" immediately after connection. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 3 ++- drivers/net/wireless/ath/wil6210/main.c | 1 + drivers/net/wireless/ath/wil6210/txrx.c | 21 ++++++++++++++++++--- drivers/net/wireless/ath/wil6210/wil6210.h | 1 + drivers/net/wireless/ath/wil6210/wmi.c | 18 ++++++++++++++++-- 5 files changed, 38 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 1d09a4b0a0f4..ea868bea9e2e 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -631,7 +631,8 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data) status = "connected"; break; } - seq_printf(s, "[%d] %pM %s\n", i, p->addr, status); + 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++) { diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 41c362dee032..f10a0b2a99b2 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -59,6 +59,7 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid) uint i; struct wil_sta_info *sta = &wil->sta[cid]; + 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; diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 7afaa5e5c42e..29f13e01b99e 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -662,6 +662,10 @@ static struct vring *wil_find_tx_vring(struct wil6210_priv *wil, if (cid < 0) return NULL; + 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) { @@ -700,12 +704,19 @@ static struct vring *wil_tx_bcast(struct wil6210_priv *wil, struct vring *v, *v2; struct sk_buff *skb2; int i; + u8 cid; - /* find 1-st vring */ + /* find 1-st vring eligible for data */ for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { v = &wil->vring_tx[i]; - if (v->va) - goto found; + 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"); @@ -721,6 +732,10 @@ found: 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); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 273d00f86130..f06f71756996 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -321,6 +321,7 @@ 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)]; diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 24eed0963581..58c3afcf839d 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -550,9 +550,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); } @@ -560,10 +567,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); } -- cgit v1.2.2 From e83eb2fcae30aa8cc52e381c45fc161f877aa88d Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:07 +0200 Subject: wil6210: enable scan while connected New firmware do support scan while connected. Enable it. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 8 ++------ drivers/net/wireless/ath/wil6210/main.c | 2 -- 2 files changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 743930357061..b1bc00724cd2 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -282,7 +282,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; } @@ -402,10 +402,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)); @@ -414,7 +411,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); } diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index f10a0b2a99b2..4cc1b789bd1c 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -113,8 +113,6 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid) GFP_KERNEL); } clear_bit(wil_status_fwconnecting, &wil->status); - wil_dbg_misc(wil, "clear_bit(wil_status_dontscan)\n"); - clear_bit(wil_status_dontscan, &wil->status); break; default: /* AP-like interface and monitor: -- cgit v1.2.2 From c236658f1434a1e00ec1fec9054964bcaf3ddde7 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:08 +0200 Subject: wil6210: add scatter-gather support When setting fragmented skb for Tx, assign skb to the last descriptor and set number of fragments in the 1-st one On Tx complete, HW sets "DU" bit in Tx descriptor only for the last descriptor; so search for it using number of fragments field. Middle descriptors may have "DU" bit not set by the hardware. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 61 ++++++++++----- drivers/net/wireless/ath/wil6210/netdev.c | 5 +- drivers/net/wireless/ath/wil6210/txrx.c | 115 ++++++++++++++++++----------- drivers/net/wireless/ath/wil6210/wil6210.h | 1 + 4 files changed, 115 insertions(+), 67 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index ea868bea9e2e..ecdabe4adec3 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -398,6 +398,44 @@ static const struct file_operations fops_reset = { .open = simple_open, }; +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) { @@ -438,26 +476,9 @@ 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 { diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 717178f09aa8..5991802a6701 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; + ndev->features |= ndev->hw_features; SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); wdev->netdev = ndev; diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 29f13e01b99e..2eb545e3981f 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -774,6 +774,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) @@ -866,8 +873,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; @@ -883,6 +890,11 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, if (unlikely(dma_mapping_error(dev, pa))) goto dma_error; wil_tx_desc_map(d, pa, len, vring_index); + /* 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); vring->ctx[i].mapped_as_page = 1; *_d = *d; } @@ -1003,6 +1015,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int 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); @@ -1012,57 +1025,69 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) 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); + new_swtail = (lf + 1) % vring->size; + while (vring->swtail != new_swtail) { + struct vring_tx_desc dd, *d = ⅆ + dma_addr_t pa; + u16 dmalen; + struct wil_ctx *ctx = &vring->ctx[vring->swtail]; + struct sk_buff *skb = ctx->skb; + _d = &vring->va[vring->swtail].tx; - 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); + *d = *_d; - 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++; - } + 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); - dev_kfree_skb_any(skb); + 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++; + 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); + } + 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/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index f06f71756996..574f4d9af18b 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -214,6 +214,7 @@ struct pending_wmi_event { */ struct wil_ctx { struct sk_buff *skb; + u8 nr_frags; u8 mapped_as_page:1; }; -- cgit v1.2.2 From 2232abd59ae5801b20c1e8269a63515bac50d28d Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:09 +0200 Subject: wil6210: generalize tx desc mapping Introduce enum to describe mapping type; allow 'none' in addition to 'single' and 'page'; this is preparation for GSO Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/txrx.c | 52 +++++++++++++++--------------- drivers/net/wireless/ath/wil6210/wil6210.h | 8 ++++- 2 files changed, 33 insertions(+), 27 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 2eb545e3981f..41f88ee49bca 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); @@ -845,8 +854,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); @@ -864,6 +871,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 */ @@ -889,13 +897,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); /* 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); - vring->ctx[i].mapped_as_page = 1; *_d = *d; } /* for the last seg only */ @@ -924,7 +932,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; @@ -932,12 +939,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); @@ -983,6 +985,10 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) /* 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 */ @@ -1041,7 +1047,6 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) new_swtail = (lf + 1) % vring->size; while (vring->swtail != new_swtail) { struct vring_tx_desc dd, *d = ⅆ - dma_addr_t pa; u16 dmalen; struct wil_ctx *ctx = &vring->ctx[vring->swtail]; struct sk_buff *skb = ctx->skb; @@ -1059,12 +1064,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) 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); + wil_txdesc_unmap(dev, d, ctx); if (skb) { if (d->dma.error == 0) { diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 574f4d9af18b..11e0898bcffd 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -209,13 +209,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 nr_frags; - u8 mapped_as_page:1; + u8 mapped_as; }; union vring_desc; -- cgit v1.2.2 From 36b10a7239ce0d384a54ab1053d83b3bbb26501b Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:10 +0200 Subject: wil6210: update target reset to support new HW Support for new chip revision. Revision read from the internal register, PCIE config's "revision id" register do not indicate HW version properly Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/main.c | 29 ++++++++++++++++++++++++++++- drivers/net/wireless/ath/wil6210/pcie_bus.c | 2 ++ drivers/net/wireless/ath/wil6210/wil6210.h | 4 ++++ 3 files changed, 34 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 4cc1b789bd1c..86444189a2ec 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -230,14 +230,22 @@ void wil_priv_deinit(struct wil6210_priv *wil) static void wil_target_reset(struct wil6210_priv *wil) { + int delay = 100; + u32 baud_rate; + 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)) + wil->hw_version = R(RGF_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 */ @@ -257,11 +265,30 @@ static void wil_target_reset(struct wil6210_priv *wil) W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); 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_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); + /* wait until device ready. Use baud rate */ + do { + msleep(1); + baud_rate = R(RGF_USER_SERIAL_BAUD_RATE); + if (delay-- < 0) { + wil_err(wil, "Reset not completed\n"); + return; + } + } while (baud_rate != 0x15e); + + if (rev_id == 2) + W(RGF_LOS_COUNTER_CTL, BIT(8)); + wil_dbg_misc(wil, "Reset completed\n"); +#undef R #undef W #undef S } diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index eeceab39cda2..d96e81131132 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -74,6 +74,8 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) if (rc) goto release_irq; + wil_info(wil, "HW version: 0x%08x\n", wil->hw_version); + return 0; release_irq: diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 11e0898bcffd..14f861cd295d 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -74,6 +74,9 @@ struct RGF_ICR { } __packed; /* registers - FW addresses */ +#define RGF_FW_REV_ID (0x880a8c) /* chip revision */ +#define RGF_USER_SERIAL_BAUD_RATE (0x880050) +#define RGF_LOS_COUNTER_CTL (0x882dc4) #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) @@ -342,6 +345,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; -- cgit v1.2.2 From aa27deaabfa0c4a08cdb4d3209a13ab02695c186 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:11 +0200 Subject: wil6210: reduce dmesg pollution after FW crash When FW crashes, dmesg get polluted with the "FW not ready" error message. Print it only once per FW lifecycle Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/txrx.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 41f88ee49bca..5cda0ea9925f 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -956,11 +956,15 @@ 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)) { @@ -971,6 +975,7 @@ 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 */ if (is_unicast_ether_addr(eth->h_dest)) { -- cgit v1.2.2 From 98a65b59f8109cfafcc3c13b34895087b90dc630 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:12 +0200 Subject: wil6210: report reset time Useful to detect hardware problems Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 86444189a2ec..1f9f1d268eda 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -230,7 +230,7 @@ void wil_priv_deinit(struct wil6210_priv *wil) static void wil_target_reset(struct wil6210_priv *wil) { - int delay = 100; + int delay = 0; u32 baud_rate; u32 rev_id; @@ -277,7 +277,7 @@ static void wil_target_reset(struct wil6210_priv *wil) do { msleep(1); baud_rate = R(RGF_USER_SERIAL_BAUD_RATE); - if (delay-- < 0) { + if (delay++ > 100) { wil_err(wil, "Reset not completed\n"); return; } @@ -286,7 +286,7 @@ static void wil_target_reset(struct wil6210_priv *wil) if (rev_id == 2) W(RGF_LOS_COUNTER_CTL, BIT(8)); - wil_dbg_misc(wil, "Reset completed\n"); + wil_dbg_misc(wil, "Reset completed in %d ms\n", delay); #undef R #undef W -- cgit v1.2.2 From f4b5a8032d513a11ef919305048f00e812605318 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:13 +0200 Subject: wil6210: fix for HW bug in interrupt setup logic Hardware bug triggered by the MSI init while INTx asserted for some reason. De-assert INTx prior to MSI set-up Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/interrupt.c | 17 +++++++++++++++++ drivers/net/wireless/ath/wil6210/pcie_bus.c | 1 + drivers/net/wireless/ath/wil6210/wil6210.h | 1 + 3 files changed, 19 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 10919f95a83c..52c40e1d593a 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -493,6 +493,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/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index d96e81131132..c60976144db3 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -153,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/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 14f861cd295d..317621c49bf8 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -476,6 +476,7 @@ 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); -- cgit v1.2.2 From 171239912187fd6262c1bb40ff74ff2b4505938b Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:14 +0200 Subject: wil6210: sort HW registers definitions Put all registers in order for easier navigation; fix naming to reflect hardware cluster Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/main.c | 6 +++--- drivers/net/wireless/ath/wil6210/wil6210.h | 31 +++++++++++++++--------------- 2 files changed, 19 insertions(+), 18 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 1f9f1d268eda..bd27bee8241f 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -244,7 +244,7 @@ static void wil_target_reset(struct wil6210_priv *wil) #define S(a, v) iowrite32(ioread32(wil->csr + HOSTADDR(a)) | v, \ wil->csr + HOSTADDR(a)) - wil->hw_version = R(RGF_FW_REV_ID); + 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)); @@ -268,7 +268,7 @@ static void wil_target_reset(struct wil6210_priv *wil) if (rev_id == 1) { W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080); } else { - W(RGF_LOS_COUNTER_CTL, BIT(6) | BIT(8)); + 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); @@ -284,7 +284,7 @@ static void wil_target_reset(struct wil6210_priv *wil) } while (baud_rate != 0x15e); if (rev_id == 2) - W(RGF_LOS_COUNTER_CTL, BIT(8)); + W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8)); wil_dbg_misc(wil, "Reset completed in %d ms\n", delay); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 317621c49bf8..b376399e68ca 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -74,26 +74,18 @@ struct RGF_ICR { } __packed; /* registers - FW addresses */ -#define RGF_FW_REV_ID (0x880a8c) /* chip revision */ #define RGF_USER_SERIAL_BAUD_RATE (0x880050) -#define RGF_LOS_COUNTER_CTL (0x882dc4) -#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_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_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) @@ -108,13 +100,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) + \ -- cgit v1.2.2 From 972072aa7992634ec642bf41679a53b7aa060dd1 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:15 +0200 Subject: wil6210: reset on power good Configure hardware to perform full reset on "power good". This mean, reset HW on system boot. This improves card stability. By default this is off. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/main.c | 8 ++++++-- drivers/net/wireless/ath/wil6210/wil6210.h | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index bd27bee8241f..684762203a62 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -241,8 +241,9 @@ static void wil_target_reset(struct wil6210_priv *wil) /* 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; @@ -286,11 +287,14 @@ static void wil_target_reset(struct wil6210_priv *wil) if (rev_id == 2) W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8)); + C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); + 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) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index b376399e68ca..f7d8f0ead23e 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -79,6 +79,8 @@ struct RGF_ICR { #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) -- cgit v1.2.2 From fa4a18e73b21402ed00cfb852d94d169994c5aa3 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:16 +0200 Subject: wil6210: reduce printing Convert 2 often printed messages to dynamic ones Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index b1bc00724cd2..848ed8551f2c 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -179,7 +179,7 @@ static int wil_cfg80211_get_station(struct wiphy *wiphy, int cid = wil_find_cid(wil, mac); - wil_info(wil, "%s(%pM) CID %d\n", __func__, mac, cid); + wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid); if (cid < 0) return cid; @@ -218,7 +218,7 @@ static int wil_cfg80211_dump_station(struct wiphy *wiphy, return -ENOENT; memcpy(mac, wil->sta[cid].addr, ETH_ALEN); - wil_info(wil, "%s(%pM) CID %d\n", __func__, mac, cid); + wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid); rc = wil_cid_fill_sinfo(wil, cid, sinfo); -- cgit v1.2.2 From 8bf6adb988c6843f0e58d2b210526cf947a8a746 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:17 +0200 Subject: wil6210: fix memory leak in the AP flow When switching between STA and AP modes, memory allocated for Rx vring leaks This is because start_ap() allocates Rx vring but stop_ap() do not free it. Logically, Rx vring is not valid (HW can't use it anymore), so free it in reset() Also, check double init for Rx vring and bail out with -EINVAL Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/main.c | 2 ++ drivers/net/wireless/ath/wil6210/txrx.c | 5 +++++ 2 files changed, 7 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 684762203a62..de952ab78607 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -343,6 +343,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); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 5cda0ea9925f..97d036adb382 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -557,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) -- cgit v1.2.2 From 0fef1818d0888067f1231b05a08b2d56f017a169 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:18 +0200 Subject: wil6210: Fix kernel oops in reset flow wil_reset() removes vring's At the same time NAPI may be active performing Rx/Tx completion. If this happens, Rx/Tx polling functions going to access already removed vrings Make sure NAPI is idle and won't be started prior to vring removal. For this, track NAPI enabled state Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/interrupt.c | 15 ++++++++++++--- drivers/net/wireless/ath/wil6210/main.c | 9 ++++++++- drivers/net/wireless/ath/wil6210/wil6210.h | 1 + 3 files changed, 21 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 52c40e1d593a..201cf06ef5d8 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) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index de952ab78607..0831d4cd173b 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -329,11 +329,16 @@ int wil_reset(struct wil6210_priv *wil) { int rc; + wil->status = 0; /* prevent NAPI from being scheduled */ + if (test_bit(wil_status_napi_en, &wil->status)) { + napi_synchronize(&wil->napi_rx); + napi_synchronize(&wil->napi_tx); + } + cancel_work_sync(&wil->disconnect_worker); wil6210_disconnect(wil, NULL); wil6210_disable_irq(wil); - wil->status = 0; wmi_event_flush(wil); @@ -426,6 +431,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; } @@ -443,6 +449,7 @@ int wil_up(struct wil6210_priv *wil) static int __wil_down(struct wil6210_priv *wil) { + clear_bit(wil_status_napi_en, &wil->status); napi_disable(&wil->napi_rx); napi_disable(&wil->napi_tx); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index f7d8f0ead23e..89cbdc35b3e4 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -249,6 +249,7 @@ 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; -- cgit v1.2.2 From ed6f9dc62f72df5710cf86279d3304319d049291 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:19 +0200 Subject: wil6210: fw error recovery upon fw error interrupt - in STA mode, disconnect/cancel scan and then reset FW/HW added module param - no_fw_recovery which is false by default Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 8 ++++- drivers/net/wireless/ath/wil6210/interrupt.c | 1 + drivers/net/wireless/ath/wil6210/main.c | 48 ++++++++++++++++++++++++++++ drivers/net/wireless/ath/wil6210/wil6210.h | 2 ++ 4 files changed, 58 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 848ed8551f2c..f6a12e7f80be 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -265,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"); @@ -305,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, diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 201cf06ef5d8..5824cd41e4ba 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -328,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) { diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 0831d4cd173b..32ac1b906abe 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -21,6 +21,10 @@ #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, * one has to read/write to/from NIC in 32-bit chunks; @@ -144,6 +148,36 @@ 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; + + 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; + } +} + static int wil_find_free_vring(struct wil6210_priv *wil) { int i; @@ -196,6 +230,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); @@ -222,6 +257,7 @@ 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); wil6210_disconnect(wil, NULL); wmi_event_flush(wil); destroy_workqueue(wil->wmi_wq_conn); @@ -335,6 +371,13 @@ int wil_reset(struct wil6210_priv *wil) napi_synchronize(&wil->napi_tx); } + 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; + } + cancel_work_sync(&wil->disconnect_worker); wil6210_disconnect(wil, NULL); @@ -363,6 +406,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) { diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 89cbdc35b3e4..80573f786df6 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -370,6 +370,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; @@ -447,6 +448,7 @@ 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); -- cgit v1.2.2 From 4cd9e8377f6f18ffabad2cf0967855432db3dbce Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:20 +0200 Subject: wil6210: fix secondary connect when STA receiving connect() when already connected, it should return error Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index f6a12e7f80be..597540a307d8 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -327,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); -- cgit v1.2.2 From 9c3bde56b7e6403a9f86b63bb02c9a5cb74456fa Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:21 +0200 Subject: wil6210: serialize fw_recovery and start_ap These methods can change device state, serialize with others similar ones like up/down Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 15 +++++++++++---- drivers/net/wireless/ath/wil6210/main.c | 2 ++ 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 597540a307d8..ed5a7e145027 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -609,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); @@ -644,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; } @@ -658,8 +662,11 @@ 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; } diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 32ac1b906abe..351925b5d2c8 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -159,6 +159,7 @@ static void wil_fw_error_worker(struct work_struct *work) if (no_fw_recovery) return; + mutex_lock(&wil->mutex); switch (wdev->iftype) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: @@ -176,6 +177,7 @@ static void wil_fw_error_worker(struct work_struct *work) default: break; } + mutex_unlock(&wil->mutex); } static int wil_find_free_vring(struct wil6210_priv *wil) -- cgit v1.2.2 From b5998e6a3d695c9261a1b1d9cf27db526aa72b3b Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:22 +0200 Subject: wil6210: use GRO GRO is easy to enable when already using NAPI framework, and it improves CPU utilisation. Enable it by default. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/netdev.c | 2 +- drivers/net/wireless/ath/wil6210/txrx.c | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 5991802a6701..fdcaeb820e75 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -128,7 +128,7 @@ 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 | - NETIF_F_SG; + 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/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 97d036adb382..cfd36cc0336b 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -488,7 +488,7 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count) */ 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); @@ -497,17 +497,17 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) 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; stats->rx_bytes += len; - - } else { - ndev->stats.rx_dropped++; - stats->rx_dropped++; } } -- cgit v1.2.2 From d28bcc302678e3c2932c4e4e73cd4f40ca4c5fc0 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:23 +0200 Subject: wil6210: target reset flow update Use 'real' indication for hardware state. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/main.c | 11 ++++++----- drivers/net/wireless/ath/wil6210/wil6210.h | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 351925b5d2c8..c782e2522d38 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -269,7 +269,7 @@ void wil_priv_deinit(struct wil6210_priv *wil) static void wil_target_reset(struct wil6210_priv *wil) { int delay = 0; - u32 baud_rate; + u32 hw_state; u32 rev_id; wil_dbg_misc(wil, "Resetting...\n"); @@ -312,15 +312,16 @@ static void wil_target_reset(struct wil6210_priv *wil) } W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); - /* wait until device ready. Use baud rate */ + /* wait until device ready */ do { msleep(1); - baud_rate = R(RGF_USER_SERIAL_BAUD_RATE); + hw_state = R(RGF_USER_HW_MACHINE_STATE); if (delay++ > 100) { - wil_err(wil, "Reset not completed\n"); + wil_err(wil, "Reset not completed, hw_state 0x%08x\n", + hw_state); return; } - } while (baud_rate != 0x15e); + } while (hw_state != HW_MACHINE_BOOT_DONE); if (rev_id == 2) W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8)); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 80573f786df6..fb1006b2a4e2 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -74,7 +74,8 @@ struct RGF_ICR { } __packed; /* registers - FW addresses */ -#define RGF_USER_SERIAL_BAUD_RATE (0x880050) +#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) -- cgit v1.2.2 From 260e695196de8b91bbab482d3804e4e0312a59b6 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:24 +0200 Subject: wil6210: add memory barriers for the reset flow make sure reset flow executed in order Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index c782e2522d38..0005d9b90772 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -289,19 +289,23 @@ static void wil_target_reset(struct wil6210_priv *wil) 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); if (rev_id == 1) { @@ -311,6 +315,7 @@ static void wil_target_reset(struct wil6210_priv *wil) 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 { @@ -327,6 +332,7 @@ static void wil_target_reset(struct wil6210_priv *wil) 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 in %d ms\n", delay); -- cgit v1.2.2 From 097638a08acde0320c44969a5dff3af105c341a0 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:25 +0200 Subject: wil6210: fix race between disconnect and Tx NAPI When disconnecting some CID, corresponded Tx vring get released. During vring release, all descriptors get freed. It is possible that Tx NAPI working on the same vring simultaneously. If it happens, descriptor may be double freed. To protect from the race above, make sure NAPI won't process the same vring. Introduce 'enabled' flag in the struct vring_tx_data. Proceed with Tx NAPI only if 'enabled' flag set. Prior to Tx vring release, clear this flag and make sure NAPI get synchronized. NAPI enablement status protected by wil->mutex, add protection where it was missing and check for it. During reset, disconnect all peers first, then proceed with the Rx vring. It allows for the disconnect flow to observe proper 'wil->status' and correctly notify cfg80211 about connection status change Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 4 ++++ drivers/net/wireless/ath/wil6210/main.c | 17 +++++++++++++---- drivers/net/wireless/ath/wil6210/pcie_bus.c | 2 ++ drivers/net/wireless/ath/wil6210/txrx.c | 17 +++++++++++++++++ drivers/net/wireless/ath/wil6210/wil6210.h | 9 +++++++++ drivers/net/wireless/ath/wil6210/wmi.c | 2 ++ 6 files changed, 47 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index ed5a7e145027..4806a49cb61b 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -674,7 +674,11 @@ 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; } diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 0005d9b90772..95f4efe9ef37 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -133,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) @@ -260,7 +262,9 @@ 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); @@ -374,10 +378,14 @@ 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); - napi_synchronize(&wil->napi_tx); } if (wil->scan_request) { @@ -387,9 +395,6 @@ int wil_reset(struct wil6210_priv *wil) wil->scan_request = NULL; } - cancel_work_sync(&wil->disconnect_worker); - wil6210_disconnect(wil, NULL); - wil6210_disable_irq(wil); wmi_event_flush(wil); @@ -447,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; @@ -506,6 +513,8 @@ 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); diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index c60976144db3..58fc0962e2e2 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -70,7 +70,9 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) 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; diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index cfd36cc0336b..c8c547457eb4 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -618,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); @@ -625,6 +626,7 @@ 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) @@ -648,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); @@ -660,9 +664,16 @@ 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); } @@ -1028,6 +1039,7 @@ 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; @@ -1038,6 +1050,11 @@ int wil_tx_complete(struct wil6210_priv *wil, int 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)) { diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index fb1006b2a4e2..2a2dec75f026 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -243,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, @@ -386,6 +394,7 @@ struct wil6210_priv { /* DMA related */ struct vring vring_rx; struct vring vring_tx[WIL6210_MAX_TX_RINGS]; + 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 */ diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 58c3afcf839d..2ba56eef0c45 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -462,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) -- cgit v1.2.2