Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [PATCH 3/4] ath9k: check for deaf rx path state
From: Felix Fietkau @ 2017-01-26 10:02 UTC (permalink / raw)
  To: Simon Wunderlich; +Cc: linux-wireless, kvalo
In-Reply-To: <4839692.lfma8z9lJt@prime>

On 2017-01-26 10:50, Simon Wunderlich wrote:
> Hey Felix,
> 
> 
> On Wednesday, January 25, 2017 5:36:53 PM CET Felix Fietkau wrote:
>> Various chips occasionally run into a state where the tx path still
>> appears to be working normally, but the rx path is deaf.
>> 
>> There is no known register signature to check for this state explicitly,
>> so use the lack of rx interrupts as an indicator.
>> 
>> This detection is prone to false positives, since a device could also
>> simply be in an environment where there are no frames on the air.
>> However, in this case doing a reset should be harmless since it's
>> obviously not interrupting any real activity. To avoid confusion, call
>> the reset counters in this case "Rx path inactive" instead of something
>> like "Rx path deaf", since it may not be an indication of a real
>> hardware failure.
>> 
>> Signed-off-by: Felix Fietkau <nbd@nbd.name>
> 
> As we observed in the field, it may happen that there are still RX interrupts 
> triggered, but just a very low number - in which case I believe your version 
> wouldn't fix the problem. Therefore we had a threshold in our original patch 
> [1].
It seems that you were seeing something different than what I was seeing
in my tests. Though it could be that my issues were actually caused by
something else. I had queued up these changes a while back before I
finally found and fixed the IRQ issue.

> We would also appreciate if you can at least briefly mention our work if you 
> resend/rework our stuff.
Sorry about that. I rebased this from older experimental patches and
forgot to put in all the relevant context.

Kalle, please drop this change for now.

- Felix

^ permalink raw reply

* Re: [PATCH 3/4] ath9k: check for deaf rx path state
From: Simon Wunderlich @ 2017-01-26  9:50 UTC (permalink / raw)
  To: Felix Fietkau; +Cc: linux-wireless, kvalo
In-Reply-To: <20170125163654.66431-3-nbd@nbd.name>

[-- Attachment #1: Type: text/plain, Size: 1248 bytes --]

Hey Felix,


On Wednesday, January 25, 2017 5:36:53 PM CET Felix Fietkau wrote:
> Various chips occasionally run into a state where the tx path still
> appears to be working normally, but the rx path is deaf.
> 
> There is no known register signature to check for this state explicitly,
> so use the lack of rx interrupts as an indicator.
> 
> This detection is prone to false positives, since a device could also
> simply be in an environment where there are no frames on the air.
> However, in this case doing a reset should be harmless since it's
> obviously not interrupting any real activity. To avoid confusion, call
> the reset counters in this case "Rx path inactive" instead of something
> like "Rx path deaf", since it may not be an indication of a real
> hardware failure.
> 
> Signed-off-by: Felix Fietkau <nbd@nbd.name>

As we observed in the field, it may happen that there are still RX interrupts 
triggered, but just a very low number - in which case I believe your version 
wouldn't fix the problem. Therefore we had a threshold in our original patch 
[1].

We would also appreciate if you can at least briefly mention our work if you 
resend/rework our stuff.

Thank you,
    Simon

[1] https://patchwork.kernel.org/patch/9433621/

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply

* Re: [RFC 3/3] cfg80211: Share Channel DFS state across wiphys of same DFS domain
From: Johannes Berg @ 2017-01-26  9:41 UTC (permalink / raw)
  To: Vasanthakumar Thiagarajan; +Cc: linux-wireless
In-Reply-To: <1485343870-23601-4-git-send-email-vthiagar@qti.qualcomm.com>

On Wed, 2017-01-25 at 17:01 +0530, Vasanthakumar Thiagarajan wrote:
> Sharing DFS channel state across multiple wiphys (radios) could
> be useful with multiple radios on the system. When one radio
> completes CAC and marks the channel available another radio
> can use this information and start beaconing without really doing
> CAC.
> 
> Whenever there is a state change in DFS channel associated to
> a particular wiphy the the same state change is propagated to
> other wiphys having the same DFS reg domain configuration.
> Also when a new wiphy is created the DFS channel state of
> other existing wiphys of same DFS domain is copied.
> 
> Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>
> ---
>  net/wireless/chan.c |  24 +++++++++--
>  net/wireless/core.c |  37 +++++++++++++++++
>  net/wireless/core.h |   6 +++
>  net/wireless/mlme.c |  11 +++++-
>  net/wireless/reg.c  | 112
> ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  net/wireless/reg.h  |  22 +++++++++++
>  6 files changed, 207 insertions(+), 5 deletions(-)
> 
> diff --git a/net/wireless/chan.c b/net/wireless/chan.c
> index 090309a..40f1097 100644
> --- a/net/wireless/chan.c
> +++ b/net/wireless/chan.c
> @@ -532,21 +532,37 @@ bool cfg80211_beaconing_iface_active(struct
> wireless_dev *wdev)
>  	return active;
>  }
>  
> +static bool cfg80211_5ghz_is_wiphy_oper_chan(struct wiphy *wiphy,
> +					     struct
> ieee80211_channel *chan)

again, nothing really 5 GHz specific here, afaict?

> +	struct wireless_dev *wdev;
> +
> +	list_for_each_entry(wdev, &wiphy->wdev_list, list) {
> +		if (!cfg80211_beaconing_iface_active(wdev))
> +			continue;
> +
> +		if (cfg80211_5ghz_sub_chan(&wdev->chandef, chan))
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
>  bool cfg80211_5ghz_any_wiphy_oper_chan(struct wiphy *wiphy,
>  				       struct ieee80211_channel
> *chan)
>  {
> -	struct wireless_dev *wdev;
> +	struct cfg80211_registered_device *rdev;
>  
>  	ASSERT_RTNL();
>  
>  	if (!(chan->flags & IEEE80211_CHAN_RADAR))
>  		return false;
>  
> -	list_for_each_entry(wdev, &wiphy->wdev_list, list) {
> -		if (!cfg80211_beaconing_iface_active(wdev))
> +	list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
> +		if (!reg_dfs_domain_same(wiphy, &rdev->wiphy))
>  			continue;
>  
> -		if (cfg80211_5ghz_sub_chan(&wdev->chandef, chan))
> +		if (cfg80211_5ghz_is_wiphy_oper_chan(&rdev->wiphy,
> chan))
>  			return true;
>  	}
>  
> diff --git a/net/wireless/core.c b/net/wireless/core.c
> index 903fc419..c3fe44b 100644
> --- a/net/wireless/core.c
> +++ b/net/wireless/core.c
> @@ -357,6 +357,38 @@ static void cfg80211_sched_scan_stop_wk(struct
> work_struct *work)
>  	rtnl_unlock();
>  }
>  
> +static void cfg80211_propagate_radar_detect_wk(struct work_struct
> *work)
> +{
> +	struct cfg80211_registered_device *rdev;
> +
> +	rdev = container_of(work, struct cfg80211_registered_device,
> +			    porpagate_radar_detect_wk);
> +
> +	rtnl_lock();
> +
> +	regulatory_propagate_dfs_state(&rdev->wiphy, &rdev-
> >radar_chandef,
> +				       NL80211_DFS_UNAVAILABLE,
> +				       NL80211_RADAR_DETECTED);
> +
> +	rtnl_unlock();
> +}
> +
> +static void cfg80211_propagate_cac_done_wk(struct work_struct *work)
> +{
> +	struct cfg80211_registered_device *rdev;
> +
> +	rdev = container_of(work, struct cfg80211_registered_device,
> +			    propagate_cac_done_wk);
> +
> +	rtnl_lock();
> +
> +	regulatory_propagate_dfs_state(&rdev->wiphy, &rdev-
> >cac_done_chandef,
> +				       NL80211_DFS_AVAILABLE,
> +				       NL80211_RADAR_CAC_FINISHED);
> +
> +	rtnl_unlock();
> +}
> +
>  /* exported functions */
>  
>  struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int
> sizeof_priv,
> @@ -456,6 +488,9 @@ struct wiphy *wiphy_new_nm(const struct
> cfg80211_ops *ops, int sizeof_priv,
>  	spin_lock_init(&rdev->destroy_list_lock);
>  	INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk);
>  	INIT_WORK(&rdev->sched_scan_stop_wk,
> cfg80211_sched_scan_stop_wk);
> +	INIT_WORK(&rdev->porpagate_radar_detect_wk,
> +		  cfg80211_propagate_radar_detect_wk);
> +	INIT_WORK(&rdev->propagate_cac_done_wk,
> cfg80211_propagate_cac_done_wk);
>  
>  #ifdef CONFIG_CFG80211_DEFAULT_PS
>  	rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
> @@ -914,6 +949,8 @@ void wiphy_unregister(struct wiphy *wiphy)
>  	flush_work(&rdev->destroy_work);
>  	flush_work(&rdev->sched_scan_stop_wk);
>  	flush_work(&rdev->mlme_unreg_wk);
> +	flush_work(&rdev->porpagate_radar_detect_wk);

typo: propagate.

> +	flush_work(&rdev->propagate_cac_done_wk);

You got it right here :)
 
>  #ifdef CONFIG_PM
>  	if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
> diff --git a/net/wireless/core.h b/net/wireless/core.h
> index 327fe95..607c8be 100644
> --- a/net/wireless/core.h
> +++ b/net/wireless/core.h
> @@ -97,6 +97,12 @@ struct cfg80211_registered_device {
>  
>  	struct work_struct sched_scan_stop_wk;
>  
> +	struct cfg80211_chan_def radar_chandef;
> +	struct work_struct porpagate_radar_detect_wk;

Since it compiled, the typo exists everywhere this is referenced.

> +++ b/net/wireless/mlme.c
> @@ -18,7 +18,6 @@
>  #include "nl80211.h"
>  #include "rdev-ops.h"
>  
> -
>  void cfg80211_rx_assoc_resp(struct net_device *dev, struct
> cfg80211_bss *bss,

please don't make unrelated "cleanups".

> +bool reg_dfs_domain_same(struct wiphy *wiphy1, struct wiphy *wiphy2)
> +{
> +	const struct ieee80211_regdomain *wiphy1_regd = NULL;
> +	const struct ieee80211_regdomain *wiphy2_regd = NULL;
> +	const struct ieee80211_regdomain *cfg80211_regd = NULL;
> +	bool dfs_domain_same = false;

You can remove that initializer,

> +	rcu_read_lock();
> +
> +	cfg80211_regd = rcu_dereference(cfg80211_regdomain);
> +	wiphy1_regd = rcu_dereference(wiphy1->regd);
> +	if (!wiphy1_regd)
> +		wiphy1_regd = cfg80211_regd;
> +
> +	wiphy2_regd = rcu_dereference(wiphy2->regd);
> +	if (!wiphy2_regd)
> +		wiphy2_regd = cfg80211_regd;
> +
> +	if (wiphy1_regd->dfs_region == wiphy2_regd->dfs_region)
> +		dfs_domain_same = true;

and just assign
	dfs_domain_same = wiphy1... == wiphy2...;

> +static void wiphy_share_dfs_chan_state(struct wiphy *dst_wiphy,
> +				       struct wiphy *src_wiphy)
> +{
> +	struct ieee80211_supported_band *src_sband, *dst_sband;
> +	int i, j;
> +
> +	dst_sband = dst_wiphy->bands[NL80211_BAND_5GHZ];
> +	src_sband = src_wiphy->bands[NL80211_BAND_5GHZ];
> +	if (!dst_sband || !src_sband)
> +		return;

Why make this 5 GHz specific? Perhaps some kind of radar stuff will
exist in future bands too. It shouldn't really cost much to iterate all
the bands, I think?

johannes

^ permalink raw reply

* Re: [RFC 2/3] cfg80211: Disallow moving out of operating DFS channel in non-ETSI
From: Johannes Berg @ 2017-01-26  9:36 UTC (permalink / raw)
  To: Vasanthakumar Thiagarajan; +Cc: linux-wireless
In-Reply-To: <1485343870-23601-3-git-send-email-vthiagar@qti.qualcomm.com>


> +static bool cfg80211_off_channel_oper_allowed(struct wireless_dev
> *wdev)
> +{
> +	if (!cfg80211_beaconing_iface_active(wdev))
> +		return true;
> +
> +	if (!(wdev->chandef.chan->flags & IEEE80211_CHAN_RADAR))
> +		return true;

That could use some locking assertions. Maybe also in the
cfg80211_beaconing_iface_active() function you introduced in the
previous patch.

> +	if (!cfg80211_off_channel_oper_allowed(wdev)) {
> +		struct ieee80211_channel *chan;
> +
> +		if (request->n_channels != 1) {
> +			err = -EBUSY;
> +			goto out_free;
> +		}
> +
> +		chan = request->channels[0];
> +		if (chan->center_freq != wdev->chandef.chan-
> >center_freq) {
> +			err = -EBUSY;
> +			goto out_free;
> +		}
> +	}

I'm not convinced you even hold the relevant locks here, though off the
top of my head I'm not even sure which are needed.

>  	i = 0;
>  	if (n_ssids) {
>  		nla_for_each_nested(attr, info-
> >attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
> @@ -9053,6 +9079,7 @@ static int nl80211_remain_on_channel(struct
> sk_buff *skb,
>  	struct cfg80211_registered_device *rdev = info->user_ptr[0];
>  	struct wireless_dev *wdev = info->user_ptr[1];
>  	struct cfg80211_chan_def chandef;
> +	const struct cfg80211_chan_def *compat_chandef;
>  	struct sk_buff *msg;
>  	void *hdr;
>  	u64 cookie;
> @@ -9081,6 +9108,14 @@ static int nl80211_remain_on_channel(struct
> sk_buff *skb,
>  	if (err)
>  		return err;
>  
> +	if (!(cfg80211_off_channel_oper_allowed(wdev) ||
> +	      cfg80211_chandef_identical(&wdev->chandef, &chandef)))

I'd prefer to write that as !off_channel && !chandef_identical, seems
easier to understand here.

johannes

^ permalink raw reply

* Re: [RFC 1/3] cfg80211: Make pre-CAC results valid only for ETSI domain
From: Johannes Berg @ 2017-01-26  9:34 UTC (permalink / raw)
  To: Vasanthakumar Thiagarajan; +Cc: linux-wireless
In-Reply-To: <1485343870-23601-2-git-send-email-vthiagar@qti.qualcomm.com>


> +		/* Should we apply the grace period during beaconing
> interface
> +		 * shutdown also?
> +		 */
> +		cfg80211_sched_dfs_chan_update(rdev);

It might make some sense, say if hostapd crashes and you restart it
automatically or something?

>  	return err;
> diff --git a/net/wireless/chan.c b/net/wireless/chan.c
> index 5497d022..090309a 100644
> --- a/net/wireless/chan.c
> +++ b/net/wireless/chan.c
> @@ -456,6 +456,102 @@ bool cfg80211_chandef_dfs_usable(struct wiphy
> *wiphy,
>  	return (r1 + r2 > 0);
>  }
>  
> +static bool cfg80211_5ghz_sub_chan(struct cfg80211_chan_def
> *chandef,
> +				   struct ieee80211_channel *chan)

This could use some explanation, and I don't see anything that's really
5 GHz specific in here, so why that in the function name?

> +	u32 start_freq_seg0 = 0, end_freq_seg0 = 0;
> +	u32 start_freq_seg1 = 0, end_freq_seg1 = 0;
> +
> +	if (chandef->chan->center_freq == chan->center_freq)
> +		return true;
> +
> +	switch (chandef->width) {
> +	case NL80211_CHAN_WIDTH_40:
> +		start_freq_seg0 = chandef->center_freq1 - 20;
> +		end_freq_seg0 = chandef->center_freq1 + 20;
> +		break;
> +	case NL80211_CHAN_WIDTH_80P80:
> +		start_freq_seg1 = chandef->center_freq2 - 40;
> +		end_freq_seg1 = chandef->center_freq2 + 40;
> +		/* fall through */
> +	case NL80211_CHAN_WIDTH_80:
> +		start_freq_seg0 = chandef->center_freq1 - 40;
> +		end_freq_seg0 = chandef->center_freq1 + 40;
> +		break;
> +	case NL80211_CHAN_WIDTH_160:
> +		start_freq_seg0 = chandef->center_freq1 - 80;
> +		end_freq_seg0 = chandef->center_freq1 + 80;
> +		break;
> +	case NL80211_CHAN_WIDTH_20_NOHT:
> +	case NL80211_CHAN_WIDTH_20:
> +	case NL80211_CHAN_WIDTH_5:
> +	case NL80211_CHAN_WIDTH_10:
> +		break;
> +	}
> +
> +	if (chan->center_freq > start_freq_seg0 &&
> +	    chan->center_freq < end_freq_seg0)
> +		return true;
> +
> +	return chan->center_freq > start_freq_seg1 &&
> +		chan->center_freq < end_freq_seg1;
> +}

It's also written pretty oddly... The 5/10/20 cases could return
immediately, the start/end could be replaced by width, and the
initializations wouldn't be needed at all ... I think we can do better
here.

> +bool cfg80211_5ghz_any_wiphy_oper_chan(struct wiphy *wiphy,
> +				       struct ieee80211_channel
> *chan)

Again, nothing 5 GHz specific.

> +	struct wireless_dev *wdev;
> +
> +	ASSERT_RTNL();
> +
> +	if (!(chan->flags & IEEE80211_CHAN_RADAR))
> +		return false;
> +
> +	list_for_each_entry(wdev, &wiphy->wdev_list, list) {
> +		if (!cfg80211_beaconing_iface_active(wdev))
> +			continue;
> +
> +		if (cfg80211_5ghz_sub_chan(&wdev->chandef, chan))
> +			return true;
> +	}
> +
> +	return false;
> +}
>  
>  static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
>  					     u32 center_freq,
> diff --git a/net/wireless/core.h b/net/wireless/core.h
> index 58ca206..327fe95 100644
> --- a/net/wireless/core.h
> +++ b/net/wireless/core.h
> @@ -459,6 +459,13 @@ void cfg80211_set_dfs_state(struct wiphy *wiphy,
>  cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
>  			      const struct cfg80211_chan_def
> *chandef);
>  
> +void cfg80211_sched_dfs_chan_update(struct
> cfg80211_registered_device *rdev);
> +
> +bool cfg80211_5ghz_any_wiphy_oper_chan(struct wiphy *wiphy,
> +				       struct ieee80211_channel
> *chan);
> +
> +bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev);
> +
>  static inline unsigned int elapsed_jiffies_msecs(unsigned long
> start)
>  {
>  	unsigned long end = jiffies;
> diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
> index 364f900..10bf040 100644
> --- a/net/wireless/ibss.c
> +++ b/net/wireless/ibss.c
> @@ -190,6 +190,7 @@ static void __cfg80211_clear_ibss(struct
> net_device *dev, bool nowext)
>  	if (!nowext)
>  		wdev->wext.ibss.ssid_len = 0;
>  #endif
> +	cfg80211_sched_dfs_chan_update(rdev);
>  }
>  
>  void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
> diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
> index 2d8518a..ec0b1c2 100644
> --- a/net/wireless/mesh.c
> +++ b/net/wireless/mesh.c
> @@ -262,6 +262,7 @@ int __cfg80211_leave_mesh(struct
> cfg80211_registered_device *rdev,
>  		wdev->beacon_interval = 0;
>  		memset(&wdev->chandef, 0, sizeof(wdev->chandef));
>  		rdev_set_qos_map(rdev, dev, NULL);
> +		cfg80211_sched_dfs_chan_update(rdev);
>  	}
>  
>  	return err;
> diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
> index 22b3d99..3c7e155 100644
> --- a/net/wireless/mlme.c
> +++ b/net/wireless/mlme.c
> @@ -745,6 +745,12 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev,
> int freq, int sig_mbm,
>  }
>  EXPORT_SYMBOL(cfg80211_rx_mgmt);
>  
> +void cfg80211_sched_dfs_chan_update(struct
> cfg80211_registered_device *rdev)
> +{
> +	cancel_delayed_work(&rdev->dfs_update_channels_wk);
> +	queue_delayed_work(cfg80211_wq, &rdev-
> >dfs_update_channels_wk, 0);
> +}

This uses 0.

> @@ -820,9 +844,7 @@ void cfg80211_radar_event(struct wiphy *wiphy,
>  	 */
>  	cfg80211_set_dfs_state(wiphy, chandef,
> NL80211_DFS_UNAVAILABLE);
>  
> -	timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_NOP_TIME_MS);
> -	queue_delayed_work(cfg80211_wq, &rdev-
> >dfs_update_channels_wk,
> -			   timeout);
> +	cfg80211_sched_dfs_chan_update(rdev);

But this didn't - why does that change?

> +unsigned long regulatory_get_pre_cac_timeout(struct wiphy *wiphy)
> +{
> +	if (!regulatory_pre_cac_allowed(wiphy))
> +		return REG_PRE_CAC_EXPIRY_GRACE_MS;
> +
> +	/*
> +	 * Return the maximum pre-CAC timeout when pre-CAC is
> allowed
> +	 * in the current dfs domain (ETSI).
> +	 */
> +	return -1;
> +}

Don't ever return -1, that's -EPERM and not really what you want
anyway.

In fact, this doesn't even make sense, since the only caller already
checks regulatory_pre_cac_allowed() before calling this.

johannes

^ permalink raw reply

* Re: [PATCH 1/2] mac80211: use helper function to access ieee802_1d_to_ac[]
From: Johannes Berg @ 2017-01-26  8:51 UTC (permalink / raw)
  To: Amadeusz Sławiński, linux-wireless
  Cc: David S. Miller, netdev, linux-kernel
In-Reply-To: <1485272531-11587-1-git-send-email-amadeusz.slawinski@tieto.com>

On Tue, 2017-01-24 at 16:42 +0100, Amadeusz Sławiński wrote:
> cleanup patch to make use of ieee80211_ac_from_tid() to retrieve ac
> from
> ieee802_1d_to_ac[]

Applied.

johannes

^ permalink raw reply

* [PATCH v2] iwlwifi: allow memory debug TLV to specify the memory type
From: Luca Coelho @ 2017-01-26  7:43 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo, luciano.coelho, Johannes Berg
In-Reply-To: <20170123220350.25305-6-luca@coelho.fi>

From: Johannes Berg <johannes.berg@intel.com>

Due to some new features and changes, the firmware file will now
specify what type of memory to dump, in upper 8 bits of the type
field of the TLV. Parse it (types we don't understand are errors)
and teach the code to dump periphery memory.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---

In v2:

The prph read should read dwords, but now the offset is incremented
by a byte in each iteration, instead of a dword.
As a result, the prph dump both prints each value multiple times
and not all of the block is read.

Fix this by advancing the read offset in a dword after every
iteration.


drivers/net/wireless/intel/iwlwifi/iwl-drv.c     | 12 +++++
 drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h | 15 +++++-
 drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c  | 65 +++++++++++++++++++-----
 3 files changed, 79 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
index 431581229948..a6719d67ac00 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
@@ -1020,6 +1020,18 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
 			IWL_DEBUG_INFO(drv, "Found debug memory segment: %u\n",
 				       dbg_mem->data_type);
 
+			switch (type & FW_DBG_MEM_TYPE_MASK) {
+			case FW_DBG_MEM_TYPE_REGULAR:
+			case FW_DBG_MEM_TYPE_PRPH:
+				/* we know how to handle these */
+				break;
+			default:
+				IWL_ERR(drv,
+					"Found debug memory segment with invalid type: 0x%x\n",
+					type);
+				return -EINVAL;
+			}
+
 			size = sizeof(*pieces->dbg_mem_tlv) *
 			       (pieces->n_dbg_mem_tlv + 1);
 			n = krealloc(pieces->dbg_mem_tlv, size, GFP_KERNEL);
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h
index 11245b9117c7..c84207576587 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h
@@ -489,9 +489,22 @@ enum iwl_fw_dbg_monitor_mode {
 };
 
 /**
+ * enum iwl_fw_mem_seg_type - memory segment type
+ * @FW_DBG_MEM_TYPE_MASK: mask for the type indication
+ * @FW_DBG_MEM_TYPE_REGULAR: regular memory
+ * @FW_DBG_MEM_TYPE_PRPH: periphery memory (requires special reading)
+ */
+enum iwl_fw_mem_seg_type {
+	FW_DBG_MEM_TYPE_MASK	= 0xff000000,
+	FW_DBG_MEM_TYPE_REGULAR	= 0x00000000,
+	FW_DBG_MEM_TYPE_PRPH	= 0x01000000,
+};
+
+/**
  * struct iwl_fw_dbg_mem_seg_tlv - configures the debug data memory segments
  *
- * @data_type: the memory segment type to record
+ * @data_type: the memory segment type to record, see &enum iwl_fw_mem_seg_type
+ *	for what we care about
  * @ofs: the memory segment offset
  * @len: the memory segment length, in bytes
  *
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
index 7df3c3f4749e..e447cd92deb3 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
@@ -406,6 +406,30 @@ static const struct iwl_prph_range iwl_prph_dump_addr_9000[] = {
 	{ .start = 0x00a02400, .end = 0x00a02758 },
 };
 
+static void _iwl_read_prph_block(struct iwl_trans *trans, u32 start,
+				 u32 len_bytes, __le32 *data)
+{
+	u32 i;
+
+	for (i = 0; i < len_bytes; i += 4)
+		*data++ = cpu_to_le32(iwl_read_prph_no_grab(trans, start + i));
+}
+
+static bool iwl_read_prph_block(struct iwl_trans *trans, u32 start,
+				u32 len_bytes, __le32 *data)
+{
+	unsigned long flags;
+	bool success = false;
+
+	if (iwl_trans_grab_nic_access(trans, &flags)) {
+		success = true;
+		_iwl_read_prph_block(trans, start, len_bytes, data);
+		iwl_trans_release_nic_access(trans, &flags);
+	}
+
+	return success;
+}
+
 static void iwl_dump_prph(struct iwl_trans *trans,
 			  struct iwl_fw_error_dump_data **data,
 			  const struct iwl_prph_range *iwl_prph_dump_addr,
@@ -422,21 +446,18 @@ static void iwl_dump_prph(struct iwl_trans *trans,
 		/* The range includes both boundaries */
 		int num_bytes_in_chunk = iwl_prph_dump_addr[i].end -
 			 iwl_prph_dump_addr[i].start + 4;
-		int reg;
-		__le32 *val;
 
 		(*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PRPH);
 		(*data)->len = cpu_to_le32(sizeof(*prph) +
 					num_bytes_in_chunk);
 		prph = (void *)(*data)->data;
 		prph->prph_start = cpu_to_le32(iwl_prph_dump_addr[i].start);
-		val = (void *)prph->data;
 
-		for (reg = iwl_prph_dump_addr[i].start;
-		     reg <= iwl_prph_dump_addr[i].end;
-		     reg += 4)
-			*val++ = cpu_to_le32(iwl_read_prph_no_grab(trans,
-								   reg));
+		_iwl_read_prph_block(trans, iwl_prph_dump_addr[i].start,
+				     /* our range is inclusive, hence + 4 */
+				     iwl_prph_dump_addr[i].end -
+				     iwl_prph_dump_addr[i].start + 4,
+				     (void *)prph->data);
 
 		*data = iwl_fw_error_next_data(*data);
 	}
@@ -716,16 +737,36 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
 	for (i = 0; i < mvm->fw->n_dbg_mem_tlv; i++) {
 		u32 len = le32_to_cpu(fw_dbg_mem[i].len);
 		u32 ofs = le32_to_cpu(fw_dbg_mem[i].ofs);
+		bool success;
 
 		dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
 		dump_data->len = cpu_to_le32(len + sizeof(*dump_mem));
 		dump_mem = (void *)dump_data->data;
 		dump_mem->type = fw_dbg_mem[i].data_type;
 		dump_mem->offset = cpu_to_le32(ofs);
-		iwl_trans_read_mem_bytes(mvm->trans, ofs,
-					 dump_mem->data,
-					 len);
-		dump_data = iwl_fw_error_next_data(dump_data);
+
+		switch (dump_mem->type & cpu_to_le32(FW_DBG_MEM_TYPE_MASK)) {
+		case cpu_to_le32(FW_DBG_MEM_TYPE_REGULAR):
+			iwl_trans_read_mem_bytes(mvm->trans, ofs,
+						 dump_mem->data,
+						 len);
+			success = true;
+			break;
+		case cpu_to_le32(FW_DBG_MEM_TYPE_PRPH):
+			success = iwl_read_prph_block(mvm->trans, ofs, len,
+						      (void *)dump_mem->data);
+			break;
+		default:
+			/*
+			 * shouldn't get here, we ignored this kind
+			 * of TLV earlier during the TLV parsing?!
+			 */
+			WARN_ON(1);
+			success = false;
+		}
+
+		if (success)
+			dump_data = iwl_fw_error_next_data(dump_data);
 	}
 
 	if (smem_len) {
-- 
2.11.0

^ permalink raw reply related

* [PATCH v2] iwlwifi: mvm: use mvm_disable_queue instead of sharing logic
From: Luca Coelho @ 2017-01-26  7:34 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo, luciano.coelho, Sara Sharon
In-Reply-To: <20170123220350.25305-25-luca@coelho.fi>

From: Sara Sharon <sara.sharon@intel.com>

When removing inactive queue - use the central disable queue
function. This is needed due to a000 changes to come, but is
a proper cleanup anyway.

Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---

In v2:

iwl_mvm_disable_txq() returns early if the hw_ref_count is
zeroed, with the result of the queue not being properly disabled.
Avoid zeroing it and other queue information in remove_sta_marking().
iwl_mvm_disable_txq() which is called later in the flow will zero
it.

drivers/net/wireless/intel/iwlwifi/mvm/mvm.h   |  4 ++--
 drivers/net/wireless/intel/iwlwifi/mvm/sta.c   | 29 +++++++-------------------
 drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 10 +++++----
 3 files changed, 16 insertions(+), 27 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 4a9cb76b7611..a672aa71c656 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -1657,8 +1657,8 @@ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
  * Disable a TXQ.
  * Note that in non-DQA mode the %mac80211_queue and %tid params are ignored.
  */
-void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
-			 u8 tid, u8 flags);
+int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
+			u8 tid, u8 flags);
 int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id, u8 minq, u8 maxq);
 
 /* Return a bitmask with all the hw supported queues, except for the
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index cf8222a8b588..40e7fc5f1f1f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -454,13 +454,6 @@ static int iwl_mvm_remove_sta_queue_marking(struct iwl_mvm *mvm, int queue)
 
 	rcu_read_unlock();
 
-	spin_lock_bh(&mvm->queue_info_lock);
-	/* Unmap MAC queues and TIDs from this queue */
-	mvm->queue_info[queue].hw_queue_to_mac80211 = 0;
-	mvm->queue_info[queue].hw_queue_refcount = 0;
-	mvm->queue_info[queue].tid_bitmap = 0;
-	spin_unlock_bh(&mvm->queue_info_lock);
-
 	return disable_agg_tids;
 }
 
@@ -755,28 +748,22 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
 	 * first
 	 */
 	if (using_inactive_queue) {
-		struct iwl_scd_txq_cfg_cmd cmd = {
-			.scd_queue = queue,
-			.action = SCD_CFG_DISABLE_QUEUE,
-		};
-		u8 txq_curr_ac;
-
-		disable_agg_tids = iwl_mvm_remove_sta_queue_marking(mvm, queue);
+		u8 txq_curr_ac, sta_id;
 
 		spin_lock_bh(&mvm->queue_info_lock);
 		txq_curr_ac = mvm->queue_info[queue].mac80211_ac;
-		cmd.sta_id = mvm->queue_info[queue].ra_sta_id;
-		cmd.tx_fifo = iwl_mvm_ac_to_tx_fifo[txq_curr_ac];
-		cmd.tid = mvm->queue_info[queue].txq_tid;
+		sta_id = mvm->queue_info[queue].ra_sta_id;
 		spin_unlock_bh(&mvm->queue_info_lock);
 
+		disable_agg_tids = iwl_mvm_remove_sta_queue_marking(mvm, queue);
 		/* Disable the queue */
 		if (disable_agg_tids)
 			iwl_mvm_invalidate_sta_queue(mvm, queue,
 						     disable_agg_tids, false);
-		iwl_trans_txq_disable(mvm->trans, queue, false);
-		ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd),
-					   &cmd);
+
+		ret = iwl_mvm_disable_txq(mvm, queue,
+					  mvmsta->vif->hw_queue[txq_curr_ac],
+					  tid, 0);
 		if (ret) {
 			IWL_ERR(mvm,
 				"Failed to free inactive queue %d (ret=%d)\n",
@@ -791,7 +778,7 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
 		}
 
 		/* If TXQ is allocated to another STA, update removal in FW */
-		if (cmd.sta_id != mvmsta->sta_id)
+		if (sta_id != mvmsta->sta_id)
 			iwl_mvm_invalidate_sta_queue(mvm, queue, 0, true);
 	}
 
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index d04babd99b53..2beea3b98e52 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -706,8 +706,8 @@ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
 	}
 }
 
-void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
-			 u8 tid, u8 flags)
+int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
+			u8 tid, u8 flags)
 {
 	struct iwl_scd_txq_cfg_cmd cmd = {
 		.scd_queue = queue,
@@ -720,7 +720,7 @@ void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
 
 	if (WARN_ON(mvm->queue_info[queue].hw_queue_refcount == 0)) {
 		spin_unlock_bh(&mvm->queue_info_lock);
-		return;
+		return 0;
 	}
 
 	mvm->queue_info[queue].tid_bitmap &= ~BIT(tid);
@@ -760,7 +760,7 @@ void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
 	/* If the queue is still enabled - nothing left to do in this func */
 	if (cmd.action == SCD_CFG_ENABLE_QUEUE) {
 		spin_unlock_bh(&mvm->queue_info_lock);
-		return;
+		return 0;
 	}
 
 	cmd.sta_id = mvm->queue_info[queue].ra_sta_id;
@@ -791,6 +791,8 @@ void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
 	if (ret)
 		IWL_ERR(mvm, "Failed to disable queue %d (ret=%d)\n",
 			queue, ret);
+
+	return ret;
 }
 
 /**
-- 
2.11.0

^ permalink raw reply related

* [PATCH v2] iwlwifi: mvm: change iwl_mvm_tx_csum to return value
From: Luca Coelho @ 2017-01-26  7:24 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo, luciano.coelho, Sara Sharon
In-Reply-To: <20170123220350.25305-12-luca@coelho.fi>

From: Sara Sharon <sara.sharon@intel.com>

Currently the function changes the TX cmd itself.
Make it more generic by returning a value, as preperation
to the new TX cmd.

Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---

In v2:

   * Fix compilation warning when CONFIG_INET is not set

drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index 66957ac12ca4..73a90d4a43eb 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -102,14 +102,13 @@ iwl_mvm_bar_check_trigger(struct iwl_mvm *mvm, const u8 *addr,
 #define OPT_HDR(type, skb, off) \
 	(type *)(skb_network_header(skb) + (off))
 
-static void iwl_mvm_tx_csum(struct iwl_mvm *mvm, struct sk_buff *skb,
-			    struct ieee80211_hdr *hdr,
-			    struct ieee80211_tx_info *info,
-			    struct iwl_tx_cmd *tx_cmd)
+static u16 iwl_mvm_tx_csum(struct iwl_mvm *mvm, struct sk_buff *skb,
+			   struct ieee80211_hdr *hdr,
+			   struct ieee80211_tx_info *info)
 {
+	u16 offload_assist = 0;
 #if IS_ENABLED(CONFIG_INET)
 	u16 mh_len = ieee80211_hdrlen(hdr->frame_control);
-	u16 offload_assist = le16_to_cpu(tx_cmd->offload_assist);
 	u8 protocol = 0;
 
 	/*
@@ -117,7 +116,7 @@ static void iwl_mvm_tx_csum(struct iwl_mvm *mvm, struct sk_buff *skb,
 	 * compute it
 	 */
 	if (skb->ip_summed != CHECKSUM_PARTIAL || IWL_MVM_SW_TX_CSUM_OFFLOAD)
-		return;
+		goto out;
 
 	/* We do not expect to be requested to csum stuff we do not support */
 	if (WARN_ONCE(!(mvm->hw->netdev_features & IWL_TX_CSUM_NETIF_FLAGS) ||
@@ -125,7 +124,7 @@ static void iwl_mvm_tx_csum(struct iwl_mvm *mvm, struct sk_buff *skb,
 		       skb->protocol != htons(ETH_P_IPV6)),
 		      "No support for requested checksum\n")) {
 		skb_checksum_help(skb);
-		return;
+		goto out;
 	}
 
 	if (skb->protocol == htons(ETH_P_IP)) {
@@ -145,7 +144,7 @@ static void iwl_mvm_tx_csum(struct iwl_mvm *mvm, struct sk_buff *skb,
 			    protocol != NEXTHDR_HOP &&
 			    protocol != NEXTHDR_DEST) {
 				skb_checksum_help(skb);
-				return;
+				goto out;
 			}
 
 			hp = OPT_HDR(struct ipv6_opt_hdr, skb, off);
@@ -159,7 +158,7 @@ static void iwl_mvm_tx_csum(struct iwl_mvm *mvm, struct sk_buff *skb,
 	if (protocol != IPPROTO_TCP && protocol != IPPROTO_UDP) {
 		WARN_ON_ONCE(1);
 		skb_checksum_help(skb);
-		return;
+		goto out;
 	}
 
 	/* enable L4 csum */
@@ -191,8 +190,9 @@ static void iwl_mvm_tx_csum(struct iwl_mvm *mvm, struct sk_buff *skb,
 	mh_len /= 2;
 	offload_assist |= mh_len << TX_CMD_OFFLD_MH_SIZE;
 
-	tx_cmd->offload_assist = cpu_to_le16(offload_assist);
+out:
 #endif
+	return offload_assist;
 }
 
 /*
@@ -295,7 +295,8 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
 	    !(tx_cmd->offload_assist & cpu_to_le16(BIT(TX_CMD_OFFLD_AMSDU))))
 		tx_cmd->offload_assist |= cpu_to_le16(BIT(TX_CMD_OFFLD_PAD));
 
-	iwl_mvm_tx_csum(mvm, skb, hdr, info, tx_cmd);
+	tx_cmd->offload_assist |=
+		cpu_to_le16(iwl_mvm_tx_csum(mvm, skb, hdr, info));
 }
 
 /*
-- 
2.11.0

^ permalink raw reply related

* Re: [PATCH] NFC: remove TI nfcwilink driver
From: Marcel Holtmann @ 2017-01-26  5:54 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-kernel, linux-wireless, Ilan Elias, Samuel Ortiz,
	Lauro Ramos Venancio, Aloisio Almeida Jr
In-Reply-To: <20170125222307.3044-1-robh@kernel.org>

Hi Rob,

> It appears that TI WiLink devices including NFC (WL185x/WL189x) never
> shipped. The only information I found were announcements in Feb
> 2012 about the parts. There's been no activity on this driver besided
> common changes since initially added in Jan 2012. There's also no in
> users that instantiate the platform device (nor DT bindings).
> 
> This is a first step in removing TI ST (shared transport) driver in
> favor of extending the BT hci_ll driver to support WL183x chips.

since the firmware files TINfcInit_* also never made it into the linux-firmware tree, I have no idea who is using this driver. I am actually fine with removing it since it would be easy enough to bring back based on hci_ll driver once there is hardware to test this on.

Regards

Marcel

^ permalink raw reply

* [PATCH] nl80211: Fix mesh HT operation check
From: Masashi Honma @ 2017-01-25 23:56 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Masashi Honma

commit 9757235f451c27deaa88925399f070ff6fcea832 ('nl80211: correct
checks for NL80211_MESHCONF_HT_OPMODE value') missed to mask a flag
when replacing FILL_IN_MESH_PARAM_IF_SET with checking codes. This
could drop the received HT operation value when called by
nl80211_update_mesh_config().

Signed-off-by: Masashi Honma <masashi.honma@gmail.com>
---
 net/wireless/nl80211.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index e6ed8dc..006c147 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5924,6 +5924,7 @@ do {									    \
 			break;
 		}
 		cfg->ht_opmode = ht_opmode;
+		mask |= (1 << (NL80211_MESHCONF_HT_OPMODE - 1));
 	}
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathToRootTimeout,
 				  1, 65535, mask,
-- 
2.7.4

^ permalink raw reply related

* [PATCH] NFC: remove TI nfcwilink driver
From: Rob Herring @ 2017-01-25 22:23 UTC (permalink / raw)
  To: linux-kernel, linux-wireless
  Cc: Ilan Elias, Marcel Holtmann, Samuel Ortiz, Lauro Ramos Venancio,
	Aloisio Almeida Jr

It appears that TI WiLink devices including NFC (WL185x/WL189x) never
shipped. The only information I found were announcements in Feb
2012 about the parts. There's been no activity on this driver besided
common changes since initially added in Jan 2012. There's also no in
users that instantiate the platform device (nor DT bindings).

This is a first step in removing TI ST (shared transport) driver in
favor of extending the BT hci_ll driver to support WL183x chips.

Cc: Ilan Elias <ilane@ti.com>
Cc: Marcel Holtmann <marcel@holtmann.org>
Cc: Samuel Ortiz <sameo@linux.intel.com>
Cc: Lauro Ramos Venancio <lauro.venancio@openbossa.org>
Cc: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
Cc: linux-wireless@vger.kernel.org
Signed-off-by: Rob Herring <robh@kernel.org>
---
 drivers/nfc/Kconfig     |  11 -
 drivers/nfc/Makefile    |   1 -
 drivers/nfc/nfcwilink.c | 578 ------------------------------------------------
 3 files changed, 590 deletions(-)
 delete mode 100644 drivers/nfc/nfcwilink.c

diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index 9d2369269abf..c4208487fadc 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -5,17 +5,6 @@
 menu "Near Field Communication (NFC) devices"
 	depends on NFC
 
-config NFC_WILINK
-	tristate "Texas Instruments NFC WiLink driver"
-	depends on TI_ST && NFC_NCI
-	help
-	  This enables the NFC driver for Texas Instrument's BT/FM/GPS/NFC
-	  combo devices. This makes use of shared transport line discipline
-	  core driver to communicate with the NFC core of the combo chip.
-
-	  Say Y here to compile support for Texas Instrument's NFC WiLink driver
-	  into the kernel or say M to compile it as module.
-
 config NFC_TRF7970A
 	tristate "Texas Instruments TRF7970a NFC driver"
 	depends on SPI && NFC_DIGITAL
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index bab8ef06ae35..640b7274371c 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -6,7 +6,6 @@ obj-$(CONFIG_NFC_FDP)		+= fdp/
 obj-$(CONFIG_NFC_PN544)		+= pn544/
 obj-$(CONFIG_NFC_MICROREAD)	+= microread/
 obj-$(CONFIG_NFC_PN533)		+= pn533/
-obj-$(CONFIG_NFC_WILINK)	+= nfcwilink.o
 obj-$(CONFIG_NFC_MEI_PHY)	+= mei_phy.o
 obj-$(CONFIG_NFC_SIM)		+= nfcsim.o
 obj-$(CONFIG_NFC_PORT100)	+= port100.o
diff --git a/drivers/nfc/nfcwilink.c b/drivers/nfc/nfcwilink.c
deleted file mode 100644
index 3fbd18b8e473..000000000000
--- a/drivers/nfc/nfcwilink.c
+++ /dev/null
@@ -1,578 +0,0 @@
-/*
- *  Texas Instrument's NFC Driver For Shared Transport.
- *
- *  NFC Driver acts as interface between NCI core and
- *  TI Shared Transport Layer.
- *
- *  Copyright (C) 2011 Texas Instruments, Inc.
- *
- *  Written by Ilan Elias <ilane@ti.com>
- *
- *  Acknowledgements:
- *  This file is based on btwilink.c, which was written
- *  by Raja Mani and Pavan Savoy.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/firmware.h>
-#include <linux/nfc.h>
-#include <net/nfc/nci.h>
-#include <net/nfc/nci_core.h>
-#include <linux/ti_wilink_st.h>
-
-#define NFCWILINK_CHNL			12
-#define NFCWILINK_OPCODE		7
-#define NFCWILINK_MAX_FRAME_SIZE	300
-#define NFCWILINK_HDR_LEN		4
-#define NFCWILINK_OFFSET_LEN_IN_HDR	1
-#define NFCWILINK_LEN_SIZE		2
-#define NFCWILINK_REGISTER_TIMEOUT	8000	/* 8 sec */
-#define NFCWILINK_CMD_TIMEOUT		5000	/* 5 sec */
-
-#define BTS_FILE_NAME_MAX_SIZE		40
-#define BTS_FILE_HDR_MAGIC		0x42535442
-#define BTS_FILE_CMD_MAX_LEN		0xff
-#define BTS_FILE_ACTION_TYPE_SEND_CMD	1
-
-#define NCI_VS_NFCC_INFO_CMD_GID	0x2f
-#define NCI_VS_NFCC_INFO_CMD_OID	0x12
-#define NCI_VS_NFCC_INFO_RSP_GID	0x4f
-#define NCI_VS_NFCC_INFO_RSP_OID	0x12
-
-struct nfcwilink_hdr {
-	__u8 chnl;
-	__u8 opcode;
-	__le16 len;
-} __packed;
-
-struct nci_vs_nfcc_info_cmd {
-	__u8 gid;
-	__u8 oid;
-	__u8 plen;
-} __packed;
-
-struct nci_vs_nfcc_info_rsp {
-	__u8 gid;
-	__u8 oid;
-	__u8 plen;
-	__u8 status;
-	__u8 hw_id;
-	__u8 sw_ver_x;
-	__u8 sw_ver_z;
-	__u8 patch_id;
-} __packed;
-
-struct bts_file_hdr {
-	__le32 magic;
-	__le32 ver;
-	__u8 rfu[24];
-	__u8 actions[0];
-} __packed;
-
-struct bts_file_action {
-	__le16 type;
-	__le16 len;
-	__u8 data[0];
-} __packed;
-
-struct nfcwilink {
-	struct platform_device		*pdev;
-	struct nci_dev			*ndev;
-	unsigned long			flags;
-
-	int				st_register_cb_status;
-	long				(*st_write) (struct sk_buff *);
-
-	struct completion		completed;
-
-	struct nci_vs_nfcc_info_rsp	nfcc_info;
-};
-
-/* NFCWILINK driver flags */
-enum {
-	NFCWILINK_RUNNING,
-	NFCWILINK_FW_DOWNLOAD,
-};
-
-static int nfcwilink_send(struct nci_dev *ndev, struct sk_buff *skb);
-
-static inline struct sk_buff *nfcwilink_skb_alloc(unsigned int len, gfp_t how)
-{
-	struct sk_buff *skb;
-
-	skb = alloc_skb(len + NFCWILINK_HDR_LEN, how);
-	if (skb)
-		skb_reserve(skb, NFCWILINK_HDR_LEN);
-
-	return skb;
-}
-
-static void nfcwilink_fw_download_receive(struct nfcwilink *drv,
-						struct sk_buff *skb)
-{
-	struct nci_vs_nfcc_info_rsp *rsp = (void *)skb->data;
-
-	/* Detect NCI_VS_NFCC_INFO_RSP and store the result */
-	if ((skb->len > 3) && (rsp->gid == NCI_VS_NFCC_INFO_RSP_GID) &&
-		(rsp->oid == NCI_VS_NFCC_INFO_RSP_OID)) {
-		memcpy(&drv->nfcc_info, rsp,
-			sizeof(struct nci_vs_nfcc_info_rsp));
-	}
-
-	kfree_skb(skb);
-
-	complete(&drv->completed);
-}
-
-static int nfcwilink_get_bts_file_name(struct nfcwilink *drv, char *file_name)
-{
-	struct nci_vs_nfcc_info_cmd *cmd;
-	struct sk_buff *skb;
-	unsigned long comp_ret;
-	int rc;
-
-	skb = nfcwilink_skb_alloc(sizeof(struct nci_vs_nfcc_info_cmd),
-					GFP_KERNEL);
-	if (!skb) {
-		nfc_err(&drv->pdev->dev,
-			"no memory for nci_vs_nfcc_info_cmd\n");
-		return -ENOMEM;
-	}
-
-	cmd = (struct nci_vs_nfcc_info_cmd *)
-			skb_put(skb, sizeof(struct nci_vs_nfcc_info_cmd));
-	cmd->gid = NCI_VS_NFCC_INFO_CMD_GID;
-	cmd->oid = NCI_VS_NFCC_INFO_CMD_OID;
-	cmd->plen = 0;
-
-	drv->nfcc_info.plen = 0;
-
-	rc = nfcwilink_send(drv->ndev, skb);
-	if (rc)
-		return rc;
-
-	comp_ret = wait_for_completion_timeout(&drv->completed,
-				msecs_to_jiffies(NFCWILINK_CMD_TIMEOUT));
-	dev_dbg(&drv->pdev->dev, "wait_for_completion_timeout returned %ld\n",
-		comp_ret);
-	if (comp_ret == 0) {
-		nfc_err(&drv->pdev->dev,
-			"timeout on wait_for_completion_timeout\n");
-		return -ETIMEDOUT;
-	}
-
-	dev_dbg(&drv->pdev->dev, "nci_vs_nfcc_info_rsp: plen %d, status %d\n",
-		drv->nfcc_info.plen, drv->nfcc_info.status);
-
-	if ((drv->nfcc_info.plen != 5) || (drv->nfcc_info.status != 0)) {
-		nfc_err(&drv->pdev->dev, "invalid nci_vs_nfcc_info_rsp\n");
-		return -EINVAL;
-	}
-
-	snprintf(file_name, BTS_FILE_NAME_MAX_SIZE,
-			"TINfcInit_%d.%d.%d.%d.bts",
-			drv->nfcc_info.hw_id,
-			drv->nfcc_info.sw_ver_x,
-			drv->nfcc_info.sw_ver_z,
-			drv->nfcc_info.patch_id);
-
-	nfc_info(&drv->pdev->dev, "nfcwilink FW file name: %s\n", file_name);
-
-	return 0;
-}
-
-static int nfcwilink_send_bts_cmd(struct nfcwilink *drv, __u8 *data, int len)
-{
-	struct nfcwilink_hdr *hdr = (struct nfcwilink_hdr *)data;
-	struct sk_buff *skb;
-	unsigned long comp_ret;
-	int rc;
-
-	/* verify valid cmd for the NFC channel */
-	if ((len <= sizeof(struct nfcwilink_hdr)) ||
-		(len > BTS_FILE_CMD_MAX_LEN) ||
-		(hdr->chnl != NFCWILINK_CHNL) ||
-		(hdr->opcode != NFCWILINK_OPCODE)) {
-		nfc_err(&drv->pdev->dev,
-			"ignoring invalid bts cmd, len %d, chnl %d, opcode %d\n",
-			len, hdr->chnl, hdr->opcode);
-		return 0;
-	}
-
-	/* remove the ST header */
-	len -= sizeof(struct nfcwilink_hdr);
-	data += sizeof(struct nfcwilink_hdr);
-
-	skb = nfcwilink_skb_alloc(len, GFP_KERNEL);
-	if (!skb) {
-		nfc_err(&drv->pdev->dev, "no memory for bts cmd\n");
-		return -ENOMEM;
-	}
-
-	memcpy(skb_put(skb, len), data, len);
-
-	rc = nfcwilink_send(drv->ndev, skb);
-	if (rc)
-		return rc;
-
-	comp_ret = wait_for_completion_timeout(&drv->completed,
-				msecs_to_jiffies(NFCWILINK_CMD_TIMEOUT));
-	dev_dbg(&drv->pdev->dev, "wait_for_completion_timeout returned %ld\n",
-		comp_ret);
-	if (comp_ret == 0) {
-		nfc_err(&drv->pdev->dev,
-			"timeout on wait_for_completion_timeout\n");
-		return -ETIMEDOUT;
-	}
-
-	return 0;
-}
-
-static int nfcwilink_download_fw(struct nfcwilink *drv)
-{
-	unsigned char file_name[BTS_FILE_NAME_MAX_SIZE];
-	const struct firmware *fw;
-	__u16 action_type, action_len;
-	__u8 *ptr;
-	int len, rc;
-
-	set_bit(NFCWILINK_FW_DOWNLOAD, &drv->flags);
-
-	rc = nfcwilink_get_bts_file_name(drv, file_name);
-	if (rc)
-		goto exit;
-
-	rc = request_firmware(&fw, file_name, &drv->pdev->dev);
-	if (rc) {
-		nfc_err(&drv->pdev->dev, "request_firmware failed %d\n", rc);
-
-		/* if the file is not found, don't exit with failure */
-		if (rc == -ENOENT)
-			rc = 0;
-
-		goto exit;
-	}
-
-	len = fw->size;
-	ptr = (__u8 *)fw->data;
-
-	if ((len == 0) || (ptr == NULL)) {
-		dev_dbg(&drv->pdev->dev,
-			"request_firmware returned size %d\n", len);
-		goto release_fw;
-	}
-
-	if (__le32_to_cpu(((struct bts_file_hdr *)ptr)->magic) !=
-			BTS_FILE_HDR_MAGIC) {
-		nfc_err(&drv->pdev->dev, "wrong bts magic number\n");
-		rc = -EINVAL;
-		goto release_fw;
-	}
-
-	/* remove the BTS header */
-	len -= sizeof(struct bts_file_hdr);
-	ptr += sizeof(struct bts_file_hdr);
-
-	while (len > 0) {
-		action_type =
-			__le16_to_cpu(((struct bts_file_action *)ptr)->type);
-		action_len =
-			__le16_to_cpu(((struct bts_file_action *)ptr)->len);
-
-		dev_dbg(&drv->pdev->dev, "bts_file_action type %d, len %d\n",
-			action_type, action_len);
-
-		switch (action_type) {
-		case BTS_FILE_ACTION_TYPE_SEND_CMD:
-			rc = nfcwilink_send_bts_cmd(drv,
-					((struct bts_file_action *)ptr)->data,
-					action_len);
-			if (rc)
-				goto release_fw;
-			break;
-		}
-
-		/* advance to the next action */
-		len -= (sizeof(struct bts_file_action) + action_len);
-		ptr += (sizeof(struct bts_file_action) + action_len);
-	}
-
-release_fw:
-	release_firmware(fw);
-
-exit:
-	clear_bit(NFCWILINK_FW_DOWNLOAD, &drv->flags);
-	return rc;
-}
-
-/* Called by ST when registration is complete */
-static void nfcwilink_register_complete(void *priv_data, int data)
-{
-	struct nfcwilink *drv = priv_data;
-
-	/* store ST registration status */
-	drv->st_register_cb_status = data;
-
-	/* complete the wait in nfc_st_open() */
-	complete(&drv->completed);
-}
-
-/* Called by ST when receive data is available */
-static long nfcwilink_receive(void *priv_data, struct sk_buff *skb)
-{
-	struct nfcwilink *drv = priv_data;
-	int rc;
-
-	if (!skb)
-		return -EFAULT;
-
-	if (!drv) {
-		kfree_skb(skb);
-		return -EFAULT;
-	}
-
-	dev_dbg(&drv->pdev->dev, "receive entry, len %d\n", skb->len);
-
-	/* strip the ST header
-	(apart for the chnl byte, which is not received in the hdr) */
-	skb_pull(skb, (NFCWILINK_HDR_LEN-1));
-
-	if (test_bit(NFCWILINK_FW_DOWNLOAD, &drv->flags)) {
-		nfcwilink_fw_download_receive(drv, skb);
-		return 0;
-	}
-
-	/* Forward skb to NCI core layer */
-	rc = nci_recv_frame(drv->ndev, skb);
-	if (rc < 0) {
-		nfc_err(&drv->pdev->dev, "nci_recv_frame failed %d\n", rc);
-		return rc;
-	}
-
-	return 0;
-}
-
-/* protocol structure registered with ST */
-static struct st_proto_s nfcwilink_proto = {
-	.chnl_id = NFCWILINK_CHNL,
-	.max_frame_size = NFCWILINK_MAX_FRAME_SIZE,
-	.hdr_len = (NFCWILINK_HDR_LEN-1),	/* not including chnl byte */
-	.offset_len_in_hdr = NFCWILINK_OFFSET_LEN_IN_HDR,
-	.len_size = NFCWILINK_LEN_SIZE,
-	.reserve = 0,
-	.recv = nfcwilink_receive,
-	.reg_complete_cb = nfcwilink_register_complete,
-	.write = NULL,
-};
-
-static int nfcwilink_open(struct nci_dev *ndev)
-{
-	struct nfcwilink *drv = nci_get_drvdata(ndev);
-	unsigned long comp_ret;
-	int rc;
-
-	if (test_and_set_bit(NFCWILINK_RUNNING, &drv->flags)) {
-		rc = -EBUSY;
-		goto exit;
-	}
-
-	nfcwilink_proto.priv_data = drv;
-
-	init_completion(&drv->completed);
-	drv->st_register_cb_status = -EINPROGRESS;
-
-	rc = st_register(&nfcwilink_proto);
-	if (rc < 0) {
-		if (rc == -EINPROGRESS) {
-			comp_ret = wait_for_completion_timeout(
-			&drv->completed,
-			msecs_to_jiffies(NFCWILINK_REGISTER_TIMEOUT));
-
-			dev_dbg(&drv->pdev->dev,
-				"wait_for_completion_timeout returned %ld\n",
-				comp_ret);
-
-			if (comp_ret == 0) {
-				/* timeout */
-				rc = -ETIMEDOUT;
-				goto clear_exit;
-			} else if (drv->st_register_cb_status != 0) {
-				rc = drv->st_register_cb_status;
-				nfc_err(&drv->pdev->dev,
-					"st_register_cb failed %d\n", rc);
-				goto clear_exit;
-			}
-		} else {
-			nfc_err(&drv->pdev->dev, "st_register failed %d\n", rc);
-			goto clear_exit;
-		}
-	}
-
-	/* st_register MUST fill the write callback */
-	BUG_ON(nfcwilink_proto.write == NULL);
-	drv->st_write = nfcwilink_proto.write;
-
-	if (nfcwilink_download_fw(drv)) {
-		nfc_err(&drv->pdev->dev, "nfcwilink_download_fw failed %d\n",
-			rc);
-		/* open should succeed, even if the FW download failed */
-	}
-
-	goto exit;
-
-clear_exit:
-	clear_bit(NFCWILINK_RUNNING, &drv->flags);
-
-exit:
-	return rc;
-}
-
-static int nfcwilink_close(struct nci_dev *ndev)
-{
-	struct nfcwilink *drv = nci_get_drvdata(ndev);
-	int rc;
-
-	if (!test_and_clear_bit(NFCWILINK_RUNNING, &drv->flags))
-		return 0;
-
-	rc = st_unregister(&nfcwilink_proto);
-	if (rc)
-		nfc_err(&drv->pdev->dev, "st_unregister failed %d\n", rc);
-
-	drv->st_write = NULL;
-
-	return rc;
-}
-
-static int nfcwilink_send(struct nci_dev *ndev, struct sk_buff *skb)
-{
-	struct nfcwilink *drv = nci_get_drvdata(ndev);
-	struct nfcwilink_hdr hdr = {NFCWILINK_CHNL, NFCWILINK_OPCODE, 0x0000};
-	long len;
-
-	dev_dbg(&drv->pdev->dev, "send entry, len %d\n", skb->len);
-
-	if (!test_bit(NFCWILINK_RUNNING, &drv->flags)) {
-		kfree_skb(skb);
-		return -EINVAL;
-	}
-
-	/* add the ST hdr to the start of the buffer */
-	hdr.len = cpu_to_le16(skb->len);
-	memcpy(skb_push(skb, NFCWILINK_HDR_LEN), &hdr, NFCWILINK_HDR_LEN);
-
-	/* Insert skb to shared transport layer's transmit queue.
-	 * Freeing skb memory is taken care in shared transport layer,
-	 * so don't free skb memory here.
-	 */
-	len = drv->st_write(skb);
-	if (len < 0) {
-		kfree_skb(skb);
-		nfc_err(&drv->pdev->dev, "st_write failed %ld\n", len);
-		return -EFAULT;
-	}
-
-	return 0;
-}
-
-static struct nci_ops nfcwilink_ops = {
-	.open = nfcwilink_open,
-	.close = nfcwilink_close,
-	.send = nfcwilink_send,
-};
-
-static int nfcwilink_probe(struct platform_device *pdev)
-{
-	struct nfcwilink *drv;
-	int rc;
-	__u32 protocols;
-
-	drv = devm_kzalloc(&pdev->dev, sizeof(struct nfcwilink), GFP_KERNEL);
-	if (!drv) {
-		rc = -ENOMEM;
-		goto exit;
-	}
-
-	drv->pdev = pdev;
-
-	protocols = NFC_PROTO_JEWEL_MASK
-		| NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK
-		| NFC_PROTO_ISO14443_MASK
-		| NFC_PROTO_ISO14443_B_MASK
-		| NFC_PROTO_NFC_DEP_MASK;
-
-	drv->ndev = nci_allocate_device(&nfcwilink_ops,
-					protocols,
-					NFCWILINK_HDR_LEN,
-					0);
-	if (!drv->ndev) {
-		nfc_err(&pdev->dev, "nci_allocate_device failed\n");
-		rc = -ENOMEM;
-		goto exit;
-	}
-
-	nci_set_parent_dev(drv->ndev, &pdev->dev);
-	nci_set_drvdata(drv->ndev, drv);
-
-	rc = nci_register_device(drv->ndev);
-	if (rc < 0) {
-		nfc_err(&pdev->dev, "nci_register_device failed %d\n", rc);
-		goto free_dev_exit;
-	}
-
-	dev_set_drvdata(&pdev->dev, drv);
-
-	goto exit;
-
-free_dev_exit:
-	nci_free_device(drv->ndev);
-
-exit:
-	return rc;
-}
-
-static int nfcwilink_remove(struct platform_device *pdev)
-{
-	struct nfcwilink *drv = dev_get_drvdata(&pdev->dev);
-	struct nci_dev *ndev;
-
-	if (!drv)
-		return -EFAULT;
-
-	ndev = drv->ndev;
-
-	nci_unregister_device(ndev);
-	nci_free_device(ndev);
-
-	return 0;
-}
-
-static struct platform_driver nfcwilink_driver = {
-	.probe = nfcwilink_probe,
-	.remove = nfcwilink_remove,
-	.driver = {
-		.name = "nfcwilink",
-	},
-};
-
-module_platform_driver(nfcwilink_driver);
-
-/* ------ Module Info ------ */
-
-MODULE_AUTHOR("Ilan Elias <ilane@ti.com>");
-MODULE_DESCRIPTION("NFC Driver for TI Shared Transport");
-MODULE_LICENSE("GPL");
-- 
2.10.1

^ permalink raw reply related

* RE: [RFC 2/3] cfg80211: Disallow moving out of operating DFS channel in non-ETSI
From: Jean-Pierre Tosoni @ 2017-01-25 18:20 UTC (permalink / raw)
  To: 'Vasanthakumar Thiagarajan'; +Cc: linux-wireless
In-Reply-To: <1485343870-23601-3-git-send-email-vthiagar@qti.qualcomm.com>

> -----Message d'origine-----
> De : linux-wireless-owner@vger.kernel.org [mailto:linux-wireless-
> owner@vger.kernel.org] De la part de Vasanthakumar Thiagarajan
> Envoyé : mercredi 25 janvier 2017 12:31
> À : johannes@sipsolutions.net
> Cc : linux-wireless@vger.kernel.org; Vasanthakumar Thiagarajan
> Objet : [RFC 2/3] cfg80211: Disallow moving out of operating DFS channel
> in non-ETSI
> 
> For non-ETSI regulatory domain, CAC result on DFS channel may not be valid
> once moving out of that channel (as done during remain-on-channel,
> scannning and off-channel tx).
> Running CAC on an operating DFS channel after every off-channel operation
> will only add complexity and disturb the current link. Better do not allow
> any off-channel switch from a DFS operating channel in non-ETSI domain.
> 

Moving out should be forbidden only to "master" devices i.e. AP, mesh,
ad-hoc.
"Slave" devices i.e. client stations, are not responsible for detecting
radars, hence, they can do an off-channel scan and go back to a "DFS
operating channel" without waiting for CAC.

It looks like your patch would forbid multichannel scan ?



> Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>
> ---
>  net/wireless/nl80211.c | 38 ++++++++++++++++++++++++++++++++++++++
>  1 file changed, 38 insertions(+)
> 
> diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index
> 63dfa60..c614af4 100644
> --- a/net/wireless/nl80211.c
> +++ b/net/wireless/nl80211.c
> @@ -6506,6 +6506,17 @@ static int nl80211_parse_random_mac(struct nlattr
> **attrs,
>  	return 0;
>  }
> 
> +static bool cfg80211_off_channel_oper_allowed(struct wireless_dev
> +*wdev) {
> +	if (!cfg80211_beaconing_iface_active(wdev))
> +		return true;
> +
> +	if (!(wdev->chandef.chan->flags & IEEE80211_CHAN_RADAR))
> +		return true;
> +
> +	return regulatory_pre_cac_allowed(wdev->wiphy);
> +}
> +
>  static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info
> *info)  {
>  	struct cfg80211_registered_device *rdev = info->user_ptr[0]; @@ -
> 6631,6 +6642,21 @@ static int nl80211_trigger_scan(struct sk_buff *skb,
> struct genl_info *info)
> 
>  	request->n_channels = i;
> 
> +	if (!cfg80211_off_channel_oper_allowed(wdev)) {
> +		struct ieee80211_channel *chan;
> +
> +		if (request->n_channels != 1) {
> +			err = -EBUSY;
> +			goto out_free;
> +		}
> +
> +		chan = request->channels[0];
> +		if (chan->center_freq != wdev->chandef.chan->center_freq) {
> +			err = -EBUSY;
> +			goto out_free;
> +		}
> +	}
> +
>  	i = 0;
>  	if (n_ssids) {
>  		nla_for_each_nested(attr, info-
> >attrs[NL80211_ATTR_SCAN_SSIDS], tmp) { @@ -9053,6 +9079,7 @@ static int
> nl80211_remain_on_channel(struct sk_buff *skb,
>  	struct cfg80211_registered_device *rdev = info->user_ptr[0];
>  	struct wireless_dev *wdev = info->user_ptr[1];
>  	struct cfg80211_chan_def chandef;
> +	const struct cfg80211_chan_def *compat_chandef;
>  	struct sk_buff *msg;
>  	void *hdr;
>  	u64 cookie;
> @@ -9081,6 +9108,14 @@ static int nl80211_remain_on_channel(struct sk_buff
> *skb,
>  	if (err)
>  		return err;
> 
> +	if (!(cfg80211_off_channel_oper_allowed(wdev) ||
> +	      cfg80211_chandef_identical(&wdev->chandef, &chandef))) {
> +		compat_chandef = cfg80211_chandef_compatible(&wdev->chandef,
> +							     &chandef);
> +		if (compat_chandef != &chandef)
> +			return -EBUSY;
> +	}
> +
>  	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
>  	if (!msg)
>  		return -ENOMEM;
> @@ -9256,6 +9291,9 @@ static int nl80211_tx_mgmt(struct sk_buff *skb,
> struct genl_info *info)
>  	if (!chandef.chan && params.offchan)
>  		return -EINVAL;
> 
> +	if (params.offchan && !cfg80211_off_channel_oper_allowed(wdev))
> +		return -EBUSY;
> +
>  	params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
>  	params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
> 
> --
> 1.9.1

^ permalink raw reply

* [PATCH 1/4] ath9k: rename tx_complete_work to hw_check_work
From: Felix Fietkau @ 2017-01-25 16:36 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo

Also include common MAC alive check. This should make the hang checks
more reliable for modes where beacons are not sent and is used as a
starting point for further hang check improvements

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 drivers/net/wireless/ath/ath9k/ath9k.h |  6 ++---
 drivers/net/wireless/ath/ath9k/init.c  |  1 +
 drivers/net/wireless/ath/ath9k/link.c  | 46 ++++++++++++++++++----------------
 drivers/net/wireless/ath/ath9k/main.c  | 10 +++++---
 drivers/net/wireless/ath/ath9k/xmit.c  |  2 --
 5 files changed, 35 insertions(+), 30 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 331947b6a667..b2fa44adc60e 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -108,7 +108,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
 #define ATH_AGGR_MIN_QDEPTH        2
 /* minimum h/w qdepth for non-aggregated traffic */
 #define ATH_NON_AGGR_MIN_QDEPTH    8
-#define ATH_TX_COMPLETE_POLL_INT   1000
+#define ATH_HW_CHECK_POLL_INT      1000
 #define ATH_TXFIFO_DEPTH           8
 #define ATH_TX_ERROR               0x01
 
@@ -745,7 +745,7 @@ void ath9k_csa_update(struct ath_softc *sc);
 #define ATH_PAPRD_TIMEOUT         100 /* msecs */
 #define ATH_PLL_WORK_INTERVAL     100
 
-void ath_tx_complete_poll_work(struct work_struct *work);
+void ath_hw_check_work(struct work_struct *work);
 void ath_reset_work(struct work_struct *work);
 bool ath_hw_check(struct ath_softc *sc);
 void ath_hw_pll_work(struct work_struct *work);
@@ -1053,7 +1053,7 @@ struct ath_softc {
 #ifdef CONFIG_ATH9K_DEBUGFS
 	struct ath9k_debug debug;
 #endif
-	struct delayed_work tx_complete_work;
+	struct delayed_work hw_check_work;
 	struct delayed_work hw_pll_work;
 	struct timer_list sleep_timer;
 
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 084ad1bd495f..a2f7f48bbb92 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -681,6 +681,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
 	INIT_WORK(&sc->hw_reset_work, ath_reset_work);
 	INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
 	INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
+	INIT_DELAYED_WORK(&sc->hw_check_work, ath_hw_check_work);
 
 	ath9k_init_channel_context(sc);
 
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c
index 5ad0feeebc86..27c50562dc47 100644
--- a/drivers/net/wireless/ath/ath9k/link.c
+++ b/drivers/net/wireless/ath/ath9k/link.c
@@ -20,20 +20,13 @@
  * TX polling - checks if the TX engine is stuck somewhere
  * and issues a chip reset if so.
  */
-void ath_tx_complete_poll_work(struct work_struct *work)
+static bool ath_tx_complete_check(struct ath_softc *sc)
 {
-	struct ath_softc *sc = container_of(work, struct ath_softc,
-					    tx_complete_work.work);
 	struct ath_txq *txq;
 	int i;
-	bool needreset = false;
-
 
-	if (sc->tx99_state) {
-		ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
-			"skip tx hung detection on tx99\n");
-		return;
-	}
+	if (sc->tx99_state)
+		return true;
 
 	for (i = 0; i < IEEE80211_NUM_ACS; i++) {
 		txq = sc->tx.txq_map[i];
@@ -41,25 +34,36 @@ void ath_tx_complete_poll_work(struct work_struct *work)
 		ath_txq_lock(sc, txq);
 		if (txq->axq_depth) {
 			if (txq->axq_tx_inprogress) {
-				needreset = true;
 				ath_txq_unlock(sc, txq);
-				break;
-			} else {
-				txq->axq_tx_inprogress = true;
+				goto reset;
 			}
+
+			txq->axq_tx_inprogress = true;
 		}
 		ath_txq_unlock(sc, txq);
 	}
 
-	if (needreset) {
-		ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
-			"tx hung, resetting the chip\n");
-		ath9k_queue_reset(sc, RESET_TYPE_TX_HANG);
+	return true;
+
+reset:
+	ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
+		"tx hung, resetting the chip\n");
+	ath9k_queue_reset(sc, RESET_TYPE_TX_HANG);
+	return false;
+
+}
+
+void ath_hw_check_work(struct work_struct *work)
+{
+	struct ath_softc *sc = container_of(work, struct ath_softc,
+					    hw_check_work.work);
+
+	if (!ath_hw_check(sc) ||
+	    !ath_tx_complete_check(sc))
 		return;
-	}
 
-	ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
-				     msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
+	ieee80211_queue_delayed_work(sc->hw, &sc->hw_check_work,
+				     msecs_to_jiffies(ATH_HW_CHECK_POLL_INT));
 }
 
 /*
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 58f06ce9a4cf..0345d6ec564f 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -181,7 +181,7 @@ void ath9k_ps_restore(struct ath_softc *sc)
 static void __ath_cancel_work(struct ath_softc *sc)
 {
 	cancel_work_sync(&sc->paprd_work);
-	cancel_delayed_work_sync(&sc->tx_complete_work);
+	cancel_delayed_work_sync(&sc->hw_check_work);
 	cancel_delayed_work_sync(&sc->hw_pll_work);
 
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
@@ -198,7 +198,8 @@ void ath_cancel_work(struct ath_softc *sc)
 
 void ath_restart_work(struct ath_softc *sc)
 {
-	ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
+	ieee80211_queue_delayed_work(sc->hw, &sc->hw_check_work,
+				     ATH_HW_CHECK_POLL_INT);
 
 	if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9330(sc->sc_ah))
 		ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
@@ -2091,7 +2092,7 @@ void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop,
 	int timeout;
 	bool drain_txq;
 
-	cancel_delayed_work_sync(&sc->tx_complete_work);
+	cancel_delayed_work_sync(&sc->hw_check_work);
 
 	if (ah->ah_flags & AH_UNPLUGGED) {
 		ath_dbg(common, ANY, "Device has been unplugged!\n");
@@ -2129,7 +2130,8 @@ void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop,
 		ath9k_ps_restore(sc);
 	}
 
-	ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0);
+	ieee80211_queue_delayed_work(hw, &sc->hw_check_work,
+				     ATH_HW_CHECK_POLL_INT);
 }
 
 static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw)
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 6962a63b869a..8f9a87915ba9 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -2916,8 +2916,6 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
 		return error;
 	}
 
-	INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
-
 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
 		error = ath_tx_edma_init(sc);
 
-- 
2.11.0

^ permalink raw reply related

* [PATCH 2/4] ath9k_hw: check if the chip failed to wake up
From: Felix Fietkau @ 2017-01-25 16:36 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo
In-Reply-To: <20170125163654.66431-1-nbd@nbd.name>

In an RFC patch, Sven Eckelmann and Simon Wunderlich reported:

"QCA 802.11n chips (especially AR9330/AR9340) sometimes end up in a
state in which a read of AR_CFG always returns 0xdeadbeef.
This should not happen when when the power_mode of the device is
ATH9K_PM_AWAKE."

Include the check for the default register state in the existing MAC
hang check.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 drivers/net/wireless/ath/ath9k/hw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 6989f89b3116..11fd98df2c43 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1623,6 +1623,10 @@ bool ath9k_hw_check_alive(struct ath_hw *ah)
 	int count = 50;
 	u32 reg, last_val;
 
+	/* Check if chip failed to wake up */
+	if (REG_READ(ah, AR_CFG) == 0xdeadbeef)
+		return false;
+
 	if (AR_SREV_9300(ah))
 		return !ath9k_hw_detect_mac_hang(ah);
 
-- 
2.11.0

^ permalink raw reply related

* [PATCH 4/4] ath9k: fix race condition in enabling/disabling IRQs
From: Felix Fietkau @ 2017-01-25 16:36 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo
In-Reply-To: <20170125163654.66431-1-nbd@nbd.name>

The code currently relies on refcounting to disable IRQs from within the
IRQ handler and re-enabling them again after the tasklet has run.

However, due to race conditions sometimes the IRQ handler might be
called twice, or the tasklet may not run at all (if interrupted in the
middle of a reset).

This can cause nasty imbalances in the irq-disable refcount which will
get the driver permanently stuck until the entire radio has been stopped
and started again (ath_reset will not recover from this).

Instead of using this fragile logic, change the code to ensure that
running the irq handler during tasklet processing is safe, and leave the
refcount untouched.

Cc: stable@vger.kernel.org
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 drivers/net/wireless/ath/ath9k/ath9k.h |  1 +
 drivers/net/wireless/ath/ath9k/init.c  |  1 +
 drivers/net/wireless/ath/ath9k/mac.c   | 44 ++++++++++++++++++++++++++--------
 drivers/net/wireless/ath/ath9k/mac.h   |  1 +
 drivers/net/wireless/ath/ath9k/main.c  | 15 ++++++++----
 5 files changed, 48 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index a396c99ee84d..46dfca522be3 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -998,6 +998,7 @@ struct ath_softc {
 	struct survey_info *cur_survey;
 	struct survey_info survey[ATH9K_NUM_CHANNELS];
 
+	spinlock_t intr_lock;
 	struct tasklet_struct intr_tq;
 	struct tasklet_struct bcon_tasklet;
 	struct ath_hw *sc_ah;
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index a2f7f48bbb92..fa4b3cc1ba22 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -669,6 +669,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
 		common->bt_ant_diversity = 1;
 
 	spin_lock_init(&common->cc_lock);
+	spin_lock_init(&sc->intr_lock);
 	spin_lock_init(&sc->sc_serial_rw);
 	spin_lock_init(&sc->sc_pm_lock);
 	spin_lock_init(&sc->chan_lock);
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index f79587570af6..c059dfcaca22 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -810,21 +810,12 @@ void ath9k_hw_disable_interrupts(struct ath_hw *ah)
 }
 EXPORT_SYMBOL(ath9k_hw_disable_interrupts);
 
-void ath9k_hw_enable_interrupts(struct ath_hw *ah)
+static void __ath9k_hw_enable_interrupts(struct ath_hw *ah)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
 	u32 sync_default = AR_INTR_SYNC_DEFAULT;
 	u32 async_mask;
 
-	if (!(ah->imask & ATH9K_INT_GLOBAL))
-		return;
-
-	if (!atomic_inc_and_test(&ah->intr_ref_cnt)) {
-		ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n",
-			atomic_read(&ah->intr_ref_cnt));
-		return;
-	}
-
 	if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
 	    AR_SREV_9561(ah))
 		sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
@@ -846,6 +837,39 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah)
 	ath_dbg(common, INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
 		REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
 }
+
+void ath9k_hw_resume_interrupts(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	if (!(ah->imask & ATH9K_INT_GLOBAL))
+		return;
+
+	if (atomic_read(&ah->intr_ref_cnt) != 0) {
+		ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n",
+			atomic_read(&ah->intr_ref_cnt));
+		return;
+	}
+
+	__ath9k_hw_enable_interrupts(ah);
+}
+EXPORT_SYMBOL(ath9k_hw_resume_interrupts);
+
+void ath9k_hw_enable_interrupts(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	if (!(ah->imask & ATH9K_INT_GLOBAL))
+		return;
+
+	if (!atomic_inc_and_test(&ah->intr_ref_cnt)) {
+		ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n",
+			atomic_read(&ah->intr_ref_cnt));
+		return;
+	}
+
+	__ath9k_hw_enable_interrupts(ah);
+}
 EXPORT_SYMBOL(ath9k_hw_enable_interrupts);
 
 void ath9k_hw_set_interrupts(struct ath_hw *ah)
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index 3bab01435a86..770fc11b41d1 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -744,6 +744,7 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah);
 void ath9k_hw_enable_interrupts(struct ath_hw *ah);
 void ath9k_hw_disable_interrupts(struct ath_hw *ah);
 void ath9k_hw_kill_interrupts(struct ath_hw *ah);
+void ath9k_hw_resume_interrupts(struct ath_hw *ah);
 
 void ar9002_hw_attach_mac_ops(struct ath_hw *ah);
 
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 985b1cade4a4..d8ea087bdd07 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -375,9 +375,14 @@ void ath9k_tasklet(unsigned long data)
 	struct ath_common *common = ath9k_hw_common(ah);
 	enum ath_reset_type type;
 	unsigned long flags;
-	u32 status = sc->intrstatus;
+	u32 status;
 	u32 rxmask;
 
+	spin_lock_irqsave(&sc->intr_lock, flags);
+	status = sc->intrstatus;
+	sc->intrstatus = 0;
+	spin_unlock_irqrestore(&sc->intr_lock, flags);
+
 	ath9k_ps_wakeup(sc);
 	spin_lock(&sc->sc_pcu_lock);
 
@@ -480,7 +485,7 @@ void ath9k_tasklet(unsigned long data)
 	ath9k_btcoex_handle_interrupt(sc, status);
 
 	/* re-enable hardware interrupt */
-	ath9k_hw_enable_interrupts(ah);
+	ath9k_hw_resume_interrupts(ah);
 out:
 	spin_unlock(&sc->sc_pcu_lock);
 	ath9k_ps_restore(sc);
@@ -544,7 +549,9 @@ irqreturn_t ath_isr(int irq, void *dev)
 		return IRQ_NONE;
 
 	/* Cache the status */
-	sc->intrstatus = status;
+	spin_lock(&sc->intr_lock);
+	sc->intrstatus |= status;
+	spin_unlock(&sc->intr_lock);
 
 	if (status & SCHED_INTR)
 		sched = true;
@@ -590,7 +597,7 @@ irqreturn_t ath_isr(int irq, void *dev)
 
 	if (sched) {
 		/* turn off every interrupt */
-		ath9k_hw_disable_interrupts(ah);
+		ath9k_hw_kill_interrupts(ah);
 		tasklet_schedule(&sc->intr_tq);
 	}
 
-- 
2.11.0

^ permalink raw reply related

* [PATCH 3/4] ath9k: check for deaf rx path state
From: Felix Fietkau @ 2017-01-25 16:36 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo
In-Reply-To: <20170125163654.66431-1-nbd@nbd.name>

Various chips occasionally run into a state where the tx path still
appears to be working normally, but the rx path is deaf.

There is no known register signature to check for this state explicitly,
so use the lack of rx interrupts as an indicator.

This detection is prone to false positives, since a device could also
simply be in an environment where there are no frames on the air.
However, in this case doing a reset should be harmless since it's
obviously not interrupting any real activity. To avoid confusion, call
the reset counters in this case "Rx path inactive" instead of something
like "Rx path deaf", since it may not be an indication of a real
hardware failure.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 drivers/net/wireless/ath/ath9k/ath9k.h |  1 +
 drivers/net/wireless/ath/ath9k/debug.c |  1 +
 drivers/net/wireless/ath/ath9k/debug.h |  1 +
 drivers/net/wireless/ath/ath9k/link.c  | 16 +++++++++++++++-
 drivers/net/wireless/ath/ath9k/main.c  |  2 ++
 5 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index b2fa44adc60e..a396c99ee84d 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -1027,6 +1027,7 @@ struct ath_softc {
 
 	u8 gtt_cnt;
 	u32 intrstatus;
+	u32 rx_active;
 	u16 ps_flags; /* PS_* */
 	bool ps_enabled;
 	bool ps_idle;
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 43930c336987..a42402413659 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -763,6 +763,7 @@ static int read_file_reset(struct seq_file *file, void *data)
 		[RESET_TYPE_BEACON_STUCK] = "Stuck Beacon",
 		[RESET_TYPE_MCI] = "MCI Reset",
 		[RESET_TYPE_CALIBRATION] = "Calibration error",
+		[RESET_TYPE_RX_INACTIVE] = "Rx path inactive",
 		[RESET_TX_DMA_ERROR] = "Tx DMA stop error",
 		[RESET_RX_DMA_ERROR] = "Rx DMA stop error",
 	};
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 249f8141cd00..a40c84e8d0b6 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -50,6 +50,7 @@ enum ath_reset_type {
 	RESET_TYPE_BEACON_STUCK,
 	RESET_TYPE_MCI,
 	RESET_TYPE_CALIBRATION,
+	RESET_TYPE_RX_INACTIVE,
 	RESET_TX_DMA_ERROR,
 	RESET_RX_DMA_ERROR,
 	__RESET_TYPE_MAX
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c
index 27c50562dc47..b9d92aae00c2 100644
--- a/drivers/net/wireless/ath/ath9k/link.c
+++ b/drivers/net/wireless/ath/ath9k/link.c
@@ -53,13 +53,27 @@ static bool ath_tx_complete_check(struct ath_softc *sc)
 
 }
 
+static bool ath_rx_active_check(struct ath_softc *sc)
+{
+	if (sc->rx_active) {
+		sc->rx_active = 0;
+		return true;
+	}
+
+	ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
+		"rx path inactive, resetting the chip\n");
+	ath9k_queue_reset(sc, RESET_TYPE_RX_INACTIVE);
+	return false;
+}
+
 void ath_hw_check_work(struct work_struct *work)
 {
 	struct ath_softc *sc = container_of(work, struct ath_softc,
 					    hw_check_work.work);
 
 	if (!ath_hw_check(sc) ||
-	    !ath_tx_complete_check(sc))
+	    !ath_tx_complete_check(sc) ||
+	    !ath_rx_active_check(sc))
 		return;
 
 	ieee80211_queue_delayed_work(sc->hw, &sc->hw_check_work,
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 0345d6ec564f..985b1cade4a4 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -269,6 +269,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
 	}
 
 	sc->gtt_cnt = 0;
+	sc->rx_active = 1;
 
 	ath9k_hw_set_interrupts(ah);
 	ath9k_hw_enable_interrupts(ah);
@@ -452,6 +453,7 @@ void ath9k_tasklet(unsigned long data)
 			ath_rx_tasklet(sc, 0, true);
 
 		ath_rx_tasklet(sc, 0, false);
+		sc->rx_active = 1;
 	}
 
 	if (status & ATH9K_INT_TX) {
-- 
2.11.0

^ permalink raw reply related

* [PATCH] wireless: radiotap: rewrite the radiotap header file
From: Johannes Berg @ 2017-01-25 14:31 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

The header file has grown a lot of #define's etc, but
they are nicer as enums, so rewrite the file from the
documentation as such.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 include/net/ieee80211_radiotap.h | 444 +++++++++++++--------------------------
 1 file changed, 144 insertions(+), 300 deletions(-)

diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h
index d0e7e3f8e67a..f4ab5c6b5ed3 100644
--- a/include/net/ieee80211_radiotap.h
+++ b/include/net/ieee80211_radiotap.h
@@ -1,201 +1,39 @@
-/*
- * Copyright (c) 2003, 2004 David Young.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of David Young may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DAVID
- * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- */
-
-/*
- * Modifications to fit into the linux IEEE 802.11 stack,
- * Mike Kershaw (dragorn@kismetwireless.net)
- */
-
-#ifndef IEEE80211RADIOTAP_H
-#define IEEE80211RADIOTAP_H
+#ifndef __RADIOTAP_H
+#define __RADIOTAP_H
 
-#include <linux/if_ether.h>
 #include <linux/kernel.h>
 #include <asm/unaligned.h>
 
-/* Base version of the radiotap packet header data */
-#define PKTHDR_RADIOTAP_VERSION		0
-
-/* A generic radio capture format is desirable. There is one for
- * Linux, but it is neither rigidly defined (there were not even
- * units given for some fields) nor easily extensible.
- *
- * I suggest the following extensible radio capture format. It is
- * based on a bitmap indicating which fields are present.
- *
- * I am trying to describe precisely what the application programmer
- * should expect in the following, and for that reason I tell the
- * units and origin of each measurement (where it applies), or else I
- * use sufficiently weaselly language ("is a monotonically nondecreasing
- * function of...") that I cannot set false expectations for lawyerly
- * readers.
- */
-
-/*
- * The radio capture header precedes the 802.11 header.
- * All data in the header is little endian on all platforms.
+/**
+ * struct ieee82011_radiotap_header - base radiotap header
  */
 struct ieee80211_radiotap_header {
-	u8 it_version;		/* Version 0. Only increases
-				 * for drastic changes,
-				 * introduction of compatible
-				 * new fields does not count.
-				 */
-	u8 it_pad;
-	__le16 it_len;		/* length of the whole
-				 * header in bytes, including
-				 * it_version, it_pad,
-				 * it_len, and data fields.
-				 */
-	__le32 it_present;	/* A bitmap telling which
-				 * fields are present. Set bit 31
-				 * (0x80000000) to extend the
-				 * bitmap by another 32 bits.
-				 * Additional extensions are made
-				 * by setting bit 31.
-				 */
+	/**
+	 * @it_version: radiotap version, always 0
+	 */
+	uint8_t it_version;
+
+	/**
+	 * @it_pad: padding (or alignment)
+	 */
+	uint8_t it_pad;
+
+	/**
+	 * @it_len: overall radiotap header length
+	 */
+	__le16 it_len;
+
+	/**
+	 * @it_present: (first) present word
+	 */
+	__le32 it_present;
 } __packed;
 
-/* Name                                 Data type    Units
- * ----                                 ---------    -----
- *
- * IEEE80211_RADIOTAP_TSFT              __le64       microseconds
- *
- *      Value in microseconds of the MAC's 64-bit 802.11 Time
- *      Synchronization Function timer when the first bit of the
- *      MPDU arrived at the MAC. For received frames, only.
- *
- * IEEE80211_RADIOTAP_CHANNEL           2 x __le16   MHz, bitmap
- *
- *      Tx/Rx frequency in MHz, followed by flags (see below).
- *
- * IEEE80211_RADIOTAP_FHSS              __le16       see below
- *
- *      For frequency-hopping radios, the hop set (first byte)
- *      and pattern (second byte).
- *
- * IEEE80211_RADIOTAP_RATE              u8           500kb/s
- *
- *      Tx/Rx data rate
- *
- * IEEE80211_RADIOTAP_DBM_ANTSIGNAL     s8           decibels from
- *                                                   one milliwatt (dBm)
- *
- *      RF signal power at the antenna, decibel difference from
- *      one milliwatt.
- *
- * IEEE80211_RADIOTAP_DBM_ANTNOISE      s8           decibels from
- *                                                   one milliwatt (dBm)
- *
- *      RF noise power at the antenna, decibel difference from one
- *      milliwatt.
- *
- * IEEE80211_RADIOTAP_DB_ANTSIGNAL      u8           decibel (dB)
- *
- *      RF signal power at the antenna, decibel difference from an
- *      arbitrary, fixed reference.
- *
- * IEEE80211_RADIOTAP_DB_ANTNOISE       u8           decibel (dB)
- *
- *      RF noise power at the antenna, decibel difference from an
- *      arbitrary, fixed reference point.
- *
- * IEEE80211_RADIOTAP_LOCK_QUALITY      __le16       unitless
- *
- *      Quality of Barker code lock. Unitless. Monotonically
- *      nondecreasing with "better" lock strength. Called "Signal
- *      Quality" in datasheets.  (Is there a standard way to measure
- *      this?)
- *
- * IEEE80211_RADIOTAP_TX_ATTENUATION    __le16       unitless
- *
- *      Transmit power expressed as unitless distance from max
- *      power set at factory calibration.  0 is max power.
- *      Monotonically nondecreasing with lower power levels.
- *
- * IEEE80211_RADIOTAP_DB_TX_ATTENUATION __le16       decibels (dB)
- *
- *      Transmit power expressed as decibel distance from max power
- *      set at factory calibration.  0 is max power.  Monotonically
- *      nondecreasing with lower power levels.
- *
- * IEEE80211_RADIOTAP_DBM_TX_POWER      s8           decibels from
- *                                                   one milliwatt (dBm)
- *
- *      Transmit power expressed as dBm (decibels from a 1 milliwatt
- *      reference). This is the absolute power level measured at
- *      the antenna port.
- *
- * IEEE80211_RADIOTAP_FLAGS             u8           bitmap
- *
- *      Properties of transmitted and received frames. See flags
- *      defined below.
- *
- * IEEE80211_RADIOTAP_ANTENNA           u8           antenna index
- *
- *      Unitless indication of the Rx/Tx antenna for this packet.
- *      The first antenna is antenna 0.
- *
- * IEEE80211_RADIOTAP_RX_FLAGS          __le16       bitmap
- *
- *     Properties of received frames. See flags defined below.
- *
- * IEEE80211_RADIOTAP_TX_FLAGS          __le16       bitmap
- *
- *     Properties of transmitted frames. See flags defined below.
- *
- * IEEE80211_RADIOTAP_RTS_RETRIES       u8           data
- *
- *     Number of rts retries a transmitted frame used.
- *
- * IEEE80211_RADIOTAP_DATA_RETRIES      u8           data
- *
- *     Number of unicast retries a transmitted frame used.
- *
- * IEEE80211_RADIOTAP_MCS	u8, u8, u8		unitless
- *
- *     Contains a bitmap of known fields/flags, the flags, and
- *     the MCS index.
- *
- * IEEE80211_RADIOTAP_AMPDU_STATUS	u32, u16, u8, u8	unitless
- *
- *	Contains the AMPDU information for the subframe.
- *
- * IEEE80211_RADIOTAP_VHT	u16, u8, u8, u8[4], u8, u8, u16
- *
- *	Contains VHT information about this frame.
- *
- * IEEE80211_RADIOTAP_TIMESTAMP		u64, u16, u8, u8	variable
- *
- *	Contains timestamp information for this frame.
- */
-enum ieee80211_radiotap_type {
+/* version is always 0 */
+#define PKTHDR_RADIOTAP_VERSION	0
+
+/* see the radiotap website for the descriptions */
+enum ieee80211_radiotap_presence {
 	IEEE80211_RADIOTAP_TSFT = 0,
 	IEEE80211_RADIOTAP_FLAGS = 1,
 	IEEE80211_RADIOTAP_RATE = 2,
@@ -214,7 +52,7 @@ enum ieee80211_radiotap_type {
 	IEEE80211_RADIOTAP_TX_FLAGS = 15,
 	IEEE80211_RADIOTAP_RTS_RETRIES = 16,
 	IEEE80211_RADIOTAP_DATA_RETRIES = 17,
-
+	/* 18 is XChannel, but it's not defined yet */
 	IEEE80211_RADIOTAP_MCS = 19,
 	IEEE80211_RADIOTAP_AMPDU_STATUS = 20,
 	IEEE80211_RADIOTAP_VHT = 21,
@@ -226,129 +64,135 @@ enum ieee80211_radiotap_type {
 	IEEE80211_RADIOTAP_EXT = 31
 };
 
-/* Channel flags. */
-#define	IEEE80211_CHAN_TURBO	0x0010	/* Turbo channel */
-#define	IEEE80211_CHAN_CCK	0x0020	/* CCK channel */
-#define	IEEE80211_CHAN_OFDM	0x0040	/* OFDM channel */
-#define	IEEE80211_CHAN_2GHZ	0x0080	/* 2 GHz spectrum channel. */
-#define	IEEE80211_CHAN_5GHZ	0x0100	/* 5 GHz spectrum channel */
-#define	IEEE80211_CHAN_PASSIVE	0x0200	/* Only passive scan allowed */
-#define	IEEE80211_CHAN_DYN	0x0400	/* Dynamic CCK-OFDM channel */
-#define	IEEE80211_CHAN_GFSK	0x0800	/* GFSK channel (FHSS PHY) */
-#define	IEEE80211_CHAN_GSM	0x1000	/* GSM (900 MHz) */
-#define	IEEE80211_CHAN_STURBO	0x2000	/* Static Turbo */
-#define	IEEE80211_CHAN_HALF	0x4000	/* Half channel (10 MHz wide) */
-#define	IEEE80211_CHAN_QUARTER	0x8000	/* Quarter channel (5 MHz wide) */
-
-/* For IEEE80211_RADIOTAP_FLAGS */
-#define	IEEE80211_RADIOTAP_F_CFP	0x01	/* sent/received
-						 * during CFP
-						 */
-#define	IEEE80211_RADIOTAP_F_SHORTPRE	0x02	/* sent/received
-						 * with short
-						 * preamble
-						 */
-#define	IEEE80211_RADIOTAP_F_WEP	0x04	/* sent/received
-						 * with WEP encryption
-						 */
-#define	IEEE80211_RADIOTAP_F_FRAG	0x08	/* sent/received
-						 * with fragmentation
-						 */
-#define	IEEE80211_RADIOTAP_F_FCS	0x10	/* frame includes FCS */
-#define	IEEE80211_RADIOTAP_F_DATAPAD	0x20	/* frame has padding between
-						 * 802.11 header and payload
-						 * (to 32-bit boundary)
-						 */
-#define IEEE80211_RADIOTAP_F_BADFCS	0x40	/* bad FCS */
-
-/* For IEEE80211_RADIOTAP_RX_FLAGS */
-#define IEEE80211_RADIOTAP_F_RX_BADPLCP	0x0002	/* frame has bad PLCP */
+/* for IEEE80211_RADIOTAP_FLAGS */
+enum ieee80211_radiotap_flags {
+	IEEE80211_RADIOTAP_F_CFP = 0x01,
+	IEEE80211_RADIOTAP_F_SHORTPRE = 0x02,
+	IEEE80211_RADIOTAP_F_WEP = 0x04,
+	IEEE80211_RADIOTAP_F_FRAG = 0x08,
+	IEEE80211_RADIOTAP_F_FCS = 0x10,
+	IEEE80211_RADIOTAP_F_DATAPAD = 0x20,
+	IEEE80211_RADIOTAP_F_BADFCS = 0x40,
+};
 
-/* For IEEE80211_RADIOTAP_TX_FLAGS */
-#define IEEE80211_RADIOTAP_F_TX_FAIL	0x0001	/* failed due to excessive
-						 * retries */
-#define IEEE80211_RADIOTAP_F_TX_CTS	0x0002	/* used cts 'protection' */
-#define IEEE80211_RADIOTAP_F_TX_RTS	0x0004	/* used rts/cts handshake */
-#define IEEE80211_RADIOTAP_F_TX_NOACK	0x0008	/* don't expect an ack */
+/* for IEEE80211_RADIOTAP_CHANNEL */
+enum ieee80211_radiotap_channel_flags {
+	IEEE80211_CHAN_CCK = 0x0020,
+	IEEE80211_CHAN_OFDM = 0x0040,
+	IEEE80211_CHAN_2GHZ = 0x0080,
+	IEEE80211_CHAN_5GHZ = 0x0100,
+	IEEE80211_CHAN_DYN = 0x0400,
+	IEEE80211_CHAN_HALF = 0x4000,
+	IEEE80211_CHAN_QUARTER = 0x8000,
+};
 
+/* for IEEE80211_RADIOTAP_RX_FLAGS */
+enum ieee80211_radiotap_rx_flags {
+	IEEE80211_RADIOTAP_F_RX_BADPLCP = 0x0002,
+};
 
-/* For IEEE80211_RADIOTAP_MCS */
-#define IEEE80211_RADIOTAP_MCS_HAVE_BW		0x01
-#define IEEE80211_RADIOTAP_MCS_HAVE_MCS		0x02
-#define IEEE80211_RADIOTAP_MCS_HAVE_GI		0x04
-#define IEEE80211_RADIOTAP_MCS_HAVE_FMT		0x08
-#define IEEE80211_RADIOTAP_MCS_HAVE_FEC		0x10
-#define IEEE80211_RADIOTAP_MCS_HAVE_STBC	0x20
+/* for IEEE80211_RADIOTAP_TX_FLAGS */
+enum ieee80211_radiotap_tx_flags {
+	IEEE80211_RADIOTAP_F_TX_FAIL = 0x0001,
+	IEEE80211_RADIOTAP_F_TX_CTS = 0x0002,
+	IEEE80211_RADIOTAP_F_TX_RTS = 0x0004,
+	IEEE80211_RADIOTAP_F_TX_NOACK = 0x0008,
+};
 
-#define IEEE80211_RADIOTAP_MCS_BW_MASK		0x03
-#define		IEEE80211_RADIOTAP_MCS_BW_20	0
-#define		IEEE80211_RADIOTAP_MCS_BW_40	1
-#define		IEEE80211_RADIOTAP_MCS_BW_20L	2
-#define		IEEE80211_RADIOTAP_MCS_BW_20U	3
-#define IEEE80211_RADIOTAP_MCS_SGI		0x04
-#define IEEE80211_RADIOTAP_MCS_FMT_GF		0x08
-#define IEEE80211_RADIOTAP_MCS_FEC_LDPC		0x10
-#define IEEE80211_RADIOTAP_MCS_STBC_MASK	0x60
-#define		IEEE80211_RADIOTAP_MCS_STBC_1	1
-#define		IEEE80211_RADIOTAP_MCS_STBC_2	2
-#define		IEEE80211_RADIOTAP_MCS_STBC_3	3
+/* for IEEE80211_RADIOTAP_MCS "have" flags */
+enum ieee80211_radiotap_mcs_have {
+	IEEE80211_RADIOTAP_MCS_HAVE_BW = 0x01,
+	IEEE80211_RADIOTAP_MCS_HAVE_MCS = 0x02,
+	IEEE80211_RADIOTAP_MCS_HAVE_GI = 0x04,
+	IEEE80211_RADIOTAP_MCS_HAVE_FMT = 0x08,
+	IEEE80211_RADIOTAP_MCS_HAVE_FEC = 0x10,
+	IEEE80211_RADIOTAP_MCS_HAVE_STBC = 0x20,
+};
 
-#define IEEE80211_RADIOTAP_MCS_STBC_SHIFT	5
+enum ieee80211_radiotap_mcs_flags {
+	IEEE80211_RADIOTAP_MCS_BW_MASK = 0x03,
+	IEEE80211_RADIOTAP_MCS_BW_20 = 0,
+	IEEE80211_RADIOTAP_MCS_BW_40 = 1,
+	IEEE80211_RADIOTAP_MCS_BW_20L = 2,
+	IEEE80211_RADIOTAP_MCS_BW_20U = 3,
+
+	IEEE80211_RADIOTAP_MCS_SGI = 0x04,
+	IEEE80211_RADIOTAP_MCS_FMT_GF = 0x08,
+	IEEE80211_RADIOTAP_MCS_FEC_LDPC = 0x10,
+	IEEE80211_RADIOTAP_MCS_STBC_MASK = 0x60,
+	IEEE80211_RADIOTAP_MCS_STBC_1 = 1,
+	IEEE80211_RADIOTAP_MCS_STBC_2 = 2,
+	IEEE80211_RADIOTAP_MCS_STBC_3 = 3,
+	IEEE80211_RADIOTAP_MCS_STBC_SHIFT = 5,
+};
 
-/* For IEEE80211_RADIOTAP_AMPDU_STATUS */
-#define IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN		0x0001
-#define IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN		0x0002
-#define IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN		0x0004
-#define IEEE80211_RADIOTAP_AMPDU_IS_LAST		0x0008
-#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR		0x0010
-#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN	0x0020
+/* for IEEE80211_RADIOTAP_AMPDU_STATUS */
+enum ieee80211_radiotap_ampdu_flags {
+	IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN = 0x0001,
+	IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN = 0x0002,
+	IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN = 0x0004,
+	IEEE80211_RADIOTAP_AMPDU_IS_LAST = 0x0008,
+	IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR = 0x0010,
+	IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN = 0x0020,
+};
 
-/* For IEEE80211_RADIOTAP_VHT */
-#define IEEE80211_RADIOTAP_VHT_KNOWN_STBC			0x0001
-#define IEEE80211_RADIOTAP_VHT_KNOWN_TXOP_PS_NA			0x0002
-#define IEEE80211_RADIOTAP_VHT_KNOWN_GI				0x0004
-#define IEEE80211_RADIOTAP_VHT_KNOWN_SGI_NSYM_DIS		0x0008
-#define IEEE80211_RADIOTAP_VHT_KNOWN_LDPC_EXTRA_OFDM_SYM	0x0010
-#define IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED			0x0020
-#define IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH			0x0040
-#define IEEE80211_RADIOTAP_VHT_KNOWN_GROUP_ID			0x0080
-#define IEEE80211_RADIOTAP_VHT_KNOWN_PARTIAL_AID		0x0100
+/* for IEEE80211_RADIOTAP_VHT */
+enum ieee80211_radiotap_vht_known {
+	IEEE80211_RADIOTAP_VHT_KNOWN_STBC = 0x0001,
+	IEEE80211_RADIOTAP_VHT_KNOWN_TXOP_PS_NA = 0x0002,
+	IEEE80211_RADIOTAP_VHT_KNOWN_GI = 0x0004,
+	IEEE80211_RADIOTAP_VHT_KNOWN_SGI_NSYM_DIS = 0x0008,
+	IEEE80211_RADIOTAP_VHT_KNOWN_LDPC_EXTRA_OFDM_SYM = 0x0010,
+	IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED = 0x0020,
+	IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH = 0x0040,
+	IEEE80211_RADIOTAP_VHT_KNOWN_GROUP_ID = 0x0080,
+	IEEE80211_RADIOTAP_VHT_KNOWN_PARTIAL_AID = 0x0100,
+};
 
-#define IEEE80211_RADIOTAP_VHT_FLAG_STBC			0x01
-#define IEEE80211_RADIOTAP_VHT_FLAG_TXOP_PS_NA			0x02
-#define IEEE80211_RADIOTAP_VHT_FLAG_SGI				0x04
-#define IEEE80211_RADIOTAP_VHT_FLAG_SGI_NSYM_M10_9		0x08
-#define IEEE80211_RADIOTAP_VHT_FLAG_LDPC_EXTRA_OFDM_SYM		0x10
-#define IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED			0x20
+enum ieee80211_radiotap_vht_flags {
+	IEEE80211_RADIOTAP_VHT_FLAG_STBC = 0x01,
+	IEEE80211_RADIOTAP_VHT_FLAG_TXOP_PS_NA = 0x02,
+	IEEE80211_RADIOTAP_VHT_FLAG_SGI = 0x04,
+	IEEE80211_RADIOTAP_VHT_FLAG_SGI_NSYM_M10_9 = 0x08,
+	IEEE80211_RADIOTAP_VHT_FLAG_LDPC_EXTRA_OFDM_SYM = 0x10,
+	IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED = 0x20,
+};
 
-#define IEEE80211_RADIOTAP_CODING_LDPC_USER0			0x01
-#define IEEE80211_RADIOTAP_CODING_LDPC_USER1			0x02
-#define IEEE80211_RADIOTAP_CODING_LDPC_USER2			0x04
-#define IEEE80211_RADIOTAP_CODING_LDPC_USER3			0x08
+enum ieee80211_radiotap_vht_coding {
+	IEEE80211_RADIOTAP_CODING_LDPC_USER0 = 0x01,
+	IEEE80211_RADIOTAP_CODING_LDPC_USER1 = 0x02,
+	IEEE80211_RADIOTAP_CODING_LDPC_USER2 = 0x04,
+	IEEE80211_RADIOTAP_CODING_LDPC_USER3 = 0x08,
+};
 
-/* For IEEE80211_RADIOTAP_TIMESTAMP */
-#define IEEE80211_RADIOTAP_TIMESTAMP_UNIT_MASK			0x000F
-#define IEEE80211_RADIOTAP_TIMESTAMP_UNIT_MS			0x0000
-#define IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US			0x0001
-#define IEEE80211_RADIOTAP_TIMESTAMP_UNIT_NS			0x0003
-#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_MASK			0x00F0
-#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_BEGIN_MDPU		0x0000
-#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_PLCP_SIG_ACQ		0x0010
-#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_PPDU		0x0020
-#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_MPDU		0x0030
-#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_UNKNOWN		0x00F0
+/* for IEEE80211_RADIOTAP_TIMESTAMP */
+enum ieee80211_radiotap_timestamp_unit_spos {
+	IEEE80211_RADIOTAP_TIMESTAMP_UNIT_MASK = 0x000F,
+	IEEE80211_RADIOTAP_TIMESTAMP_UNIT_MS = 0x0000,
+	IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US = 0x0001,
+	IEEE80211_RADIOTAP_TIMESTAMP_UNIT_NS = 0x0003,
+	IEEE80211_RADIOTAP_TIMESTAMP_SPOS_MASK = 0x00F0,
+	IEEE80211_RADIOTAP_TIMESTAMP_SPOS_BEGIN_MDPU = 0x0000,
+	IEEE80211_RADIOTAP_TIMESTAMP_SPOS_PLCP_SIG_ACQ = 0x0010,
+	IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_PPDU = 0x0020,
+	IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_MPDU = 0x0030,
+	IEEE80211_RADIOTAP_TIMESTAMP_SPOS_UNKNOWN = 0x00F0,
+};
 
-#define IEEE80211_RADIOTAP_TIMESTAMP_FLAG_64BIT			0x00
-#define IEEE80211_RADIOTAP_TIMESTAMP_FLAG_32BIT			0x01
-#define IEEE80211_RADIOTAP_TIMESTAMP_FLAG_ACCURACY		0x02
+enum ieee80211_radiotap_timestamp_flags {
+	IEEE80211_RADIOTAP_TIMESTAMP_FLAG_64BIT = 0x00,
+	IEEE80211_RADIOTAP_TIMESTAMP_FLAG_32BIT = 0x01,
+	IEEE80211_RADIOTAP_TIMESTAMP_FLAG_ACCURACY = 0x02,
+};
 
-/* helpers */
-static inline int ieee80211_get_radiotap_len(unsigned char *data)
+/**
+ * ieee80211_get_radiotap_len - get radiotap header length
+ */
+static inline u16 ieee80211_get_radiotap_len(const char *data)
 {
-	struct ieee80211_radiotap_header *hdr =
-		(struct ieee80211_radiotap_header *)data;
+	struct ieee80211_radiotap_header *hdr = (void *)data;
 
 	return get_unaligned_le16(&hdr->it_len);
 }
 
-#endif				/* IEEE80211_RADIOTAP_H */
+#endif /* __RADIOTAP_H */
-- 
2.9.3

^ permalink raw reply related

* [PATCH v2] wireless: radiotap: rewrite the radiotap header file
From: Johannes Berg @ 2017-01-25 14:36 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

The header file has grown a lot of #define's etc, but
they are nicer as enums, so rewrite the file from the
documentation as such.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 include/net/ieee80211_radiotap.h | 455 ++++++++++++++-------------------------
 1 file changed, 157 insertions(+), 298 deletions(-)

diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h
index d0e7e3f8e67a..d91f9e7f4d71 100644
--- a/include/net/ieee80211_radiotap.h
+++ b/include/net/ieee80211_radiotap.h
@@ -1,201 +1,54 @@
 /*
- * Copyright (c) 2003, 2004 David Young.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of David Young may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DAVID
- * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- */
-
-/*
- * Modifications to fit into the linux IEEE 802.11 stack,
- * Mike Kershaw (dragorn@kismetwireless.net)
+ * Copyright (c) 2017		Intel Deutschland GmbH
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
+#ifndef __RADIOTAP_H
+#define __RADIOTAP_H
 
-#ifndef IEEE80211RADIOTAP_H
-#define IEEE80211RADIOTAP_H
-
-#include <linux/if_ether.h>
 #include <linux/kernel.h>
 #include <asm/unaligned.h>
 
-/* Base version of the radiotap packet header data */
-#define PKTHDR_RADIOTAP_VERSION		0
-
-/* A generic radio capture format is desirable. There is one for
- * Linux, but it is neither rigidly defined (there were not even
- * units given for some fields) nor easily extensible.
- *
- * I suggest the following extensible radio capture format. It is
- * based on a bitmap indicating which fields are present.
- *
- * I am trying to describe precisely what the application programmer
- * should expect in the following, and for that reason I tell the
- * units and origin of each measurement (where it applies), or else I
- * use sufficiently weaselly language ("is a monotonically nondecreasing
- * function of...") that I cannot set false expectations for lawyerly
- * readers.
- */
-
-/*
- * The radio capture header precedes the 802.11 header.
- * All data in the header is little endian on all platforms.
+/**
+ * struct ieee82011_radiotap_header - base radiotap header
  */
 struct ieee80211_radiotap_header {
-	u8 it_version;		/* Version 0. Only increases
-				 * for drastic changes,
-				 * introduction of compatible
-				 * new fields does not count.
-				 */
-	u8 it_pad;
-	__le16 it_len;		/* length of the whole
-				 * header in bytes, including
-				 * it_version, it_pad,
-				 * it_len, and data fields.
-				 */
-	__le32 it_present;	/* A bitmap telling which
-				 * fields are present. Set bit 31
-				 * (0x80000000) to extend the
-				 * bitmap by another 32 bits.
-				 * Additional extensions are made
-				 * by setting bit 31.
-				 */
+	/**
+	 * @it_version: radiotap version, always 0
+	 */
+	uint8_t it_version;
+
+	/**
+	 * @it_pad: padding (or alignment)
+	 */
+	uint8_t it_pad;
+
+	/**
+	 * @it_len: overall radiotap header length
+	 */
+	__le16 it_len;
+
+	/**
+	 * @it_present: (first) present word
+	 */
+	__le32 it_present;
 } __packed;
 
-/* Name                                 Data type    Units
- * ----                                 ---------    -----
- *
- * IEEE80211_RADIOTAP_TSFT              __le64       microseconds
- *
- *      Value in microseconds of the MAC's 64-bit 802.11 Time
- *      Synchronization Function timer when the first bit of the
- *      MPDU arrived at the MAC. For received frames, only.
- *
- * IEEE80211_RADIOTAP_CHANNEL           2 x __le16   MHz, bitmap
- *
- *      Tx/Rx frequency in MHz, followed by flags (see below).
- *
- * IEEE80211_RADIOTAP_FHSS              __le16       see below
- *
- *      For frequency-hopping radios, the hop set (first byte)
- *      and pattern (second byte).
- *
- * IEEE80211_RADIOTAP_RATE              u8           500kb/s
- *
- *      Tx/Rx data rate
- *
- * IEEE80211_RADIOTAP_DBM_ANTSIGNAL     s8           decibels from
- *                                                   one milliwatt (dBm)
- *
- *      RF signal power at the antenna, decibel difference from
- *      one milliwatt.
- *
- * IEEE80211_RADIOTAP_DBM_ANTNOISE      s8           decibels from
- *                                                   one milliwatt (dBm)
- *
- *      RF noise power at the antenna, decibel difference from one
- *      milliwatt.
- *
- * IEEE80211_RADIOTAP_DB_ANTSIGNAL      u8           decibel (dB)
- *
- *      RF signal power at the antenna, decibel difference from an
- *      arbitrary, fixed reference.
- *
- * IEEE80211_RADIOTAP_DB_ANTNOISE       u8           decibel (dB)
- *
- *      RF noise power at the antenna, decibel difference from an
- *      arbitrary, fixed reference point.
- *
- * IEEE80211_RADIOTAP_LOCK_QUALITY      __le16       unitless
- *
- *      Quality of Barker code lock. Unitless. Monotonically
- *      nondecreasing with "better" lock strength. Called "Signal
- *      Quality" in datasheets.  (Is there a standard way to measure
- *      this?)
- *
- * IEEE80211_RADIOTAP_TX_ATTENUATION    __le16       unitless
- *
- *      Transmit power expressed as unitless distance from max
- *      power set at factory calibration.  0 is max power.
- *      Monotonically nondecreasing with lower power levels.
- *
- * IEEE80211_RADIOTAP_DB_TX_ATTENUATION __le16       decibels (dB)
- *
- *      Transmit power expressed as decibel distance from max power
- *      set at factory calibration.  0 is max power.  Monotonically
- *      nondecreasing with lower power levels.
- *
- * IEEE80211_RADIOTAP_DBM_TX_POWER      s8           decibels from
- *                                                   one milliwatt (dBm)
- *
- *      Transmit power expressed as dBm (decibels from a 1 milliwatt
- *      reference). This is the absolute power level measured at
- *      the antenna port.
- *
- * IEEE80211_RADIOTAP_FLAGS             u8           bitmap
- *
- *      Properties of transmitted and received frames. See flags
- *      defined below.
- *
- * IEEE80211_RADIOTAP_ANTENNA           u8           antenna index
- *
- *      Unitless indication of the Rx/Tx antenna for this packet.
- *      The first antenna is antenna 0.
- *
- * IEEE80211_RADIOTAP_RX_FLAGS          __le16       bitmap
- *
- *     Properties of received frames. See flags defined below.
- *
- * IEEE80211_RADIOTAP_TX_FLAGS          __le16       bitmap
- *
- *     Properties of transmitted frames. See flags defined below.
- *
- * IEEE80211_RADIOTAP_RTS_RETRIES       u8           data
- *
- *     Number of rts retries a transmitted frame used.
- *
- * IEEE80211_RADIOTAP_DATA_RETRIES      u8           data
- *
- *     Number of unicast retries a transmitted frame used.
- *
- * IEEE80211_RADIOTAP_MCS	u8, u8, u8		unitless
- *
- *     Contains a bitmap of known fields/flags, the flags, and
- *     the MCS index.
- *
- * IEEE80211_RADIOTAP_AMPDU_STATUS	u32, u16, u8, u8	unitless
- *
- *	Contains the AMPDU information for the subframe.
- *
- * IEEE80211_RADIOTAP_VHT	u16, u8, u8, u8[4], u8, u8, u16
- *
- *	Contains VHT information about this frame.
- *
- * IEEE80211_RADIOTAP_TIMESTAMP		u64, u16, u8, u8	variable
- *
- *	Contains timestamp information for this frame.
- */
-enum ieee80211_radiotap_type {
+/* version is always 0 */
+#define PKTHDR_RADIOTAP_VERSION	0
+
+/* see the radiotap website for the descriptions */
+enum ieee80211_radiotap_presence {
 	IEEE80211_RADIOTAP_TSFT = 0,
 	IEEE80211_RADIOTAP_FLAGS = 1,
 	IEEE80211_RADIOTAP_RATE = 2,
@@ -214,7 +67,7 @@ enum ieee80211_radiotap_type {
 	IEEE80211_RADIOTAP_TX_FLAGS = 15,
 	IEEE80211_RADIOTAP_RTS_RETRIES = 16,
 	IEEE80211_RADIOTAP_DATA_RETRIES = 17,
-
+	/* 18 is XChannel, but it's not defined yet */
 	IEEE80211_RADIOTAP_MCS = 19,
 	IEEE80211_RADIOTAP_AMPDU_STATUS = 20,
 	IEEE80211_RADIOTAP_VHT = 21,
@@ -226,129 +79,135 @@ enum ieee80211_radiotap_type {
 	IEEE80211_RADIOTAP_EXT = 31
 };
 
-/* Channel flags. */
-#define	IEEE80211_CHAN_TURBO	0x0010	/* Turbo channel */
-#define	IEEE80211_CHAN_CCK	0x0020	/* CCK channel */
-#define	IEEE80211_CHAN_OFDM	0x0040	/* OFDM channel */
-#define	IEEE80211_CHAN_2GHZ	0x0080	/* 2 GHz spectrum channel. */
-#define	IEEE80211_CHAN_5GHZ	0x0100	/* 5 GHz spectrum channel */
-#define	IEEE80211_CHAN_PASSIVE	0x0200	/* Only passive scan allowed */
-#define	IEEE80211_CHAN_DYN	0x0400	/* Dynamic CCK-OFDM channel */
-#define	IEEE80211_CHAN_GFSK	0x0800	/* GFSK channel (FHSS PHY) */
-#define	IEEE80211_CHAN_GSM	0x1000	/* GSM (900 MHz) */
-#define	IEEE80211_CHAN_STURBO	0x2000	/* Static Turbo */
-#define	IEEE80211_CHAN_HALF	0x4000	/* Half channel (10 MHz wide) */
-#define	IEEE80211_CHAN_QUARTER	0x8000	/* Quarter channel (5 MHz wide) */
-
-/* For IEEE80211_RADIOTAP_FLAGS */
-#define	IEEE80211_RADIOTAP_F_CFP	0x01	/* sent/received
-						 * during CFP
-						 */
-#define	IEEE80211_RADIOTAP_F_SHORTPRE	0x02	/* sent/received
-						 * with short
-						 * preamble
-						 */
-#define	IEEE80211_RADIOTAP_F_WEP	0x04	/* sent/received
-						 * with WEP encryption
-						 */
-#define	IEEE80211_RADIOTAP_F_FRAG	0x08	/* sent/received
-						 * with fragmentation
-						 */
-#define	IEEE80211_RADIOTAP_F_FCS	0x10	/* frame includes FCS */
-#define	IEEE80211_RADIOTAP_F_DATAPAD	0x20	/* frame has padding between
-						 * 802.11 header and payload
-						 * (to 32-bit boundary)
-						 */
-#define IEEE80211_RADIOTAP_F_BADFCS	0x40	/* bad FCS */
-
-/* For IEEE80211_RADIOTAP_RX_FLAGS */
-#define IEEE80211_RADIOTAP_F_RX_BADPLCP	0x0002	/* frame has bad PLCP */
+/* for IEEE80211_RADIOTAP_FLAGS */
+enum ieee80211_radiotap_flags {
+	IEEE80211_RADIOTAP_F_CFP = 0x01,
+	IEEE80211_RADIOTAP_F_SHORTPRE = 0x02,
+	IEEE80211_RADIOTAP_F_WEP = 0x04,
+	IEEE80211_RADIOTAP_F_FRAG = 0x08,
+	IEEE80211_RADIOTAP_F_FCS = 0x10,
+	IEEE80211_RADIOTAP_F_DATAPAD = 0x20,
+	IEEE80211_RADIOTAP_F_BADFCS = 0x40,
+};
 
-/* For IEEE80211_RADIOTAP_TX_FLAGS */
-#define IEEE80211_RADIOTAP_F_TX_FAIL	0x0001	/* failed due to excessive
-						 * retries */
-#define IEEE80211_RADIOTAP_F_TX_CTS	0x0002	/* used cts 'protection' */
-#define IEEE80211_RADIOTAP_F_TX_RTS	0x0004	/* used rts/cts handshake */
-#define IEEE80211_RADIOTAP_F_TX_NOACK	0x0008	/* don't expect an ack */
+/* for IEEE80211_RADIOTAP_CHANNEL */
+enum ieee80211_radiotap_channel_flags {
+	IEEE80211_CHAN_CCK = 0x0020,
+	IEEE80211_CHAN_OFDM = 0x0040,
+	IEEE80211_CHAN_2GHZ = 0x0080,
+	IEEE80211_CHAN_5GHZ = 0x0100,
+	IEEE80211_CHAN_DYN = 0x0400,
+	IEEE80211_CHAN_HALF = 0x4000,
+	IEEE80211_CHAN_QUARTER = 0x8000,
+};
 
+/* for IEEE80211_RADIOTAP_RX_FLAGS */
+enum ieee80211_radiotap_rx_flags {
+	IEEE80211_RADIOTAP_F_RX_BADPLCP = 0x0002,
+};
 
-/* For IEEE80211_RADIOTAP_MCS */
-#define IEEE80211_RADIOTAP_MCS_HAVE_BW		0x01
-#define IEEE80211_RADIOTAP_MCS_HAVE_MCS		0x02
-#define IEEE80211_RADIOTAP_MCS_HAVE_GI		0x04
-#define IEEE80211_RADIOTAP_MCS_HAVE_FMT		0x08
-#define IEEE80211_RADIOTAP_MCS_HAVE_FEC		0x10
-#define IEEE80211_RADIOTAP_MCS_HAVE_STBC	0x20
+/* for IEEE80211_RADIOTAP_TX_FLAGS */
+enum ieee80211_radiotap_tx_flags {
+	IEEE80211_RADIOTAP_F_TX_FAIL = 0x0001,
+	IEEE80211_RADIOTAP_F_TX_CTS = 0x0002,
+	IEEE80211_RADIOTAP_F_TX_RTS = 0x0004,
+	IEEE80211_RADIOTAP_F_TX_NOACK = 0x0008,
+};
 
-#define IEEE80211_RADIOTAP_MCS_BW_MASK		0x03
-#define		IEEE80211_RADIOTAP_MCS_BW_20	0
-#define		IEEE80211_RADIOTAP_MCS_BW_40	1
-#define		IEEE80211_RADIOTAP_MCS_BW_20L	2
-#define		IEEE80211_RADIOTAP_MCS_BW_20U	3
-#define IEEE80211_RADIOTAP_MCS_SGI		0x04
-#define IEEE80211_RADIOTAP_MCS_FMT_GF		0x08
-#define IEEE80211_RADIOTAP_MCS_FEC_LDPC		0x10
-#define IEEE80211_RADIOTAP_MCS_STBC_MASK	0x60
-#define		IEEE80211_RADIOTAP_MCS_STBC_1	1
-#define		IEEE80211_RADIOTAP_MCS_STBC_2	2
-#define		IEEE80211_RADIOTAP_MCS_STBC_3	3
+/* for IEEE80211_RADIOTAP_MCS "have" flags */
+enum ieee80211_radiotap_mcs_have {
+	IEEE80211_RADIOTAP_MCS_HAVE_BW = 0x01,
+	IEEE80211_RADIOTAP_MCS_HAVE_MCS = 0x02,
+	IEEE80211_RADIOTAP_MCS_HAVE_GI = 0x04,
+	IEEE80211_RADIOTAP_MCS_HAVE_FMT = 0x08,
+	IEEE80211_RADIOTAP_MCS_HAVE_FEC = 0x10,
+	IEEE80211_RADIOTAP_MCS_HAVE_STBC = 0x20,
+};
 
-#define IEEE80211_RADIOTAP_MCS_STBC_SHIFT	5
+enum ieee80211_radiotap_mcs_flags {
+	IEEE80211_RADIOTAP_MCS_BW_MASK = 0x03,
+	IEEE80211_RADIOTAP_MCS_BW_20 = 0,
+	IEEE80211_RADIOTAP_MCS_BW_40 = 1,
+	IEEE80211_RADIOTAP_MCS_BW_20L = 2,
+	IEEE80211_RADIOTAP_MCS_BW_20U = 3,
+
+	IEEE80211_RADIOTAP_MCS_SGI = 0x04,
+	IEEE80211_RADIOTAP_MCS_FMT_GF = 0x08,
+	IEEE80211_RADIOTAP_MCS_FEC_LDPC = 0x10,
+	IEEE80211_RADIOTAP_MCS_STBC_MASK = 0x60,
+	IEEE80211_RADIOTAP_MCS_STBC_1 = 1,
+	IEEE80211_RADIOTAP_MCS_STBC_2 = 2,
+	IEEE80211_RADIOTAP_MCS_STBC_3 = 3,
+	IEEE80211_RADIOTAP_MCS_STBC_SHIFT = 5,
+};
 
-/* For IEEE80211_RADIOTAP_AMPDU_STATUS */
-#define IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN		0x0001
-#define IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN		0x0002
-#define IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN		0x0004
-#define IEEE80211_RADIOTAP_AMPDU_IS_LAST		0x0008
-#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR		0x0010
-#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN	0x0020
+/* for IEEE80211_RADIOTAP_AMPDU_STATUS */
+enum ieee80211_radiotap_ampdu_flags {
+	IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN = 0x0001,
+	IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN = 0x0002,
+	IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN = 0x0004,
+	IEEE80211_RADIOTAP_AMPDU_IS_LAST = 0x0008,
+	IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR = 0x0010,
+	IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN = 0x0020,
+};
 
-/* For IEEE80211_RADIOTAP_VHT */
-#define IEEE80211_RADIOTAP_VHT_KNOWN_STBC			0x0001
-#define IEEE80211_RADIOTAP_VHT_KNOWN_TXOP_PS_NA			0x0002
-#define IEEE80211_RADIOTAP_VHT_KNOWN_GI				0x0004
-#define IEEE80211_RADIOTAP_VHT_KNOWN_SGI_NSYM_DIS		0x0008
-#define IEEE80211_RADIOTAP_VHT_KNOWN_LDPC_EXTRA_OFDM_SYM	0x0010
-#define IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED			0x0020
-#define IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH			0x0040
-#define IEEE80211_RADIOTAP_VHT_KNOWN_GROUP_ID			0x0080
-#define IEEE80211_RADIOTAP_VHT_KNOWN_PARTIAL_AID		0x0100
+/* for IEEE80211_RADIOTAP_VHT */
+enum ieee80211_radiotap_vht_known {
+	IEEE80211_RADIOTAP_VHT_KNOWN_STBC = 0x0001,
+	IEEE80211_RADIOTAP_VHT_KNOWN_TXOP_PS_NA = 0x0002,
+	IEEE80211_RADIOTAP_VHT_KNOWN_GI = 0x0004,
+	IEEE80211_RADIOTAP_VHT_KNOWN_SGI_NSYM_DIS = 0x0008,
+	IEEE80211_RADIOTAP_VHT_KNOWN_LDPC_EXTRA_OFDM_SYM = 0x0010,
+	IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED = 0x0020,
+	IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH = 0x0040,
+	IEEE80211_RADIOTAP_VHT_KNOWN_GROUP_ID = 0x0080,
+	IEEE80211_RADIOTAP_VHT_KNOWN_PARTIAL_AID = 0x0100,
+};
 
-#define IEEE80211_RADIOTAP_VHT_FLAG_STBC			0x01
-#define IEEE80211_RADIOTAP_VHT_FLAG_TXOP_PS_NA			0x02
-#define IEEE80211_RADIOTAP_VHT_FLAG_SGI				0x04
-#define IEEE80211_RADIOTAP_VHT_FLAG_SGI_NSYM_M10_9		0x08
-#define IEEE80211_RADIOTAP_VHT_FLAG_LDPC_EXTRA_OFDM_SYM		0x10
-#define IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED			0x20
+enum ieee80211_radiotap_vht_flags {
+	IEEE80211_RADIOTAP_VHT_FLAG_STBC = 0x01,
+	IEEE80211_RADIOTAP_VHT_FLAG_TXOP_PS_NA = 0x02,
+	IEEE80211_RADIOTAP_VHT_FLAG_SGI = 0x04,
+	IEEE80211_RADIOTAP_VHT_FLAG_SGI_NSYM_M10_9 = 0x08,
+	IEEE80211_RADIOTAP_VHT_FLAG_LDPC_EXTRA_OFDM_SYM = 0x10,
+	IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED = 0x20,
+};
 
-#define IEEE80211_RADIOTAP_CODING_LDPC_USER0			0x01
-#define IEEE80211_RADIOTAP_CODING_LDPC_USER1			0x02
-#define IEEE80211_RADIOTAP_CODING_LDPC_USER2			0x04
-#define IEEE80211_RADIOTAP_CODING_LDPC_USER3			0x08
+enum ieee80211_radiotap_vht_coding {
+	IEEE80211_RADIOTAP_CODING_LDPC_USER0 = 0x01,
+	IEEE80211_RADIOTAP_CODING_LDPC_USER1 = 0x02,
+	IEEE80211_RADIOTAP_CODING_LDPC_USER2 = 0x04,
+	IEEE80211_RADIOTAP_CODING_LDPC_USER3 = 0x08,
+};
 
-/* For IEEE80211_RADIOTAP_TIMESTAMP */
-#define IEEE80211_RADIOTAP_TIMESTAMP_UNIT_MASK			0x000F
-#define IEEE80211_RADIOTAP_TIMESTAMP_UNIT_MS			0x0000
-#define IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US			0x0001
-#define IEEE80211_RADIOTAP_TIMESTAMP_UNIT_NS			0x0003
-#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_MASK			0x00F0
-#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_BEGIN_MDPU		0x0000
-#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_PLCP_SIG_ACQ		0x0010
-#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_PPDU		0x0020
-#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_MPDU		0x0030
-#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_UNKNOWN		0x00F0
+/* for IEEE80211_RADIOTAP_TIMESTAMP */
+enum ieee80211_radiotap_timestamp_unit_spos {
+	IEEE80211_RADIOTAP_TIMESTAMP_UNIT_MASK = 0x000F,
+	IEEE80211_RADIOTAP_TIMESTAMP_UNIT_MS = 0x0000,
+	IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US = 0x0001,
+	IEEE80211_RADIOTAP_TIMESTAMP_UNIT_NS = 0x0003,
+	IEEE80211_RADIOTAP_TIMESTAMP_SPOS_MASK = 0x00F0,
+	IEEE80211_RADIOTAP_TIMESTAMP_SPOS_BEGIN_MDPU = 0x0000,
+	IEEE80211_RADIOTAP_TIMESTAMP_SPOS_PLCP_SIG_ACQ = 0x0010,
+	IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_PPDU = 0x0020,
+	IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_MPDU = 0x0030,
+	IEEE80211_RADIOTAP_TIMESTAMP_SPOS_UNKNOWN = 0x00F0,
+};
 
-#define IEEE80211_RADIOTAP_TIMESTAMP_FLAG_64BIT			0x00
-#define IEEE80211_RADIOTAP_TIMESTAMP_FLAG_32BIT			0x01
-#define IEEE80211_RADIOTAP_TIMESTAMP_FLAG_ACCURACY		0x02
+enum ieee80211_radiotap_timestamp_flags {
+	IEEE80211_RADIOTAP_TIMESTAMP_FLAG_64BIT = 0x00,
+	IEEE80211_RADIOTAP_TIMESTAMP_FLAG_32BIT = 0x01,
+	IEEE80211_RADIOTAP_TIMESTAMP_FLAG_ACCURACY = 0x02,
+};
 
-/* helpers */
-static inline int ieee80211_get_radiotap_len(unsigned char *data)
+/**
+ * ieee80211_get_radiotap_len - get radiotap header length
+ */
+static inline u16 ieee80211_get_radiotap_len(const char *data)
 {
-	struct ieee80211_radiotap_header *hdr =
-		(struct ieee80211_radiotap_header *)data;
+	struct ieee80211_radiotap_header *hdr = (void *)data;
 
 	return get_unaligned_le16(&hdr->it_len);
 }
 
-#endif				/* IEEE80211_RADIOTAP_H */
+#endif /* __RADIOTAP_H */
-- 
2.9.3

^ permalink raw reply related

* Re: [PATCH v3] ath10k: Fix crash during rmmod when probe firmware fails
From: Valo, Kalle @ 2017-01-25 13:46 UTC (permalink / raw)
  To: Shajakhan, Mohammed Shafi (Mohammed Shafi)
  Cc: ath10k@lists.infradead.org, mohammed@codeaurora.org,
	linux-wireless@vger.kernel.org
In-Reply-To: <8760l38dz0.fsf@kamboji.qca.qualcomm.com>

Kalle Valo <kvalo@qca.qualcomm.com> writes:

> Mohammed Shafi Shajakhan <mohammed@qti.qualcomm.com> writes:
>
>> From: Mohammed Shafi Shajakhan <mohammed@qti.qualcomm.com>
>>
>> This fixes the below crash when ath10k probe firmware fails,
>> NAPI polling tries to access a rx ring resource which was never
>> allocated, fix this by disabling NAPI right away once the probe
>> firmware fails by calling 'ath10k_hif_stop'. Its good to note
>> that the error is never propogated to 'ath10k_pci_probe' when
>> ath10k_core_register fails, so calling 'ath10k_hif_stop' to cleanup
>> PCI related things seems to be ok
>>
>> BUG: unable to handle kernel NULL pointer dereference at (null)
>> IP:  __ath10k_htt_rx_ring_fill_n+0x19/0x230 [ath10k_core]
>> __ath10k_htt_rx_ring_fill_n+0x19/0x230 [ath10k_core]
>>
>> Call Trace:
>>
>> [<ffffffffa113ec62>] ath10k_htt_rx_msdu_buff_replenish+0x42/0x90
>> [ath10k_core]
>> [<ffffffffa113f393>] ath10k_htt_txrx_compl_task+0x433/0x17d0
>> [ath10k_core]
>> [<ffffffff8114406d>] ? __wake_up_common+0x4d/0x80
>> [<ffffffff811349ec>] ? cpu_load_update+0xdc/0x150
>> [<ffffffffa119301d>] ? ath10k_pci_read32+0xd/0x10 [ath10k_pci]
>> [<ffffffffa1195b17>] ath10k_pci_napi_poll+0x47/0x110 [ath10k_pci]
>> [<ffffffff817863af>] net_rx_action+0x20f/0x370
>>
>> Reported-by: Ben Greear <greearb@candelatech.com>
>> Fixes: 3c97f5de1f28 ("ath10k: implement NAPI support")
>> Signed-off-by: Mohammed Shafi Shajakhan <mohammed@qti.qualcomm.com>
>
> Is there an easy way to reproduce this bug? I don't see it on my x86
> laptop with qca988x and I call rmmod all the time. I would like to test
> this myself.
>
>> --- a/drivers/net/wireless/ath/ath10k/core.c
>> +++ b/drivers/net/wireless/ath/ath10k/core.c
>> @@ -2164,6 +2164,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
>>  	ath10k_core_free_firmware_files(ar);
>> =20
>>  err_power_down:
>> +	ath10k_hif_stop(ar);
>>  	ath10k_hif_power_down(ar);
>> =20
>>  	return ret;
>
> This breaks the symmetry, we should not be calling ath10k_hif_stop() if
> we haven't called ath10k_hif_start() from the same function. This can
> just create a bigger mess later, for example with other bus support like
> sdio or usb. In theory it should enough that we call
> ath10k_hif_power_down() and pci.c does the rest correctly "behind the
> scenes".
>
> I investigated this a bit and I think the real cause is that we call
> napi_enable() from ath10k_pci_hif_power_up() and napi_disable() from
> ath10k_pci_hif_stop(). Does anyone remember why?
>
> I was expecting that we would call napi_enable()/napi_disable() either
> in ath10k_hif_power_up/down() or ath10k_hif_start()/stop(), but not
> mixed like it's currently.

So below is something I was thinking of, now napi_enable() is called
from ath10k_hif_start() and napi_disable() from ath10k_hif_stop(). Would
that work?

--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1648,6 +1648,8 @@ static int ath10k_pci_hif_start(struct ath10k *ar)
=20
 	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n");
=20
+	napi_enable(&ar->napi);
+
 	ath10k_pci_irq_enable(ar);
 	ath10k_pci_rx_post(ar);
=20
@@ -2532,7 +2534,6 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 		ath10k_err(ar, "could not wake up target CPU: %d\n", ret);
 		goto err_ce;
 	}
-	napi_enable(&ar->napi);
=20
 	return 0;

--=20
Kalle Valo=

^ permalink raw reply

* Re: [PATCH v3] ath10k: Fix crash during rmmod when probe firmware fails
From: Valo, Kalle @ 2017-01-25 13:29 UTC (permalink / raw)
  To: Shajakhan, Mohammed Shafi (Mohammed Shafi)
  Cc: ath10k@lists.infradead.org, mohammed@codeaurora.org,
	linux-wireless@vger.kernel.org
In-Reply-To: <1482221351-24029-1-git-send-email-mohammed@qca.qualcomm.com>

Mohammed Shafi Shajakhan <mohammed@qti.qualcomm.com> writes:

> From: Mohammed Shafi Shajakhan <mohammed@qti.qualcomm.com>
>
> This fixes the below crash when ath10k probe firmware fails,
> NAPI polling tries to access a rx ring resource which was never
> allocated, fix this by disabling NAPI right away once the probe
> firmware fails by calling 'ath10k_hif_stop'. Its good to note
> that the error is never propogated to 'ath10k_pci_probe' when
> ath10k_core_register fails, so calling 'ath10k_hif_stop' to cleanup
> PCI related things seems to be ok
>
> BUG: unable to handle kernel NULL pointer dereference at (null)
> IP:  __ath10k_htt_rx_ring_fill_n+0x19/0x230 [ath10k_core]
> __ath10k_htt_rx_ring_fill_n+0x19/0x230 [ath10k_core]
>
> Call Trace:
>
> [<ffffffffa113ec62>] ath10k_htt_rx_msdu_buff_replenish+0x42/0x90
> [ath10k_core]
> [<ffffffffa113f393>] ath10k_htt_txrx_compl_task+0x433/0x17d0
> [ath10k_core]
> [<ffffffff8114406d>] ? __wake_up_common+0x4d/0x80
> [<ffffffff811349ec>] ? cpu_load_update+0xdc/0x150
> [<ffffffffa119301d>] ? ath10k_pci_read32+0xd/0x10 [ath10k_pci]
> [<ffffffffa1195b17>] ath10k_pci_napi_poll+0x47/0x110 [ath10k_pci]
> [<ffffffff817863af>] net_rx_action+0x20f/0x370
>
> Reported-by: Ben Greear <greearb@candelatech.com>
> Fixes: 3c97f5de1f28 ("ath10k: implement NAPI support")
> Signed-off-by: Mohammed Shafi Shajakhan <mohammed@qti.qualcomm.com>

Is there an easy way to reproduce this bug? I don't see it on my x86
laptop with qca988x and I call rmmod all the time. I would like to test
this myself.

> --- a/drivers/net/wireless/ath/ath10k/core.c
> +++ b/drivers/net/wireless/ath/ath10k/core.c
> @@ -2164,6 +2164,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
>  	ath10k_core_free_firmware_files(ar);
> =20
>  err_power_down:
> +	ath10k_hif_stop(ar);
>  	ath10k_hif_power_down(ar);
> =20
>  	return ret;

This breaks the symmetry, we should not be calling ath10k_hif_stop() if
we haven't called ath10k_hif_start() from the same function. This can
just create a bigger mess later, for example with other bus support like
sdio or usb. In theory it should enough that we call
ath10k_hif_power_down() and pci.c does the rest correctly "behind the
scenes".

I investigated this a bit and I think the real cause is that we call
napi_enable() from ath10k_pci_hif_power_up() and napi_disable() from
ath10k_pci_hif_stop(). Does anyone remember why?

I was expecting that we would call napi_enable()/napi_disable() either
in ath10k_hif_power_up/down() or ath10k_hif_start()/stop(), but not
mixed like it's currently.

--=20
Kalle Valo=

^ permalink raw reply

* [PATCH v4 4/5] mac80211: Add set_cqm_rssi_range_config
From: Andrew Zaborowski @ 2017-01-25 11:43 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <20170125114344.8179-1-andrew.zaborowski@intel.com>

Support .set_cqm_rssi_range_config if the beacons are available for
processing in mac80211.  There's no reason that this couldn't be
offloaded by mac80211-based drivers but there's no driver method for
that added in this patch as I don't have the hardware.

Signed-off-by: Andrew Zaborowski <andrew.zaborowski@intel.com>
---
changes in v3:
 - set NL80211_EXT_FEATURE_CQM_RSSI_LIST automatically in
   ieee80211_register_hw based on the default interface's
   IEEE80211_VIF_BEACON_FILTER flag.
changes in v4:
 - drop the above attempt and set NL80211_EXT_FEATURE_CQM_RSSI_LIST
   in a separate patch in each driver.
---
 include/net/mac80211.h |  6 ++++++
 net/mac80211/cfg.c     | 28 ++++++++++++++++++++++++++++
 net/mac80211/mlme.c    | 24 ++++++++++++++++++++++++
 3 files changed, 58 insertions(+)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 8810ae7..d3992c4 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -502,6 +502,10 @@ struct ieee80211_mu_group_data {
  *	implies disabled. As with the cfg80211 callback, a change here should
  *	cause an event to be sent indicating where the current value is in
  *	relation to the newly configured threshold.
+ * @cqm_rssi_low: Connection quality monitor RSSI lower threshold, a zero value
+ *	implies disabled.  This is an alternative mechanism to the single
+ *	threshold event and can't be enabled simultaneously with it.
+ * @cqm_rssi_high: Connection quality monitor RSSI upper threshold.
  * @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis
  * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The
  *	may filter ARP queries targeted for other addresses than listed here.
@@ -554,6 +558,8 @@ struct ieee80211_bss_conf {
 	u16 ht_operation_mode;
 	s32 cqm_rssi_thold;
 	u32 cqm_rssi_hyst;
+	s32 cqm_rssi_low;
+	s32 cqm_rssi_high;
 	struct cfg80211_chan_def chandef;
 	struct ieee80211_mu_group_data mu_group;
 	__be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index e91e503..cf02aaa 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2630,6 +2630,33 @@ static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy,
 
 	bss_conf->cqm_rssi_thold = rssi_thold;
 	bss_conf->cqm_rssi_hyst = rssi_hyst;
+	bss_conf->cqm_rssi_low = 0;
+	bss_conf->cqm_rssi_high = 0;
+	sdata->u.mgd.last_cqm_event_signal = 0;
+
+	/* tell the driver upon association, unless already associated */
+	if (sdata->u.mgd.associated &&
+	    sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)
+		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM);
+
+	return 0;
+}
+
+static int ieee80211_set_cqm_rssi_range_config(struct wiphy *wiphy,
+					       struct net_device *dev,
+					       s32 rssi_low, s32 rssi_high)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_vif *vif = &sdata->vif;
+	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+
+	if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER)
+		return -EOPNOTSUPP;
+
+	bss_conf->cqm_rssi_low = rssi_low;
+	bss_conf->cqm_rssi_high = rssi_high;
+	bss_conf->cqm_rssi_thold = 0;
+	bss_conf->cqm_rssi_hyst = 0;
 	sdata->u.mgd.last_cqm_event_signal = 0;
 
 	/* tell the driver upon association, unless already associated */
@@ -3628,6 +3655,7 @@ const struct cfg80211_ops mac80211_config_ops = {
 	.mgmt_tx = ieee80211_mgmt_tx,
 	.mgmt_tx_cancel_wait = ieee80211_mgmt_tx_cancel_wait,
 	.set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,
+	.set_cqm_rssi_range_config = ieee80211_set_cqm_rssi_range_config,
 	.mgmt_frame_register = ieee80211_mgmt_frame_register,
 	.set_antenna = ieee80211_set_antenna,
 	.get_antenna = ieee80211_get_antenna,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 0cfa215..260e20d 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3434,6 +3434,30 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 		}
 	}
 
+	if (bss_conf->cqm_rssi_low &&
+	    ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) {
+		int sig = -ewma_beacon_signal_read(&ifmgd->ave_beacon_signal);
+		int last_event = ifmgd->last_cqm_event_signal;
+		int low = bss_conf->cqm_rssi_low;
+		int high = bss_conf->cqm_rssi_high;
+
+		if (sig < low &&
+		    (last_event == 0 || last_event >= low)) {
+			ifmgd->last_cqm_event_signal = sig;
+			ieee80211_cqm_rssi_notify(
+				&sdata->vif,
+				NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
+				sig, GFP_KERNEL);
+		} else if (sig > high &&
+			   (last_event == 0 || last_event <= high)) {
+			ifmgd->last_cqm_event_signal = sig;
+			ieee80211_cqm_rssi_notify(
+				&sdata->vif,
+				NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+				sig, GFP_KERNEL);
+		}
+	}
+
 	if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) {
 		mlme_dbg_ratelimited(sdata,
 				     "cancelling AP probe due to a received beacon\n");
-- 
2.9.3

^ permalink raw reply related

* [PATCH v4 3/5] cfg80211: Accept multiple RSSI thresholds for CQM
From: Andrew Zaborowski @ 2017-01-25 11:43 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <20170125114344.8179-1-andrew.zaborowski@intel.com>

Change the SET CQM command's RSSI threshold attribute to accept any
number of thresholds as a sorted array.  The API should be backwards
compatible so that if one s32 threshold value is passed, the old
mechanism is enabled.  The netlink event generated is the same in both
cases.

cfg80211 handles an arbitrary number of RSSI thresholds but drivers have
to provide a method (set_cqm_rssi_range_config) that configures a range
set by a high and a low value.  Drivers have to call back when the RSSI
goes out of that range and there's no additional event every time the
range is reconfigured as there was with the current API.

This method doesn't have a hysteresis parameter because there's no
benefit to the cfg80211 code from having the hysteresis be handled by
hardware/driver in terms of the number of wakeups.  At the same time
it would likely be less consistent between drivers if offloaded or
done in the drivers.

Signed-off-by: Andrew Zaborowski <andrew.zaborowski@intel.com>
---
changes in v3:
 - define NL80211_EXT_FEATURE_CQM_RSSI_LIST which drivers need to set
   if they implement set_cqm_rssi_range_config (mac80211 is a special
   case)
 - error check the kzalloc in nl80211_set_cqm_rssi
 - add a rdev->ops->get_station check before calling get_station
changes in v4:
 - simplify the case of disabling CQM in nl80211_set_cqm_rssi
---
 include/net/cfg80211.h       |  13 ++++
 include/uapi/linux/nl80211.h |   9 ++-
 net/wireless/core.c          |   9 +++
 net/wireless/core.h          |   9 +++
 net/wireless/nl80211.c       | 145 +++++++++++++++++++++++++++++++++++++++----
 net/wireless/rdev-ops.h      |  12 ++++
 net/wireless/trace.h         |  22 +++++++
 7 files changed, 205 insertions(+), 14 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 9adff4e..bb84edb 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2660,6 +2660,11 @@ struct cfg80211_nan_func {
  *	the current level is above/below the configured threshold; this may
  *	need some care when the configuration is changed (without first being
  *	disabled.)
+ * @set_cqm_rssi_range_config: Configure two RSSI thresholds in the
+ *	connection quality monitor.  An event is to be sent only when the
+ *	signal level is found to be outside the two values.  The driver should
+ *	set %NL80211_EXT_FEATURE_CQM_RSSI_LIST if this method is implemented.
+ *	If it is provided then there's no point providing @set_cqm_rssi_config.
  * @set_cqm_txe_config: Configure connection quality monitor TX error
  *	thresholds.
  * @sched_scan_start: Tell the driver to start a scheduled scan.
@@ -2949,6 +2954,10 @@ struct cfg80211_ops {
 				       struct net_device *dev,
 				       s32 rssi_thold, u32 rssi_hyst);
 
+	int	(*set_cqm_rssi_range_config)(struct wiphy *wiphy,
+					     struct net_device *dev,
+					     s32 rssi_low, s32 rssi_high);
+
 	int	(*set_cqm_txe_config)(struct wiphy *wiphy,
 				      struct net_device *dev,
 				      u32 rate, u32 pkts, u32 intvl);
@@ -3782,6 +3791,7 @@ void wiphy_free(struct wiphy *wiphy);
 struct cfg80211_conn;
 struct cfg80211_internal_bss;
 struct cfg80211_cached_keys;
+struct cfg80211_cqm_config;
 
 /**
  * struct wireless_dev - wireless device state
@@ -3845,6 +3855,7 @@ struct cfg80211_cached_keys;
  * @event_list: (private) list for internal event processing
  * @event_lock: (private) lock for event list
  * @owner_nlportid: (private) owner socket port ID
+ * @cqm_config: (private) nl80211 RSSI monitor state
  */
 struct wireless_dev {
 	struct wiphy *wiphy;
@@ -3913,6 +3924,8 @@ struct wireless_dev {
 		bool prev_bssid_valid;
 	} wext;
 #endif
+
+	struct cfg80211_cqm_config *cqm_config;
 };
 
 static inline u8 *wdev_address(struct wireless_dev *wdev)
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 5cd7a81..e011b75 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -3898,7 +3898,10 @@ enum nl80211_ps_state {
  * @__NL80211_ATTR_CQM_INVALID: invalid
  * @NL80211_ATTR_CQM_RSSI_THOLD: RSSI threshold in dBm. This value specifies
  *	the threshold for the RSSI level at which an event will be sent. Zero
- *	to disable.
+ *	to disable.  Alternatively, if %NL80211_EXT_FEATURE_CQM_RSSI_LIST is
+ *	set, multiple values can be supplied as a low-to-high sorted array of
+ *	threshold values in dBm.  Events will be sent when the RSSI value
+ *	crosses any of the thresholds.
  * @NL80211_ATTR_CQM_RSSI_HYST: RSSI hysteresis in dBm. This value specifies
  *	the minimum amount the RSSI level must change after an event before a
  *	new event may be issued (to reduce effects of RSSI oscillation).
@@ -4702,6 +4705,9 @@ enum nl80211_feature_flags {
  *	configuration (AP/mesh) with VHT rates.
  * @NL80211_EXT_FEATURE_FILS_STA: This driver supports Fast Initial Link Setup
  *	with user space SME (NL80211_CMD_AUTHENTICATE) in station mode.
+ * @NL80211_EXT_FEATURE_CQM_RSSI_LIST: This driver accepts lists of RSSI
+ *	threshold values to monitor in the %NL80211_ATTR_CQM_RSSI_THOLD
+ *	attribute rather than exactly one threshold.
  *
  * @NUM_NL80211_EXT_FEATURES: number of extended features.
  * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -4717,6 +4723,7 @@ enum nl80211_ext_feature_index {
 	NL80211_EXT_FEATURE_BEACON_RATE_HT,
 	NL80211_EXT_FEATURE_BEACON_RATE_VHT,
 	NL80211_EXT_FEATURE_FILS_STA,
+	NL80211_EXT_FEATURE_CQM_RSSI_LIST,
 
 	/* add new features before the definition below */
 	NUM_NL80211_EXT_FEATURES,
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 903fc41..7f5760c 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -953,6 +953,12 @@ void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked)
 }
 EXPORT_SYMBOL(wiphy_rfkill_set_hw_state);
 
+void cfg80211_cqm_config_free(struct wireless_dev *wdev)
+{
+	kfree(wdev->cqm_config);
+	wdev->cqm_config = NULL;
+}
+
 void cfg80211_unregister_wdev(struct wireless_dev *wdev)
 {
 	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
@@ -979,6 +985,8 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)
 		WARN_ON_ONCE(1);
 		break;
 	}
+
+	cfg80211_cqm_config_free(wdev);
 }
 EXPORT_SYMBOL(cfg80211_unregister_wdev);
 
@@ -1233,6 +1241,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
 			kzfree(wdev->wext.keys);
 #endif
 			flush_work(&wdev->disconnect_wk);
+			cfg80211_cqm_config_free(wdev);
 		}
 		/*
 		 * synchronise (so that we won't find this netdev
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 9d1a030..c8e218b 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -271,6 +271,13 @@ struct cfg80211_iface_destroy {
 	u32 nlportid;
 };
 
+struct cfg80211_cqm_config {
+	u32 rssi_hyst;
+	s32 last_rssi_event_value;
+	int n_rssi_thresholds;
+	s32 rssi_thresholds[0];
+};
+
 void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev);
 
 /* free object */
@@ -507,4 +514,6 @@ void cfg80211_stop_nan(struct cfg80211_registered_device *rdev,
 #define CFG80211_DEV_WARN_ON(cond)	({bool __r = (cond); __r; })
 #endif
 
+void cfg80211_cqm_config_free(struct wireless_dev *wdev);
+
 #endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 7749687..623bf0a 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -9380,7 +9380,7 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
 
 static const struct nla_policy
 nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
-	[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
+	[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_BINARY },
 	[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
 	[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
 	[NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
@@ -9409,28 +9409,130 @@ static int nl80211_set_cqm_txe(struct genl_info *info,
 	return rdev_set_cqm_txe_config(rdev, dev, rate, pkts, intvl);
 }
 
+static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
+				    struct net_device *dev)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	s32 last, low, high;
+	u32 hyst;
+	int i, n;
+	int err;
+
+	/* RSSI reporting disabled? */
+	if (!wdev->cqm_config)
+		return rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0);
+
+	/*
+	 * Obtain current RSSI value if possible, if not and no RSSI threshold
+	 * event has been received yet, we should receive an event after a
+	 * connection is established and enough beacons received to calculate
+	 * the average.
+	 */
+	if (!wdev->cqm_config->last_rssi_event_value && wdev->current_bss &&
+	    rdev->ops->get_station) {
+		struct station_info sinfo;
+		u8 *mac_addr;
+
+		mac_addr = wdev->current_bss->pub.bssid;
+
+		err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
+		if (err)
+			return err;
+
+		if (sinfo.filled & BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG))
+			wdev->cqm_config->last_rssi_event_value =
+				(s8) sinfo.rx_beacon_signal_avg;
+	}
+
+	if (!wiphy_ext_feature_isset(&rdev->wiphy,
+				     NL80211_EXT_FEATURE_CQM_RSSI_LIST))
+		return -EOPNOTSUPP;
+
+	last = wdev->cqm_config->last_rssi_event_value;
+	hyst = wdev->cqm_config->rssi_hyst;
+	n = wdev->cqm_config->n_rssi_thresholds;
+
+	for (i = 0; i < n; i++)
+		if (last < wdev->cqm_config->rssi_thresholds[i])
+			break;
+
+	low = i > 0 ? wdev->cqm_config->rssi_thresholds[i - 1] : S32_MIN;
+	high = i < n ? wdev->cqm_config->rssi_thresholds[i] : S32_MAX;
+
+	if (low > (s32) (last - hyst))
+		low = last - hyst;
+	if (high < (s32) (last + hyst))
+		high = last + hyst;
+
+	return rdev_set_cqm_rssi_range_config(rdev, dev, low, high - 1);
+}
+
 static int nl80211_set_cqm_rssi(struct genl_info *info,
-				s32 threshold, u32 hysteresis)
+				const s32 *thresholds, int n_thresholds,
+				u32 hysteresis)
 {
 	struct cfg80211_registered_device *rdev = info->user_ptr[0];
 	struct net_device *dev = info->user_ptr[1];
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	int i, err;
+	s32 prev = S32_MIN;
 
-	if (threshold > 0)
-		return -EINVAL;
-
-	/* disabling - hysteresis should also be zero then */
-	if (threshold == 0)
-		hysteresis = 0;
+	/* Check all values negative and sorted */
+	for (i = 0; i < n_thresholds; i++) {
+		if (thresholds[i] > 0 || thresholds[i] <= prev)
+			return -EINVAL;
 
-	if (!rdev->ops->set_cqm_rssi_config)
-		return -EOPNOTSUPP;
+		prev = thresholds[i];
+	}
 
 	if (wdev->iftype != NL80211_IFTYPE_STATION &&
 	    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
 		return -EOPNOTSUPP;
 
-	return rdev_set_cqm_rssi_config(rdev, dev, threshold, hysteresis);
+	wdev_lock(wdev);
+	cfg80211_cqm_config_free(wdev);
+	wdev_unlock(wdev);
+
+	if (n_thresholds <= 1 && rdev->ops->set_cqm_rssi_config) {
+		if (n_thresholds == 0 || thresholds[0] == 0) /* Disabling */
+			return rdev_set_cqm_rssi_config(rdev, dev, 0, 0);
+
+		return rdev_set_cqm_rssi_config(rdev, dev,
+						thresholds[0], hysteresis);
+	}
+
+	if (!wiphy_ext_feature_isset(&rdev->wiphy,
+				     NL80211_EXT_FEATURE_CQM_RSSI_LIST))
+		return -EOPNOTSUPP;
+
+	if (n_thresholds == 1 && thresholds[0] == 0) /* Disabling */
+		n_thresholds = 0;
+
+	wdev_lock(wdev);
+	if (n_thresholds) {
+		struct cfg80211_cqm_config *cqm_config;
+
+		cqm_config = kzalloc(sizeof(struct cfg80211_cqm_config) +
+				     n_thresholds * sizeof(s32), GFP_KERNEL);
+		if (!cqm_config) {
+			err = -ENOMEM;
+			goto unlock;
+		}
+
+		cqm_config->rssi_hyst = hysteresis;
+		cqm_config->n_rssi_thresholds = n_thresholds;
+		memcpy(cqm_config->rssi_thresholds, thresholds,
+		       n_thresholds * sizeof(s32));
+
+		wdev->cqm_config = cqm_config;
+	}
+
+	err = cfg80211_cqm_rssi_update(rdev, dev);
+
+unlock:
+	wdev_unlock(wdev);
+
+	return err;
 }
 
 static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
@@ -9450,10 +9552,16 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
 
 	if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] &&
 	    attrs[NL80211_ATTR_CQM_RSSI_HYST]) {
-		s32 threshold = nla_get_s32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
+		const s32 *thresholds =
+			nla_data(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
+		int len = nla_len(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
 		u32 hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
 
-		return nl80211_set_cqm_rssi(info, threshold, hysteresis);
+		if (len % 4)
+			return -EINVAL;
+
+		return nl80211_set_cqm_rssi(info, thresholds, len / 4,
+					    hysteresis);
 	}
 
 	if (attrs[NL80211_ATTR_CQM_TXE_RATE] &&
@@ -13877,6 +13985,8 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
 			      s32 rssi_level, gfp_t gfp)
 {
 	struct sk_buff *msg;
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
 
 	trace_cfg80211_cqm_rssi_notify(dev, rssi_event, rssi_level);
 
@@ -13884,6 +13994,15 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
 		    rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
 		return;
 
+	if (wdev->cqm_config) {
+		wdev->cqm_config->last_rssi_event_value = rssi_level;
+
+		cfg80211_cqm_rssi_update(rdev, dev);
+
+		if (rssi_level == 0)
+			rssi_level = wdev->cqm_config->last_rssi_event_value;
+	}
+
 	msg = cfg80211_prepare_cqm(dev, NULL, gfp);
 	if (!msg)
 		return;
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 2f42507..f2baf59 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -750,6 +750,18 @@ rdev_set_cqm_rssi_config(struct cfg80211_registered_device *rdev,
 }
 
 static inline int
+rdev_set_cqm_rssi_range_config(struct cfg80211_registered_device *rdev,
+			       struct net_device *dev, s32 low, s32 high)
+{
+	int ret;
+	trace_rdev_set_cqm_rssi_range_config(&rdev->wiphy, dev, low, high);
+	ret = rdev->ops->set_cqm_rssi_range_config(&rdev->wiphy, dev,
+						   low, high);
+	trace_rdev_return_int(&rdev->wiphy, ret);
+	return ret;
+}
+
+static inline int
 rdev_set_cqm_txe_config(struct cfg80211_registered_device *rdev,
 			struct net_device *dev, u32 rate, u32 pkts, u32 intvl)
 {
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 2419c39..4e6dab3 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -1322,6 +1322,28 @@ TRACE_EVENT(rdev_set_cqm_rssi_config,
 		 __entry->rssi_thold, __entry->rssi_hyst)
 );
 
+TRACE_EVENT(rdev_set_cqm_rssi_range_config,
+	TP_PROTO(struct wiphy *wiphy,
+		 struct net_device *netdev, s32 low, s32 high),
+	TP_ARGS(wiphy, netdev, low, high),
+	TP_STRUCT__entry(
+		WIPHY_ENTRY
+		NETDEV_ENTRY
+		__field(s32, rssi_low)
+		__field(s32, rssi_high)
+	),
+	TP_fast_assign(
+		WIPHY_ASSIGN;
+		NETDEV_ASSIGN;
+		__entry->rssi_low = low;
+		__entry->rssi_high = high;
+	),
+	TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT
+		  ", range: %d - %d ",
+		  WIPHY_PR_ARG, NETDEV_PR_ARG,
+		  __entry->rssi_low, __entry->rssi_high)
+);
+
 TRACE_EVENT(rdev_set_cqm_txe_config,
 	TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u32 rate,
 		 u32 pkts, u32 intvl),
-- 
2.9.3

^ permalink raw reply related

* [PATCH v4 2/5] cfg80211: Pass new RSSI level in CQM RSSI notification
From: Andrew Zaborowski @ 2017-01-25 11:43 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <20170125114344.8179-1-andrew.zaborowski@intel.com>

Update the drivers to pass the RSSI level as a cfg80211_cqm_rssi_notify
parameter and pass this value to userspace in a new nl80211 attribute.
This helps both userspace and also helps in the implementation of the
multiple RSSI thresholds CQM mechanism.

Note for marvell/mwifiex I pass 0 for the RSSI value because the new
RSSI value is not available to the driver at the time of the
cfg80211_cqm_rssi_notify call, but the driver queries the new value
immediately after that, so it is actually available just a moment later
if we wanted to defer caling cfg80211_cqm_rssi_notify until that moment.
Without this, the new cfg80211 code (patch 3) will call .get_station
which will send a duplicate HostCmd_CMD_RSSI_INFO command to the hardware.

Signed-off-by: Andrew Zaborowski <andrew.zaborowski@intel.com>
---
 drivers/net/wireless/marvell/mwifiex/sta_event.c |  4 ++--
 drivers/net/wireless/rndis_wlan.c                |  2 +-
 include/net/cfg80211.h                           |  3 ++-
 include/uapi/linux/nl80211.h                     |  3 +++
 net/mac80211/mlme.c                              |  2 +-
 net/wireless/nl80211.c                           |  9 +++++++--
 net/wireless/trace.h                             | 11 +++++++----
 7 files changed, 23 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/sta_event.c b/drivers/net/wireless/marvell/mwifiex/sta_event.c
index 9df0c4d..5cc3aa7 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_event.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_event.c
@@ -824,7 +824,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 	case EVENT_RSSI_LOW:
 		cfg80211_cqm_rssi_notify(priv->netdev,
 					 NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
-					 GFP_KERNEL);
+					 0, GFP_KERNEL);
 		mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO,
 				 HostCmd_ACT_GEN_GET, 0, NULL, false);
 		priv->subsc_evt_rssi_state = RSSI_LOW_RECVD;
@@ -839,7 +839,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 	case EVENT_RSSI_HIGH:
 		cfg80211_cqm_rssi_notify(priv->netdev,
 					 NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
-					 GFP_KERNEL);
+					 0, GFP_KERNEL);
 		mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO,
 				 HostCmd_ACT_GEN_GET, 0, NULL, false);
 		priv->subsc_evt_rssi_state = RSSI_HIGH_RECVD;
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 603c904..785334f 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -3187,7 +3187,7 @@ static void rndis_do_cqm(struct usbnet *usbdev, s32 rssi)
 		return;
 
 	priv->last_cqm_event_rssi = rssi;
-	cfg80211_cqm_rssi_notify(usbdev->net, event, GFP_KERNEL);
+	cfg80211_cqm_rssi_notify(usbdev->net, event, rssi, GFP_KERNEL);
 }
 
 #define DEVICE_POLLER_JIFFIES (HZ)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 57383a1..9adff4e 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -5303,6 +5303,7 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
  * cfg80211_cqm_rssi_notify - connection quality monitoring rssi event
  * @dev: network device
  * @rssi_event: the triggered RSSI event
+ * @rssi_level: new RSSI level value or 0 if not available
  * @gfp: context flags
  *
  * This function is called when a configured connection quality monitoring
@@ -5310,7 +5311,7 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
  */
 void cfg80211_cqm_rssi_notify(struct net_device *dev,
 			      enum nl80211_cqm_rssi_threshold_event rssi_event,
-			      gfp_t gfp);
+			      s32 rssi_level, gfp_t gfp);
 
 /**
  * cfg80211_cqm_pktloss_notify - notify userspace about packetloss to peer
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 455ed9b..5cd7a81 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -3918,6 +3918,8 @@ enum nl80211_ps_state {
  *	%NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting.
  * @NL80211_ATTR_CQM_BEACON_LOSS_EVENT: flag attribute that's set in a beacon
  *	loss event
+ * @NL80211_ATTR_CQM_RSSI_LEVEL: the RSSI value in dBm that triggered the
+ *	RSSI threshold event.
  * @__NL80211_ATTR_CQM_AFTER_LAST: internal
  * @NL80211_ATTR_CQM_MAX: highest key attribute
  */
@@ -3931,6 +3933,7 @@ enum nl80211_attr_cqm {
 	NL80211_ATTR_CQM_TXE_PKTS,
 	NL80211_ATTR_CQM_TXE_INTVL,
 	NL80211_ATTR_CQM_BEACON_LOSS_EVENT,
+	NL80211_ATTR_CQM_RSSI_LEVEL,
 
 	/* keep last */
 	__NL80211_ATTR_CQM_AFTER_LAST,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index a40b90b..0cfa215 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -5052,7 +5052,7 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
 
 	trace_api_cqm_rssi_notify(sdata, rssi_event, rssi_level);
 
-	cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp);
+	cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, rssi_level, gfp);
 }
 EXPORT_SYMBOL(ieee80211_cqm_rssi_notify);
 
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index cc05d36..7749687 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -9386,6 +9386,7 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
 	[NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
 	[NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 },
 	[NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 },
+	[NL80211_ATTR_CQM_RSSI_LEVEL] = { .type = NLA_S32 },
 };
 
 static int nl80211_set_cqm_txe(struct genl_info *info,
@@ -13873,11 +13874,11 @@ static void cfg80211_send_cqm(struct sk_buff *msg, gfp_t gfp)
 
 void cfg80211_cqm_rssi_notify(struct net_device *dev,
 			      enum nl80211_cqm_rssi_threshold_event rssi_event,
-			      gfp_t gfp)
+			      s32 rssi_level, gfp_t gfp)
 {
 	struct sk_buff *msg;
 
-	trace_cfg80211_cqm_rssi_notify(dev, rssi_event);
+	trace_cfg80211_cqm_rssi_notify(dev, rssi_event, rssi_level);
 
 	if (WARN_ON(rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW &&
 		    rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
@@ -13891,6 +13892,10 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
 			rssi_event))
 		goto nla_put_failure;
 
+	if (rssi_level && nla_put_s32(msg, NL80211_ATTR_CQM_RSSI_LEVEL,
+				      rssi_level))
+		goto nla_put_failure;
+
 	cfg80211_send_cqm(msg, gfp);
 
 	return;
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index ea1b47e..2419c39 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2490,18 +2490,21 @@ TRACE_EVENT(cfg80211_mgmt_tx_status,
 
 TRACE_EVENT(cfg80211_cqm_rssi_notify,
 	TP_PROTO(struct net_device *netdev,
-		 enum nl80211_cqm_rssi_threshold_event rssi_event),
-	TP_ARGS(netdev, rssi_event),
+		 enum nl80211_cqm_rssi_threshold_event rssi_event,
+		 s32 rssi_level),
+	TP_ARGS(netdev, rssi_event, rssi_level),
 	TP_STRUCT__entry(
 		NETDEV_ENTRY
 		__field(enum nl80211_cqm_rssi_threshold_event, rssi_event)
+		__field(s32, rssi_level)
 	),
 	TP_fast_assign(
 		NETDEV_ASSIGN;
 		__entry->rssi_event = rssi_event;
+		__entry->rssi_level = rssi_level;
 	),
-	TP_printk(NETDEV_PR_FMT ", rssi event: %d",
-		  NETDEV_PR_ARG, __entry->rssi_event)
+	TP_printk(NETDEV_PR_FMT ", rssi event: %d, level: %d",
+		  NETDEV_PR_ARG, __entry->rssi_event, __entry->rssi_level)
 );
 
 TRACE_EVENT(cfg80211_reg_can_beacon,
-- 
2.9.3

^ permalink raw reply related

* [PATCH v4 5/5] wireless: Set NL80211_EXT_FEATURE_CQM_RSSI_LIST in multiple drivers
From: Andrew Zaborowski @ 2017-01-25 11:43 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <20170125114344.8179-1-andrew.zaborowski@intel.com>

Set the NL80211_EXT_FEATURE_CQM_RSSI_LIST wiphy extended feature
wholesale in all mac80211-based drivers that do not set the
IEEE80211_VIF_BEACON_FILTER flags on their interfaces.  mac80211 will
be processing supplied RSSI values in ieee80211_rx_mgmt_beacon and
will detect when the thresholds set by
ieee80211_set_cqm_rssi_range_config are crossed.  Remaining (few)
drivers need code to enable the firmware to monitor the thresholds.
This is mostly only compile-tested.

Signed-off-by: Andrew Zaborowski <andrew.zaborowski@intel.com>
---
 drivers/net/wireless/admtek/adm8211.c                          | 2 ++
 drivers/net/wireless/ath/ar5523/ar5523.c                       | 2 ++
 drivers/net/wireless/ath/ath10k/mac.c                          | 2 ++
 drivers/net/wireless/ath/ath5k/base.c                          | 2 ++
 drivers/net/wireless/ath/ath9k/htc_drv_init.c                  | 2 ++
 drivers/net/wireless/ath/ath9k/init.c                          | 2 ++
 drivers/net/wireless/ath/carl9170/main.c                       | 2 ++
 drivers/net/wireless/ath/wcn36xx/main.c                        | 3 +++
 drivers/net/wireless/atmel/at76c50x-usb.c                      | 2 ++
 drivers/net/wireless/broadcom/b43/main.c                       | 2 ++
 drivers/net/wireless/broadcom/b43legacy/main.c                 | 2 ++
 drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c | 2 ++
 drivers/net/wireless/intel/iwlegacy/3945-mac.c                 | 2 ++
 drivers/net/wireless/intel/iwlegacy/4965-mac.c                 | 2 ++
 drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c              | 2 ++
 drivers/net/wireless/mac80211_hwsim.c                          | 2 ++
 drivers/net/wireless/marvell/libertas_tf/main.c                | 2 ++
 drivers/net/wireless/marvell/mwl8k.c                           | 2 ++
 drivers/net/wireless/mediatek/mt7601u/init.c                   | 2 ++
 drivers/net/wireless/ralink/rt2x00/rt2x00dev.c                 | 3 +++
 drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c             | 2 ++
 drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c             | 2 ++
 drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c          | 2 ++
 drivers/net/wireless/rsi/rsi_91x_mac80211.c                    | 2 ++
 drivers/net/wireless/zydas/zd1211rw/zd_mac.c                   | 2 ++
 drivers/staging/vt6655/device_main.c                           | 2 ++
 drivers/staging/vt6656/main_usb.c                              | 2 ++
 27 files changed, 56 insertions(+)

diff --git a/drivers/net/wireless/admtek/adm8211.c b/drivers/net/wireless/admtek/adm8211.c
index 70ecd82..96362f0 100644
--- a/drivers/net/wireless/admtek/adm8211.c
+++ b/drivers/net/wireless/admtek/adm8211.c
@@ -1896,6 +1896,8 @@ static int adm8211_probe(struct pci_dev *pdev,
 
 	dev->wiphy->bands[NL80211_BAND_2GHZ] = &priv->band;
 
+	wiphy_ext_feature_set(dev->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	err = ieee80211_register_hw(dev);
 	if (err) {
 		printk(KERN_ERR "%s (adm8211): Cannot register device\n",
diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c
index 7a60d2e..f2f4ccf 100644
--- a/drivers/net/wireless/ath/ar5523/ar5523.c
+++ b/drivers/net/wireless/ath/ar5523/ar5523.c
@@ -1689,6 +1689,8 @@ static int ar5523_probe(struct usb_interface *intf,
 	if (error)
 		goto out_cancel_rx_cmd;
 
+	wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	usb_set_intfdata(intf, hw);
 
 	error = ieee80211_register_hw(hw);
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index aa545a1..fe7eab3 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -8146,6 +8146,8 @@ int ath10k_mac_register(struct ath10k *ar)
 	ar->hw->wiphy->cipher_suites = cipher_suites;
 	ar->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
 
+	wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	ret = ieee80211_register_hw(ar->hw);
 	if (ret) {
 		ath10k_err(ar, "failed to register ieee80211: %d\n", ret);
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index d98fd42..92ece64 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -2564,6 +2564,8 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops)
 
 	hw->extra_tx_headroom = 2;
 
+	wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	/*
 	 * Mark the device as detached to avoid processing
 	 * interrupts until setup is complete.
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index b65c1b6..defacc6 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -780,6 +780,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
 	}
 
 	SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
+
+	wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
 }
 
 static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv)
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 2079466..6bacda1 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -951,6 +951,8 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
 	ath9k_cmn_reload_chainmask(ah);
 
 	SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
+
+	wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
 }
 
 int ath9k_init_device(u16 devid, struct ath_softc *sc,
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index ffb22a0..988c885 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -1874,6 +1874,8 @@ void *carl9170_alloc(size_t priv_size)
 	for (i = 0; i < ARRAY_SIZE(ar->noise); i++)
 		ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */
 
+	wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	return ar;
 
 err_nomem:
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index e1d59da..1b6c173 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -1046,6 +1046,9 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
 	wcn->hw->sta_data_size = sizeof(struct wcn36xx_sta);
 	wcn->hw->vif_data_size = sizeof(struct wcn36xx_vif);
 
+	wiphy_ext_feature_set(wcn->hw->wiphy,
+			      NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	return ret;
 }
 
diff --git a/drivers/net/wireless/atmel/at76c50x-usb.c b/drivers/net/wireless/atmel/at76c50x-usb.c
index 0e18067..09defbc 100644
--- a/drivers/net/wireless/atmel/at76c50x-usb.c
+++ b/drivers/net/wireless/atmel/at76c50x-usb.c
@@ -2377,6 +2377,8 @@ static int at76_init_new_device(struct at76_priv *priv,
 
 	wiphy->hw_version = priv->board_type;
 
+	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	ret = ieee80211_register_hw(priv->hw);
 	if (ret) {
 		printk(KERN_ERR "cannot register mac80211 hw (status %d)!\n",
diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c
index 52f3541..d23aac7 100644
--- a/drivers/net/wireless/broadcom/b43/main.c
+++ b/drivers/net/wireless/broadcom/b43/main.c
@@ -5598,6 +5598,8 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev)
 
 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
 
+	wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	wl->hw_registred = false;
 	hw->max_rates = 2;
 	SET_IEEE80211_DEV(hw, dev->dev);
diff --git a/drivers/net/wireless/broadcom/b43legacy/main.c b/drivers/net/wireless/broadcom/b43legacy/main.c
index e97ab2b..44781b8 100644
--- a/drivers/net/wireless/broadcom/b43legacy/main.c
+++ b/drivers/net/wireless/broadcom/b43legacy/main.c
@@ -3850,6 +3850,8 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
 	else
 		SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac);
 
+	wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	/* Get and initialize struct b43legacy_wl */
 	wl = hw_to_b43legacy_wl(hw);
 	memset(wl, 0, sizeof(*wl));
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
index 7c2a9a9..ddfdfe1 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
@@ -1082,6 +1082,8 @@ static int ieee_hw_init(struct ieee80211_hw *hw)
 	 * hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
 	 */
 
+	wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	hw->rate_control_algorithm = "minstrel_ht";
 
 	hw->sta_data_size = 0;
diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c
index 466912e..ebd74f7 100644
--- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c
+++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c
@@ -3592,6 +3592,8 @@ il3945_setup_mac(struct il_priv *il)
 
 	il_leds_init(il);
 
+	wiphy_ext_feature_set(il->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	ret = ieee80211_register_hw(il->hw);
 	if (ret) {
 		IL_ERR("Failed to register hw (error %d)\n", ret);
diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c
index a91d170..54ecda5 100644
--- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c
@@ -5799,6 +5799,8 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length)
 
 	il_leds_init(il);
 
+	wiphy_ext_feature_set(il->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	ret = ieee80211_register_hw(il->hw);
 	if (ret) {
 		IL_ERR("Failed to register hw (error %d)\n", ret);
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c
index 8c07194..2b23c3f 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c
@@ -213,6 +213,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
 
 	iwl_leds_init(priv);
 
+	wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	ret = ieee80211_register_hw(priv->hw);
 	if (ret) {
 		IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 1620a5d..0150747 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -2645,6 +2645,8 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
 	if (param->no_vif)
 		ieee80211_hw_set(hw, NO_AUTO_VIF);
 
+	wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	err = ieee80211_register_hw(hw);
 	if (err < 0) {
 		printk(KERN_DEBUG "mac80211_hwsim: ieee80211_register_hw failed (%d)\n",
diff --git a/drivers/net/wireless/marvell/libertas_tf/main.c b/drivers/net/wireless/marvell/libertas_tf/main.c
index 54e426c..d803331 100644
--- a/drivers/net/wireless/marvell/libertas_tf/main.c
+++ b/drivers/net/wireless/marvell/libertas_tf/main.c
@@ -641,6 +641,8 @@ struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev)
 		BIT(NL80211_IFTYPE_ADHOC);
 	skb_queue_head_init(&priv->bc_ps_buf);
 
+	wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	SET_IEEE80211_DEV(hw, dmdev);
 
 	INIT_WORK(&priv->cmd_work, lbtf_cmd_work);
diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c
index b1b400b..c295a4c 100644
--- a/drivers/net/wireless/marvell/mwl8k.c
+++ b/drivers/net/wireless/marvell/mwl8k.c
@@ -6144,6 +6144,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)
 	if (priv->sta_macids_supported || priv->device_info->fw_image_sta)
 		hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION);
 
+	wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	rc = ieee80211_register_hw(hw);
 	if (rc) {
 		wiphy_err(hw->wiphy, "Cannot register device\n");
diff --git a/drivers/net/wireless/mediatek/mt7601u/init.c b/drivers/net/wireless/mediatek/mt7601u/init.c
index a6e9017..d3b611a 100644
--- a/drivers/net/wireless/mediatek/mt7601u/init.c
+++ b/drivers/net/wireless/mediatek/mt7601u/init.c
@@ -615,6 +615,8 @@ int mt7601u_register_device(struct mt7601u_dev *dev)
 	wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
 	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
 
+	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	ret = mt76_init_sband_2g(dev);
 	if (ret)
 		return ret;
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
index eb7b714..139bb51 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
@@ -1389,6 +1389,9 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
 
 	rt2x00dev->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
 
+	wiphy_ext_feature_set(rt2x00dev->hw->wiphy,
+			      NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	/*
 	 * Initialize ieee80211 structure.
 	 */
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c
index e895a84..e387dec 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c
@@ -1877,6 +1877,8 @@ static int rtl8180_probe(struct pci_dev *pdev,
 	else
 		ieee80211_hw_set(dev, SIGNAL_UNSPEC);
 
+	wiphy_ext_feature_set(dev->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	rtl8180_eeprom_read(priv);
 
 	switch (priv->rf_type) {
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
index 231f84d..274ad6d 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
@@ -1609,6 +1609,8 @@ static int rtl8187_probe(struct usb_interface *intf,
 	dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
 				      BIT(NL80211_IFTYPE_ADHOC) ;
 
+	wiphy_ext_feature_set(dev->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b)
 		printk(KERN_INFO "rtl8187: inconsistency between id with OEM"
 		       " info!\n");
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
index 3a86675..75fbb39 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
@@ -6134,6 +6134,8 @@ static int rtl8xxxu_probe(struct usb_interface *interface,
 	ieee80211_hw_set(hw, HAS_RATE_CONTROL);
 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
 
+	wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	ret = ieee80211_register_hw(priv->hw);
 	if (ret) {
 		dev_err(&udev->dev, "%s: Failed to register: %i\n",
diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
index e321647..021e5ac 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -1261,6 +1261,8 @@ int rsi_mac80211_attach(struct rsi_common *common)
 
 	wiphy->reg_notifier = rsi_reg_notify;
 
+	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	status = ieee80211_register_hw(hw);
 	if (status)
 		return status;
diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c
index 3e37a04..fe6517a 100644
--- a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c
@@ -1408,6 +1408,8 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
 		BIT(NL80211_IFTYPE_ADHOC) |
 		BIT(NL80211_IFTYPE_AP);
 
+	wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	hw->max_signal = 100;
 	hw->queues = 1;
 	hw->extra_tx_headroom = sizeof(struct zd_ctrlset);
diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c
index da0f711..7f18f70 100644
--- a/drivers/staging/vt6655/device_main.c
+++ b/drivers/staging/vt6655/device_main.c
@@ -1661,6 +1661,8 @@ vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent)
 	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
 		BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
 
+	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	ieee80211_hw_set(priv->hw, TIMING_BEACON_ONLY);
 	ieee80211_hw_set(priv->hw, SIGNAL_DBM);
 	ieee80211_hw_set(priv->hw, RX_INCLUDES_FCS);
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c
index 50d02d9..80b5c73 100644
--- a/drivers/staging/vt6656/main_usb.c
+++ b/drivers/staging/vt6656/main_usb.c
@@ -986,6 +986,8 @@ vt6656_probe(struct usb_interface *intf, const struct usb_device_id *id)
 	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
 		BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
 
+	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
 	ieee80211_hw_set(priv->hw, TIMING_BEACON_ONLY);
 	ieee80211_hw_set(priv->hw, SIGNAL_DBM);
 	ieee80211_hw_set(priv->hw, RX_INCLUDES_FCS);
-- 
2.9.3

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox