Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH v2] mac80211: fix mesh fail_avg check
From: Rajkumar Manoharan @ 2017-02-15 20:46 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, rmanohar, Rajkumar Manoharan

Mesh failure average never be more than 100. Only in case of
fixed path, average will be more than threshold limit (95%).
With recent EWMA changes it may go upto 99 as it is scaled to
100. It make sense to return maximum metric when average is
greater than threshold limit.

Signed-off-by: Rajkumar Manoharan <rmanohar@qca.qualcomm.com>
---
v2: define MACRO for threshold

 net/mac80211/mesh_hwmp.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index d07ee3ca07ee..4005edd71fe8 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -16,6 +16,7 @@
 #define TEST_FRAME_LEN	8192
 #define MAX_METRIC	0xffffffff
 #define ARITH_SHIFT	8
+#define LINK_FAIL_THRESH 95
 
 #define MAX_PREQ_QUEUE_LEN	64
 
@@ -311,7 +312,8 @@ void ieee80211s_update_metric(struct ieee80211_local *local,
 	 * feed failure as 100 and success as 0
 	 */
 	ewma_mesh_fail_avg_add(&sta->mesh->fail_avg, failed * 100);
-	if (ewma_mesh_fail_avg_read(&sta->mesh->fail_avg) > 95)
+	if (ewma_mesh_fail_avg_read(&sta->mesh->fail_avg) >
+			LINK_FAIL_THRESH)
 		mesh_plink_broken(sta);
 }
 
@@ -339,7 +341,7 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local,
 	if (rate) {
 		err = 0;
 	} else {
-		if (fail_avg >= 100)
+		if (fail_avg > LINK_FAIL_THRESH)
 			return MAX_METRIC;
 
 		sta_set_rate_info_tx(sta, &sta->tx_stats.last_rate, &rinfo);
-- 
1.9.1

^ permalink raw reply related

* Re: [PATCH 1/2] mac80211: Update the driver with beacon info constantly
From: kbuild test robot @ 2017-02-15 20:41 UTC (permalink / raw)
  To: Doru
  Cc: kbuild-all, linux-wireless, andra.paraschiv7, costin.raiciu,
	dragos.niculescu, Doru Gucea
In-Reply-To: <1487185278-8643-1-git-send-email-gucea.doru@gmail.com>

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

Hi Doru,

[auto build test ERROR on mac80211-next/master]
[also build test ERROR on v4.10-rc8 next-20170215]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Doru/mac80211-Update-the-driver-with-beacon-info-constantly/20170216-034614
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git master
config: x86_64-lkp (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All errors (new ones prefixed by >>):

   net/mac80211/mlme.c: In function 'ieee80211_rx_mgmt_beacon':
>> net/mac80211/mlme.c:3555:35: error: 'sata' undeclared (first use in this function)
     ieee80211_bss_info_change_notify(sata, changed);
                                      ^~~~
   net/mac80211/mlme.c:3555:35: note: each undeclared identifier is reported only once for each function it appears in

vim +/sata +3555 net/mac80211/mlme.c

  3549		}
  3550	
  3551		/* trigger hardware timers adjustment
  3552		 * this needs to be done before beacon filtering
  3553		*/
  3554		changed |= BSS_CHANGED_BEACON_INFO;
> 3555		ieee80211_bss_info_change_notify(sata, changed);
  3556	
  3557		if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
  3558			return;

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 24694 bytes --]

^ permalink raw reply

* Re: [PATCH 2/2] ath9k_htc: Adjust beacon timers for power save
From: kbuild test robot @ 2017-02-15 20:31 UTC (permalink / raw)
  To: Doru
  Cc: kbuild-all, linux-wireless, andra.paraschiv7, costin.raiciu,
	dragos.niculescu, Doru Gucea
In-Reply-To: <1487185303-8700-1-git-send-email-gucea.doru@gmail.com>

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

Hi Doru,

[auto build test ERROR on mac80211-next/master]
[also build test ERROR on v4.10-rc8 next-20170215]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Doru/mac80211-Update-the-driver-with-beacon-info-constantly/20170216-034614
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git master
config: i386-randconfig-s1-201707 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

   drivers/net/wireless/ath/ath9k/main.c: In function 'ath9k_bss_info_changed':
>> drivers/net/wireless/ath/ath9k/main.c:1774:3: error: implicit declaration of function 'ath9k_htc_beacon_config' [-Werror=implicit-function-declaration]
      ath9k_htc_beacon_config(priv, vif);
      ^~~~~~~~~~~~~~~~~~~~~~~
>> drivers/net/wireless/ath/ath9k/main.c:1774:27: error: 'priv' undeclared (first use in this function)
      ath9k_htc_beacon_config(priv, vif);
                              ^~~~
   drivers/net/wireless/ath/ath9k/main.c:1774:27: note: each undeclared identifier is reported only once for each function it appears in
   cc1: some warnings being treated as errors

vim +/ath9k_htc_beacon_config +1774 drivers/net/wireless/ath/ath9k/main.c

  1768	
  1769		ath9k_ps_wakeup(sc);
  1770		mutex_lock(&sc->mutex);
  1771	
  1772		/* adjust beacon timers */
  1773		if (changed && BSS_CHANGED_BEACON_INFO)
> 1774			ath9k_htc_beacon_config(priv, vif);
  1775	
  1776		if (changed & BSS_CHANGED_ASSOC) {
  1777			ath_dbg(common, CONFIG, "BSSID %pM Changed ASSOC %d\n",

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 28726 bytes --]

^ permalink raw reply

* Re: [RFC-PATCH] ath9k_htc: Adjust beacon timers for Power Save
From: Gucea Doru @ 2017-02-15 19:03 UTC (permalink / raw)
  To: Kalle Valo
  Cc: linux-wireless, ath9k_htc_fw, Andra Paraschiv, Costin Raiciu,
	Dragos N
In-Reply-To: <87r32z968n.fsf@purkki.adurom.net>

On Wed, Feb 15, 2017 at 11:02 AM, Kalle Valo <kvalo@codeaurora.org> wrote:
> Doru <gucea.doru@gmail.com> writes:
>
>> From: Doru Gucea <gucea.doru@gmail.com>
>>
>> Each time we receive a beacon we need to adjust the hardware
>> timers for next DTIM and next TBTT.
>>
>> Before this commit, the Power Save behaviour was incorrect.
>> The scenario was:
>> - STA receives a beacon from AP with TIM unset;
>> - mac80211 layers puts the chip to sleep;
>> - chip is woken up by mac80211's software timer reponsible for
>> beacon miss after 7 * beacon_interval period.
>>
>> Normally the chip should sleep at most DTIM period. This commit
>> configures hardware timers for waking up the chip correctly.
>>
>> More details on the wiki:
>> https://github.com/doru91/linux-stable/wiki/Single-Interface-Power-Save
>>
>> Signed-off-by: Doru Gucea <gucea.doru@gmail.com>
>> ---
>>  drivers/net/wireless/ath/ath9k/htc_drv_main.c | 4 ++++
>>  net/mac80211/mlme.c                           | 6 ++++++
>>  2 files changed, 10 insertions(+)
>
> [...]
>
>> --- a/net/mac80211/mlme.c
>> +++ b/net/mac80211/mlme.c
>> @@ -3536,6 +3536,12 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
>>                       sdata->vif.bss_conf.sync_dtim_count = 0;
>>       }
>>
>> +     /* trigger hardware timers adjustment
>> +      * this needs to be done before beacon filtering
>> +      */
>> +     changed |= BSS_CHANGED_BEACON_INFO;
>> +     ieee80211_bss_info_change_notify(sdata, changed);
>
> You shouldn't mix driver and mac80211 changes in the same patch, I
> suspect Johannes didn't even notice this change because of that. Create
> a new patchset with two patches, one for ath9k and another for mac80211.

Thanks, I've just sent two patches as you suggested.

>
> --
> Kalle Valo

^ permalink raw reply

* [PATCH 2/2] ath9k_htc: Adjust beacon timers for power save
From: Doru @ 2017-02-15 19:01 UTC (permalink / raw)
  To: linux-wireless, andra.paraschiv7, costin.raiciu, dragos.niculescu
  Cc: Doru Gucea

From: Doru Gucea <gucea.doru@gmail.com>

Each time we receive a beacon we need to adjust the hardware
timers for next DTIM and next TBTT.

Before this commit, the Power Save behaviour was incorrect.
The scenario was:
- STA receives a beacon from AP with TIM unset;
- mac80211 layers puts the chip to sleep;
- chip is woken up by mac80211's software timer reponsible for
beacon miss after 7 * beacon_interval period.

Normally the chip should sleep at most DTIM period. This commit
configures hardware timers for waking up the chip correctly.

More details on the wiki:
https://github.com/doru91/linux-stable/wiki/Single-Interface-Power-Save

Signed-off-by: Doru Gucea <gucea.doru@gmail.com>
---
 drivers/net/wireless/ath/ath9k/main.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index c27143b..d2934e1 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1749,6 +1749,10 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
 	ath9k_ps_wakeup(sc);
 	mutex_lock(&sc->mutex);
 
+	/* adjust beacon timers */
+	if (changed && BSS_CHANGED_BEACON_INFO)
+		ath9k_htc_beacon_config(priv, vif);
+
 	if (changed & BSS_CHANGED_ASSOC) {
 		ath_dbg(common, CONFIG, "BSSID %pM Changed ASSOC %d\n",
 			bss_conf->bssid, bss_conf->assoc);
-- 
1.9.1

^ permalink raw reply related

* [PATCH 1/2] mac80211: Update the driver with beacon info constantly
From: Doru @ 2017-02-15 19:01 UTC (permalink / raw)
  To: linux-wireless, andra.paraschiv7, costin.raiciu, dragos.niculescu
  Cc: Doru Gucea

From: Doru Gucea <gucea.doru@gmail.com>

Once the mac80211 layer receives a beacon, it should send a notification
to the driver. This will allow finer timining control in case of drivers
that need a correct estimation for the arrival time of a beacon.

Signed-off-by: Doru Gucea <gucea.doru@gmail.com>
---
 net/mac80211/mlme.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index cd7e55e..0b8eed5 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3536,6 +3536,12 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 			sdata->vif.bss_conf.sync_dtim_count = 0;
 	}
 
+	/* trigger hardware timers adjustment
+	 * this needs to be done before beacon filtering
+	*/
+	changed |= BSS_CHANGED_BEACON_INFO;
+	ieee80211_bss_info_change_notify(sata, changed);
+
 	if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
 		return;
 	ifmgd->beacon_crc = ncrc;
-- 
1.9.1

^ permalink raw reply related

* Re: [PATCH] average: change to declare precision, not factor
From: David Miller @ 2017-02-15 17:54 UTC (permalink / raw)
  To: johannes
  Cc: linux-wireless, netdev, mst, jasowang, virtualization,
	mareklindner, sw, a, sgruszka, johannes.berg
In-Reply-To: <20170215084926.29482-1-johannes@sipsolutions.net>

From: Johannes Berg <johannes@sipsolutions.net>
Date: Wed, 15 Feb 2017 09:49:26 +0100

> From: Johannes Berg <johannes.berg@intel.com>
> 
> Declaring the factor is counter-intuitive, and people are prone
> to using small(-ish) values even when that makes no sense.
> 
> Change the DECLARE_EWMA() macro to take the fractional precision,
> in bits, rather than a factor, and update all users.
> 
> While at it, add some more documentation.
> 
> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
> ---
> Unless I hear any objections, I will take this through my tree.

Acked-by: David S. Miller <davem@davemloft.net>

^ permalink raw reply

* Re: [PATCH] mac80211:  allow overriding station bandwidth.
From: Johannes Berg @ 2017-02-15 16:05 UTC (permalink / raw)
  To: Ben Greear, linux-wireless
In-Reply-To: <58A46F91.6090707@candelatech.com>


> Likely for some time remote third-party peers will not update with
> your patches to advertise the proper IEs, even if the local system
> does?

I think they ought to start doing that pretty soon.

> Either way, I suspect that 4x4 VHT80 may perform quite well vs 2x2
> VHT160 if there is any sort of interference on the secondary 80Mhz
> band...

True. Rate scaling should probably pick that over 160 MHz bandwidth, if
supported. But if, for example, VHT opmode notification restricts
current operation to 2x2, rate scaling should still pick 160 MHz.

> But, I can just remove the 'why' part of the description entirely if
> you prefer?

Yes, I just don't want to give people the wrong idea about this :)

johannes

^ permalink raw reply

* Re: [PATCH] mac80211:  allow overriding station bandwidth.
From: Ben Greear @ 2017-02-15 15:11 UTC (permalink / raw)
  To: Johannes Berg, linux-wireless
In-Reply-To: <1487144841.4026.1.camel@sipsolutions.net>

On 02/14/2017 11:47 PM, Johannes Berg wrote:
> On Tue, 2017-02-14 at 13:01 -0800, greearb@candelatech.com wrote:
>> From: Ben Greear <greearb@candelatech.com>
>>
>> This allows one to disable VHT160 (or 80+80) on hardware
>> that might otherwise try to use it.  One potential reason
>> to do this is that at least some 160Mhz/80+80 hardware can
>> only do 2x2 at 160Mhz, but can do 4x4 at 80Mhz.  And, due to
>> driver and firmware issues, it may effectively be limitted
>> to 1x1 at 160Mhz for some NICs.
>
> I think the feature is acceptable and don't mind adding that (though
> perhaps we should start thinking about making some of these things
> debug-only features), but I think the description of why you might want
> to do this is misleading - those issues you're describing really should
> be solved differently, and I posted the basis for that yesterday.

Likely for some time remote third-party peers will not update with your patches
to advertise the proper IEs, even if the local system does?

Either way, I suspect that 4x4 VHT80 may perform quite well vs 2x2 VHT160 if
there is any sort of interference on the secondary 80Mhz band...

But, I can just remove the 'why' part of the description entirely if you prefer?

Thanks,
Ben

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com

^ permalink raw reply

* Re: wireless driver crashing frequently
From: Arend Van Spriel @ 2017-02-15 14:42 UTC (permalink / raw)
  To: ravin goyal; +Cc: linux-wireless
In-Reply-To: <CANU0Mn01mQoWfxvWK_jLRyM9MZwDR7Baeah6ZkJ6pNhxB=YeKQ@mail.gmail.com>



On 15-2-2017 11:55, ravin goyal wrote:
> okay thanks for the help.

No intent to blow you off. I just do not support that driver nor anyone
else on this list.

Regards,
Arend

> regards
> ravin
> 
> On 15 February 2017 at 16:20, Arend Van Spriel
> <arend.vanspriel@broadcom.com> wrote:
>>
>>
>> On 15-2-2017 11:38, ravin goyal wrote:
>>> that is what I have found on my banana pi board running raspbian lite
>>> 3.4.112-sun8i.
>>> removing bcmdhd results in removing my wlan0 interface from the
>>> list(iwconfig/ifconfig/ip).
>>
>> Ok. If it is raspbian that choose to include bcmdhd in their distro I
>> would suggest to file the bug there [1].
>>
>> Regards,
>> Arend
>>
>> [1] https://www.raspbian.org/RaspbianBugs

^ permalink raw reply

* [mac80211-next:vht-he 11/14] net/mac80211/vht.c:307:4: error: expected ')' before 'break'
From: kbuild test robot @ 2017-02-15 14:33 UTC (permalink / raw)
  To: Johannes Berg; +Cc: kbuild-all, linux-wireless

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

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git vht-he
head:   860f13022f1783b9ac8e5ce4aed06ac9dbf110cb
commit: 5df804200a23280b5c7955996897a5a235a96cb7 [11/14] mac80211: copy VHT EXT NSS BW Support/Capable data to station
config: x86_64-randconfig-x000-201707 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        git checkout 5df804200a23280b5c7955996897a5a235a96cb7
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All errors (new ones prefixed by >>):

   net/mac80211/vht.c: In function 'ieee80211_vht_cap_ie_to_sta_vht_cap':
>> net/mac80211/vht.c:307:4: error: expected ')' before 'break'
       break;
       ^~~~~
>> net/mac80211/vht.c:316:2: error: expected expression before '}' token
     }
     ^

vim +307 net/mac80211/vht.c

   301			break;
   302		default:
   303			sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80;
   304	
   305			if (!(vht_cap->vht_mcs.tx_highest &
   306					cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE))
 > 307				break;
   308	
   309			/*
   310			 * If this is non-zero, then it does support 160 MHz after all,
   311			 * in one form or the other. We don't distinguish here (or even
   312			 * above) between 160 and 80+80 yet.
   313			 */
   314			if (cap_info & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK)
   315				sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160;
 > 316		}
   317	
   318		sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta);
   319	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 26999 bytes --]

^ permalink raw reply

* [mac80211-next:vht-he 11/14] net/mac80211/vht.c:575:0: error: unterminated argument list invoking macro "if"
From: kbuild test robot @ 2017-02-15 14:28 UTC (permalink / raw)
  To: Johannes Berg; +Cc: kbuild-all, linux-wireless

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

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git vht-he
head:   860f13022f1783b9ac8e5ce4aed06ac9dbf110cb
commit: 5df804200a23280b5c7955996897a5a235a96cb7 [11/14] mac80211: copy VHT EXT NSS BW Support/Capable data to station
config: i386-randconfig-x076-201707 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        git checkout 5df804200a23280b5c7955996897a5a235a96cb7
        # save the attached .config to linux build tree
        make ARCH=i386 

All error/warnings (new ones prefixed by >>):

   net/mac80211/vht.c: In function 'ieee80211_vht_cap_ie_to_sta_vht_cap':
>> net/mac80211/vht.c:575:0: error: unterminated argument list invoking macro "if"
    }
    
>> net/mac80211/vht.c:305:3: error: expected '(' at end of input
      if (!(vht_cap->vht_mcs.tx_highest &
      ^~
>> net/mac80211/vht.c:305:3: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
   net/mac80211/vht.c:575:0: note: ...this statement, but the latter is misleadingly indented as if it is guarded by the 'if'
    }
    
>> net/mac80211/vht.c:305:3: error: expected declaration or statement at end of input
      if (!(vht_cap->vht_mcs.tx_highest &
      ^~
>> net/mac80211/vht.c:305:3: error: expected declaration or statement at end of input

vim +/if +575 net/mac80211/vht.c

b119ad6e Lorenzo Bianconi 2015-08-06  569  		case IEEE80211_VHT_MCS_NOT_SUPPORTED:
b119ad6e Lorenzo Bianconi 2015-08-06  570  		default:
b119ad6e Lorenzo Bianconi 2015-08-06  571  			vht_mask[i] = 0;
b119ad6e Lorenzo Bianconi 2015-08-06  572  			break;
b119ad6e Lorenzo Bianconi 2015-08-06  573  		}
b119ad6e Lorenzo Bianconi 2015-08-06  574  	}
b119ad6e Lorenzo Bianconi 2015-08-06 @575  }

:::::: The code at line 575 was first introduced by commit
:::::: b119ad6e726cc805f739f8f6843b9de4df1f895e mac80211: add rate mask logic for vht rates

:::::: TO: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
:::::: CC: Johannes Berg <johannes.berg@intel.com>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 34888 bytes --]

^ permalink raw reply

* [RFC v2 5/5] cfg80211: add support for HE MCSs
From: Johannes Berg @ 2017-02-15 14:02 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20170215140256.19455-1-johannes@sipsolutions.net>

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

Add support for the HE MCSs in cfg80211 and also add userspace
API to nl80211 to send rate information out.

The bandwidth calculation is somewhat approximate to avoid all
the big tables that are otherwise necessary.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 include/net/cfg80211.h       | 15 +++++++--
 include/uapi/linux/nl80211.h | 42 +++++++++++++++++++++++
 net/wireless/nl80211.c       | 16 +++++++++
 net/wireless/util.c          | 80 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 151 insertions(+), 2 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 86c12f85fb53..48af8d6b4fc7 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -986,12 +986,14 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
  * @RATE_INFO_FLAGS_VHT_MCS: mcs field filled with VHT MCS
  * @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval
  * @RATE_INFO_FLAGS_60G: 60GHz MCS
+ * @RATE_INFO_FLAGS_HE_MCS: HE MCS information
  */
 enum rate_info_flags {
 	RATE_INFO_FLAGS_MCS			= BIT(0),
 	RATE_INFO_FLAGS_VHT_MCS			= BIT(1),
 	RATE_INFO_FLAGS_SHORT_GI		= BIT(2),
 	RATE_INFO_FLAGS_60G			= BIT(3),
+	RATE_INFO_FLAGS_HE_MCS			= BIT(4),
 };
 
 /**
@@ -1005,6 +1007,7 @@ enum rate_info_flags {
  * @RATE_INFO_BW_40: 40 MHz bandwidth
  * @RATE_INFO_BW_80: 80 MHz bandwidth
  * @RATE_INFO_BW_160: 160 MHz bandwidth
+ * @RATE_INFO_BW_HE_RU: bandwidth determined by HE RU allocation
  */
 enum rate_info_bw {
 	RATE_INFO_BW_5,
@@ -1013,6 +1016,7 @@ enum rate_info_bw {
 	RATE_INFO_BW_40,
 	RATE_INFO_BW_80,
 	RATE_INFO_BW_160,
+	RATE_INFO_BW_HE_RU,
 };
 
 /**
@@ -1021,10 +1025,14 @@ enum rate_info_bw {
  * Information about a receiving or transmitting bitrate
  *
  * @flags: bitflag of flags from &enum rate_info_flags
- * @mcs: mcs index if struct describes a 802.11n bitrate
+ * @mcs: mcs index if struct describes an HT/VHT/HE rate
  * @legacy: bitrate in 100kbit/s for 802.11abg
- * @nss: number of streams (VHT only)
+ * @nss: number of streams (VHT & HE only)
  * @bw: bandwidth (from &enum rate_info_bw)
+ * @he_gi: HE guard interval (from &enum nl80211_he_gi)
+ * @he_dcm: HE DCM value
+ * @he_ru_alloc: HE RU allocation (from &enum nl80211_he_ru_alloc,
+ *	only valid if bw is %RATE_INFO_BW_HE_RU)
  */
 struct rate_info {
 	u8 flags;
@@ -1032,6 +1040,9 @@ struct rate_info {
 	u16 legacy;
 	u8 nss;
 	u8 bw;
+	u8 he_gi;
+	u8 he_dcm;
+	u8 he_ru_alloc;
 };
 
 /**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 9a499b15cfbc..f2b577dbaca0 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2598,6 +2598,36 @@ struct nl80211_sta_flag_update {
 } __attribute__((packed));
 
 /**
+ * enum nl80211_he_gi - HE guard interval
+ * @NL80211_RATE_INFO_HE_GI_0_8: 0.8 usec
+ * @NL80211_RATE_INFO_HE_GI_1_6: 1.6 usec
+ * @NL80211_RATE_INFO_HE_GI_3_2: 3.2 usec
+ */
+enum nl80211_he_gi {
+	NL80211_RATE_INFO_HE_GI_0_8,
+	NL80211_RATE_INFO_HE_GI_1_6,
+	NL80211_RATE_INFO_HE_GI_3_2,
+};
+
+/**
+ * @enum nl80211_he_ru_alloc - HE RU allocation values
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_26: 26-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_52: 52-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_106: 106-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_242: 242-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_484: 484-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_969: 969-tone RU allocation
+ */
+enum nl80211_he_ru_alloc {
+	NL80211_RATE_INFO_HE_RU_ALLOC_26,
+	NL80211_RATE_INFO_HE_RU_ALLOC_52,
+	NL80211_RATE_INFO_HE_RU_ALLOC_106,
+	NL80211_RATE_INFO_HE_RU_ALLOC_242,
+	NL80211_RATE_INFO_HE_RU_ALLOC_484,
+	NL80211_RATE_INFO_HE_RU_ALLOC_969,
+};
+
+/**
  * enum nl80211_rate_info - bitrate information
  *
  * These attribute types are used with %NL80211_STA_INFO_TXRATE
@@ -2629,6 +2659,13 @@ struct nl80211_sta_flag_update {
  * @NL80211_RATE_INFO_5_MHZ_WIDTH: 5 MHz width - note that this is
  *	a legacy rate and will be reported as the actual bitrate, i.e.
  *	a quarter of the base (20 MHz) rate
+ * @NL80211_RATE_INFO_HE_MCS: HE MCS index (u8, 0-11)
+ * @NL80211_RATE_INFO_HE_NSS: HE NSS value (u8, 1-8)
+ * @NL80211_RATE_INFO_HE_GI: HE guard interval identifier
+ *	(u8, see &enum nl80211_he_gi)
+ * @NL80211_RATE_INFO_HE_DCM: HE DCM value (u8, 0/1)
+ * @NL80211_RATE_INFO_RU_ALLOC: HE RU allocation, if not present then
+ *	non-OFDMA was used (u8, see &enum nl80211_he_ru_alloc)
  * @__NL80211_RATE_INFO_AFTER_LAST: internal use
  */
 enum nl80211_rate_info {
@@ -2645,6 +2682,11 @@ enum nl80211_rate_info {
 	NL80211_RATE_INFO_160_MHZ_WIDTH,
 	NL80211_RATE_INFO_10_MHZ_WIDTH,
 	NL80211_RATE_INFO_5_MHZ_WIDTH,
+	NL80211_RATE_INFO_HE_MCS,
+	NL80211_RATE_INFO_HE_NSS,
+	NL80211_RATE_INFO_HE_GI,
+	NL80211_RATE_INFO_HE_DCM,
+	NL80211_RATE_INFO_HE_RU_ALLOC,
 
 	/* keep last */
 	__NL80211_RATE_INFO_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d516527fcb8e..e779733143b8 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -4204,6 +4204,9 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
 	case RATE_INFO_BW_160:
 		rate_flg = NL80211_RATE_INFO_160_MHZ_WIDTH;
 		break;
+	case RATE_INFO_BW_HE_RU:
+		rate_flg = 0;
+		WARN_ON(!(info->flags & RATE_INFO_FLAGS_HE_MCS));
 	}
 
 	if (rate_flg && nla_put_flag(msg, rate_flg))
@@ -4223,6 +4226,19 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
 		if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
 		    nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
 			return false;
+	} else if (info->flags & RATE_INFO_FLAGS_HE_MCS) {
+		if (nla_put_u8(msg, NL80211_RATE_INFO_HE_MCS, info->mcs))
+			return false;
+		if (nla_put_u8(msg, NL80211_RATE_INFO_HE_NSS, info->nss))
+			return false;
+		if (nla_put_u8(msg, NL80211_RATE_INFO_HE_GI, info->he_gi))
+			return false;
+		if (nla_put_u8(msg, NL80211_RATE_INFO_HE_DCM, info->he_dcm))
+			return false;
+		if (info->bw == RATE_INFO_BW_HE_RU &&
+		    nla_put_u8(msg, NL80211_RATE_INFO_HE_RU_ALLOC,
+			       info->he_ru_alloc))
+			return false;
 	}
 
 	nla_nest_end(msg, rate);
diff --git a/net/wireless/util.c b/net/wireless/util.c
index bc676d9b7e80..967fc20e10f2 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1258,6 +1258,84 @@ static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate)
 	return (bitrate + 50000) / 100000;
 }
 
+static u32 cfg80211_calculate_bitrate_he(struct rate_info *rate)
+{
+#define SCALE 2048
+	u16 mcs_divisors[12] = {
+		34133, /* 16.666666... */
+		17067, /*  8.333333... */
+		11378, /*  5.555555... */
+		 8533, /*  4.166666... */
+		 5689, /*  2.777777... */
+		 4267, /*  2.083333... */
+		 3923, /*  1.851851... */
+		 3413, /*  1.666666... */
+		 2844, /*  1.388888... */
+		 2560, /*  1.250000... */
+		 2276, /*  1.111111... */
+		 2048, /*  1.000000... */
+	};
+	u32 rates_160M[3] = { 960777777, 907400000, 816666666 };
+	u32 rates_969[3] =  { 480388888, 453700000, 408333333 };
+	u32 rates_484[3] =  { 229411111, 216666666, 195000000 };
+	u32 rates_242[3] =  { 114711111, 108333333,  97500000 };
+	u32 rates_106[3] =  {  40000000,  37777777,  34000000 };
+	u32 rates_52[3]  =  {  18820000,  17777777,  16000000 };
+	u32 rates_26[3]  =  {   9411111,   8888888,   8000000 };
+	u64 tmp;
+	u32 result;
+
+	if (WARN_ON_ONCE(rate->mcs > 11))
+		return 0;
+
+	if (WARN_ON_ONCE(rate->he_gi > NL80211_RATE_INFO_HE_GI_3_2))
+		return 0;
+	if (WARN_ON_ONCE(rate->he_ru_alloc > NL80211_RATE_INFO_HE_RU_ALLOC_969))
+		return 0;
+	if (WARN_ON_ONCE(rate->nss < 1 || rate->nss > 8))
+		return 0;
+
+	if (rate->bw == RATE_INFO_BW_160)
+		result = rates_160M[rate->he_gi];
+	else if (rate->bw == RATE_INFO_BW_80 ||
+		 (rate->bw == RATE_INFO_BW_HE_RU &&
+		  rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_969))
+		result = rates_969[rate->he_gi];
+	else if (rate->bw == RATE_INFO_BW_40 ||
+		 (rate->bw == RATE_INFO_BW_HE_RU &&
+		  rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_484))
+		result = rates_484[rate->he_gi];
+	else if (rate->bw == RATE_INFO_BW_20 ||
+		 (rate->bw == RATE_INFO_BW_HE_RU &&
+		  rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_242))
+		result = rates_242[rate->he_gi];
+	else if (rate->bw == RATE_INFO_BW_HE_RU &&
+		 rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_106)
+		result = rates_106[rate->he_gi];
+	else if (rate->bw == RATE_INFO_BW_HE_RU &&
+		 rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_52)
+		result = rates_52[rate->he_gi];
+	else if (rate->bw == RATE_INFO_BW_HE_RU &&
+		 rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_26)
+		result = rates_26[rate->he_gi];
+	else if (WARN(1, "invalid HE MCS: bw:%d, ru:%d\n",
+		      rate->bw, rate->he_ru_alloc))
+		result = 0;
+
+	/* now scale to the appropriate MCS */
+	tmp = result;
+	tmp *= SCALE;
+	do_div(tmp, mcs_divisors[rate->mcs]);
+	result = tmp;
+
+	/* and take MCS, DCM into account */
+	result = (result / 8) * rate->nss;
+	if (rate->he_dcm)
+		result /= 2;
+
+	return result;
+}
+
 u32 cfg80211_calculate_bitrate(struct rate_info *rate)
 {
 	if (rate->flags & RATE_INFO_FLAGS_MCS)
@@ -1266,6 +1344,8 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate)
 		return cfg80211_calculate_bitrate_60g(rate);
 	if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)
 		return cfg80211_calculate_bitrate_vht(rate);
+	if (rate->flags & RATE_INFO_FLAGS_HE_MCS)
+		return cfg80211_calculate_bitrate_he(rate);
 
 	return rate->legacy;
 }
-- 
2.9.3

^ permalink raw reply related

* [RFC v2 4/5] mac80211: copy VHT EXT NSS BW Support/Capable data to station
From: Johannes Berg @ 2017-02-15 14:02 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20170215140256.19455-1-johannes@sipsolutions.net>

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

When taking VHT capabilities for a station, copy the new
fields if we support them as a transmitter. Also adjust
the maximum bandwidth the station supports appropriately.

Also, since it was missing, copy tx_highest and rx_highest.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/mac80211/vht.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index 19ec2189d3ac..2d1e72747ab8 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -231,6 +231,13 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
 	memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs,
 	       sizeof(struct ieee80211_vht_mcs_info));
 
+	/* copy EXT_NSS_BW Support value or remove the capability */
+	if (ieee80211_hw_check(&sdata->local->hw, SUPPORTS_VHT_EXT_NSS_BW))
+		vht_cap->cap |= (cap_info & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK);
+	else
+		vht_cap->vht_mcs.tx_highest &=
+			~cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE);
+
 	/* but also restrict MCSes */
 	for (i = 0; i < 8; i++) {
 		u16 own_rx, own_tx, peer_rx, peer_tx;
@@ -294,6 +301,18 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
 		break;
 	default:
 		sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80;
+
+		if (!(vht_cap->vht_mcs.tx_highest &
+				cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE))
+			break;
+
+		/*
+		 * If this is non-zero, then it does support 160 MHz after all,
+		 * in one form or the other. We don't distinguish here (or even
+		 * above) between 160 and 80+80 yet.
+		 */
+		if (cap_info & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK)
+			sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160;
 	}
 
 	sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta);
-- 
2.9.3

^ permalink raw reply related

* [RFC v2 3/5] mac80211: add ability to parse CCFS2
From: Johannes Berg @ 2017-02-15 14:02 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20170215140256.19455-1-johannes@sipsolutions.net>

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

With newer VHT implementations, it's necessary to look at the
HT operation's CCFS2 field to identify the actual bandwidth
used.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/mac80211/ibss.c        |  4 +++-
 net/mac80211/ieee80211_i.h |  4 +++-
 net/mac80211/mesh.c        |  4 +++-
 net/mac80211/mlme.c        |  3 ++-
 net/mac80211/spectmgmt.c   |  5 ++++-
 net/mac80211/util.c        | 48 ++++++++++++++++++++++++++++++----------------
 6 files changed, 47 insertions(+), 21 deletions(-)

diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 98999d3d5262..a5c0c5818da5 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -1065,7 +1065,9 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata,
 			struct ieee80211_vht_cap cap_ie;
 			struct ieee80211_sta_vht_cap cap = sta->sta.vht_cap;
 
-			ieee80211_chandef_vht_oper(elems->vht_operation,
+			ieee80211_chandef_vht_oper(&local->hw,
+						   elems->vht_operation,
+						   elems->ht_operation,
 						   &chandef);
 			memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie));
 			ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 4047fc528977..b0690c2d7f7d 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2074,7 +2074,9 @@ u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo);
 /* channel management */
 bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
 			       struct cfg80211_chan_def *chandef);
-bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper,
+bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw,
+				const struct ieee80211_vht_operation *oper,
+				const struct ieee80211_ht_operation *htop,
 				struct cfg80211_chan_def *chandef);
 u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c);
 
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index c28b0af9c1f2..1b60b4350517 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -92,7 +92,9 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
 	cfg80211_chandef_create(&sta_chan_def, sdata->vif.bss_conf.chandef.chan,
 				NL80211_CHAN_NO_HT);
 	ieee80211_chandef_ht_oper(ie->ht_operation, &sta_chan_def);
-	ieee80211_chandef_vht_oper(ie->vht_operation, &sta_chan_def);
+	ieee80211_chandef_vht_oper(&sdata->local->hw,
+				   ie->vht_operation, ie->ht_operation,
+				   &sta_chan_def);
 
 	if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef,
 					 &sta_chan_def))
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 23986934d7af..2ff3040ebb09 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -213,7 +213,8 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
 	}
 
 	vht_chandef = *chandef;
-	if (!ieee80211_chandef_vht_oper(vht_oper, &vht_chandef)) {
+	if (!ieee80211_chandef_vht_oper(&sdata->local->hw,
+					vht_oper, ht_oper, &vht_chandef)) {
 		if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
 			sdata_info(sdata,
 				   "AP VHT information is invalid, disable VHT\n");
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index 0782e486fe89..5a013b53b4f0 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -138,6 +138,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
 				wide_bw_chansw_ie->new_center_freq_seg1,
 			/* .basic_mcs_set doesn't matter */
 		};
+		struct ieee80211_ht_operation ht_oper = {};
 
 		/* default, for the case of IEEE80211_VHT_CHANWIDTH_USE_HT,
 		 * to the previously parsed chandef
@@ -145,7 +146,9 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
 		new_vht_chandef = csa_ie->chandef;
 
 		/* ignore if parsing fails */
-		if (!ieee80211_chandef_vht_oper(&vht_oper, &new_vht_chandef))
+		if (!ieee80211_chandef_vht_oper(&sdata->local->hw,
+						&vht_oper, &ht_oper,
+						&new_vht_chandef))
 			new_vht_chandef.chan = NULL;
 
 		if (sta_flags & IEEE80211_STA_DISABLE_80P80MHZ &&
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 7a37ce78bb38..152aae54b67f 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2482,49 +2482,65 @@ bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
 	return true;
 }
 
-bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper,
+bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw,
+				const struct ieee80211_vht_operation *oper,
+				const struct ieee80211_ht_operation *htop,
 				struct cfg80211_chan_def *chandef)
 {
 	struct cfg80211_chan_def new = *chandef;
-	int cf1, cf2;
+	int cf0, cf1;
+	int ccfs0, ccfs1, ccfs2;
+	int ccf0, ccf1;
 
-	if (!oper)
+	if (!oper || !htop)
 		return false;
 
-	cf1 = ieee80211_channel_to_frequency(oper->center_freq_seg0_idx,
-					     chandef->chan->band);
-	cf2 = ieee80211_channel_to_frequency(oper->center_freq_seg1_idx,
-					     chandef->chan->band);
+	ccfs0 = oper->center_freq_seg0_idx;
+	ccfs1 = oper->center_freq_seg1_idx;
+	ccfs2 = (le16_to_cpu(htop->operation_mode) &
+				IEEE80211_HT_OP_MODE_CCFS2_MASK)
+			>> IEEE80211_HT_OP_MODE_CCFS2_SHIFT;
+
+	/* when parsing (and we know how to) CCFS1 and CCFS2 are equivalent */
+	ccf0 = ccfs0;
+	ccf1 = ccfs1;
+	if (!ccfs1 && ieee80211_hw_check(hw, SUPPORTS_VHT_EXT_NSS_BW))
+		ccf1 = ccfs2;
+
+	cf0 = ieee80211_channel_to_frequency(ccf0, chandef->chan->band);
+	cf1 = ieee80211_channel_to_frequency(ccf1, chandef->chan->band);
 
 	switch (oper->chan_width) {
 	case IEEE80211_VHT_CHANWIDTH_USE_HT:
+		/* just use HT information directly */
 		break;
 	case IEEE80211_VHT_CHANWIDTH_80MHZ:
 		new.width = NL80211_CHAN_WIDTH_80;
-		new.center_freq1 = cf1;
+		new.center_freq1 = cf0;
 		/* If needed, adjust based on the newer interop workaround. */
-		if (oper->center_freq_seg1_idx) {
+		if (ccf1) {
 			unsigned int diff;
 
-			diff = abs(oper->center_freq_seg1_idx -
-				   oper->center_freq_seg0_idx);
+			diff = abs(ccf1 - ccf0);
 			if (diff == 8) {
 				new.width = NL80211_CHAN_WIDTH_160;
-				new.center_freq1 = cf2;
+				new.center_freq1 = cf1;
 			} else if (diff > 8) {
 				new.width = NL80211_CHAN_WIDTH_80P80;
-				new.center_freq2 = cf2;
+				new.center_freq2 = cf1;
 			}
 		}
 		break;
 	case IEEE80211_VHT_CHANWIDTH_160MHZ:
+		/* deprecated encoding */
 		new.width = NL80211_CHAN_WIDTH_160;
-		new.center_freq1 = cf1;
+		new.center_freq1 = cf0;
 		break;
 	case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
+		/* deprecated encoding */
 		new.width = NL80211_CHAN_WIDTH_80P80;
-		new.center_freq1 = cf1;
-		new.center_freq2 = cf2;
+		new.center_freq1 = cf0;
+		new.center_freq2 = cf1;
 		break;
 	default:
 		return false;
-- 
2.9.3

^ permalink raw reply related

* [RFC v2 1/5] ieee80211: add new VHT capability fields/parsing
From: Johannes Berg @ 2017-02-15 14:02 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg

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

IEEE 802.11-2016 extended the VHT capability fields to allow
indicating the number of spatial streams depending on the
actually used bandwidth, add support for decoding this.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 include/linux/ieee80211.h |  35 ++++++++++++++-
 net/wireless/util.c       | 107 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 140 insertions(+), 2 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 4a7200c6c9ea..aed8faaacc38 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1457,13 +1457,16 @@ struct ieee80211_ht_operation {
  *	STA can receive. Rate expressed in units of 1 Mbps.
  *	If this field is 0 this value should not be used to
  *	consider the highest RX data rate supported.
- *	The top 3 bits of this field are reserved.
+ *	The top 3 bits of this field indicate the Maximum NSTS,total
+ *	(a beamformee capability.)
  * @tx_mcs_map: TX MCS map 2 bits for each stream, total 8 streams
  * @tx_highest: Indicates highest long GI VHT PPDU data rate
  *	STA can transmit. Rate expressed in units of 1 Mbps.
  *	If this field is 0 this value should not be used to
  *	consider the highest TX data rate supported.
- *	The top 3 bits of this field are reserved.
+ *	The top 2 bits of this field are reserved, the
+ *	3rd bit from the top indiciates VHT Extended NSS BW
+ *	Capability.
  */
 struct ieee80211_vht_mcs_info {
 	__le16 rx_mcs_map;
@@ -1472,6 +1475,13 @@ struct ieee80211_vht_mcs_info {
 	__le16 tx_highest;
 } __packed;
 
+/* for rx_highest */
+#define IEEE80211_VHT_MAX_NSTS_TOTAL_SHIFT	13
+#define IEEE80211_VHT_MAX_NSTS_TOTAL_MASK	(7 << IEEE80211_VHT_MAX_NSTS_TOTAL_SHIFT)
+
+/* for tx_highest */
+#define IEEE80211_VHT_EXT_NSS_BW_CAPABLE	(1 << 13)
+
 /**
  * enum ieee80211_vht_mcs_support - VHT MCS support definitions
  * @IEEE80211_VHT_MCS_SUPPORT_0_7: MCSes 0-7 are supported for the
@@ -1547,6 +1557,7 @@ struct ieee80211_vht_operation {
 #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ		0x00000004
 #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ	0x00000008
 #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK			0x0000000C
+#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_SHIFT			2
 #define IEEE80211_VHT_CAP_RXLDPC				0x00000010
 #define IEEE80211_VHT_CAP_SHORT_GI_80				0x00000020
 #define IEEE80211_VHT_CAP_SHORT_GI_160				0x00000040
@@ -1575,6 +1586,26 @@ struct ieee80211_vht_operation {
 #define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB	0x0c000000
 #define IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN			0x10000000
 #define IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN			0x20000000
+#define IEEE80211_VHT_CAP_EXT_NSS_BW_SHIFT			30
+#define IEEE80211_VHT_CAP_EXT_NSS_BW_MASK			0xc0000000
+
+/**
+ * ieee80211_get_vht_max_nss - return max NSS for a given bandwidth/MCS
+ * @cap: VHT capabilities of the peer
+ * @bw: bandwidth to use
+ * @mcs: MCS index to use
+ * @ext_nss_bw_capable: indicates whether or not the local transmitter
+ *	(rate scaling algorithm) can deal with the new logic
+ *	(dot11VHTExtendedNSSBWCapable)
+ *
+ * Due to the VHT Extended NSS Bandwidth Support, the maximum NSS can
+ * vary for a given BW/MCS. This function parses the data.
+ *
+ * Note: This function is exported by cfg80211.
+ */
+int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
+			      enum ieee80211_vht_chanwidth bw,
+			      int mcs, bool ext_nss_bw_capable);
 
 /* Authentication algorithms */
 #define WLAN_AUTH_OPEN 0
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 23ee3d66dfe0..bc676d9b7e80 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -8,6 +8,7 @@
 #include <linux/bitops.h>
 #include <linux/etherdevice.h>
 #include <linux/slab.h>
+#include <linux/ieee80211.h>
 #include <net/cfg80211.h>
 #include <net/ip.h>
 #include <net/dsfield.h>
@@ -1874,3 +1875,109 @@ EXPORT_SYMBOL(rfc1042_header);
 const unsigned char bridge_tunnel_header[] __aligned(2) =
 	{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
 EXPORT_SYMBOL(bridge_tunnel_header);
+
+int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
+			      enum ieee80211_vht_chanwidth bw,
+			      int mcs, bool ext_nss_bw_capable)
+{
+	u16 map = le16_to_cpu(cap->supp_mcs.rx_mcs_map);
+	int max_vht_nss = 0;
+	int ext_nss_bw;
+	int supp_width;
+	int i, mcs_encoding;
+
+	if (map == 0xffff)
+		return 0;
+
+	if (WARN_ON(mcs > 9))
+		return 0;
+	if (mcs <= 7)
+		mcs_encoding = 0;
+	else if (mcs == 8)
+		mcs_encoding = 1;
+	else
+		mcs_encoding = 2;
+
+	/* find max_vht_nss for the given MCS */
+	for (i = 7; i >= 0; i--) {
+		int supp = (map >> (2*i)) & 3;
+
+		if (supp == 3)
+			continue;
+
+		if (supp >= mcs_encoding) {
+			max_vht_nss = i;
+			break;
+		}
+	}
+
+	if (!(cap->supp_mcs.tx_mcs_map & cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE)))
+		return max_vht_nss;
+
+	ext_nss_bw = (le32_to_cpu(cap->vht_cap_info) &
+					IEEE80211_VHT_CAP_EXT_NSS_BW_MASK)
+			>> IEEE80211_VHT_CAP_EXT_NSS_BW_SHIFT;
+	supp_width = (le32_to_cpu(cap->vht_cap_info) &
+					IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK)
+			>> IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_SHIFT;
+
+	/* if not capable, treat ext_nss_bw as 0 */
+	if (!ext_nss_bw_capable)
+		ext_nss_bw = 0;
+
+	/* This is invalid */
+	if (supp_width == 3)
+		return 0;
+
+	/* This is an invalid combination so pretend nothing is supported */
+	if (supp_width == 2 && (ext_nss_bw == 1 || ext_nss_bw == 2))
+		return 0;
+
+	/*
+	 * Cover all the special cases according to IEEE 802.11-2016 Table 9-250.
+	 * All other cases are either factor of 1 or not valid/supported.
+	 */
+	switch (bw) {
+	case IEEE80211_VHT_CHANWIDTH_USE_HT:
+	case IEEE80211_VHT_CHANWIDTH_80MHZ:
+		if ((supp_width == 1 || supp_width == 2) &&
+		    ext_nss_bw == 3)
+			return 2 * max_vht_nss;
+		break;
+	case IEEE80211_VHT_CHANWIDTH_160MHZ:
+		if (supp_width == 0 &&
+		    (ext_nss_bw == 1 || ext_nss_bw == 2))
+			return DIV_ROUND_UP(max_vht_nss, 2);
+		if (supp_width == 0 &&
+		    ext_nss_bw == 3)
+			return DIV_ROUND_UP(3 * max_vht_nss, 4);
+		if (supp_width == 1 &&
+		    ext_nss_bw == 3)
+			return 2 * max_vht_nss;
+		break;
+	case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
+		if (supp_width == 0 &&
+		    (ext_nss_bw == 1 || ext_nss_bw == 2))
+			return 0; /* not possible */
+		if (supp_width == 0 &&
+		    ext_nss_bw == 2)
+			return DIV_ROUND_UP(max_vht_nss, 2);
+		if (supp_width == 0 &&
+		    ext_nss_bw == 3)
+			return DIV_ROUND_UP(3 * max_vht_nss, 4);
+		if (supp_width == 1 &&
+		    ext_nss_bw == 0)
+			return 0; /* not possible */
+		if (supp_width == 1 &&
+		    ext_nss_bw == 1)
+			return DIV_ROUND_UP(max_vht_nss, 2);
+		if (supp_width == 1 &&
+		    ext_nss_bw == 2)
+			return DIV_ROUND_UP(3 * max_vht_nss, 4);
+		break;
+	}
+
+	/* not covered or invalid combination received */
+	return max_vht_nss;
+}
+EXPORT_SYMBOL(ieee80211_get_vht_max_nss);
-- 
2.9.3

^ permalink raw reply related

* [RFC v2 2/5] mac80211: introduce capability flags for VHT EXT NSS support
From: Johannes Berg @ 2017-02-15 14:02 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20170215140256.19455-1-johannes@sipsolutions.net>

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

Depending on whether or not rate control supports selecting
rates depending on the bandwidth, we can use VHT extended
NSS support. In essence, this is dot11VHTExtendedNSSBWCapable
from the spec, since depending on that we'll need to parse
the bandwidth.

If needed, also set/clear the VHT Capability Element bit for
this capability so that we don't advertise it erroneously or
don't advertise it when we actually use it.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 include/net/mac80211.h     | 18 ++++++++++++++++
 net/mac80211/debugfs.c     |  1 +
 net/mac80211/ieee80211_i.h |  3 +++
 net/mac80211/main.c        | 52 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 74 insertions(+)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 3edb469a6de1..9017feff1784 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2049,6 +2049,11 @@ struct ieee80211_txq {
  *	The stack will not do fragmentation.
  *	The callback for @set_frag_threshold should be set as well.
  *
+ * @IEEE80211_HW_SUPPORTS_VHT_EXT_NSS_BW: (Hardware) rate control supports VHT
+ *	extended NSS BW (dot11VHTExtendedNSSBWCapable). This flag will be set if
+ *	the selected rate control algorithm sets %RATE_CTRL_CAPA_VHT_EXT_NSS_BW
+ *	but if the rate control is built-in then it must be set by the driver.
+ *
  * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
  */
 enum ieee80211_hw_flags {
@@ -2091,6 +2096,7 @@ enum ieee80211_hw_flags {
 	IEEE80211_HW_TX_FRAG_LIST,
 	IEEE80211_HW_REPORTS_LOW_ACK,
 	IEEE80211_HW_SUPPORTS_TX_FRAG,
+	IEEE80211_HW_SUPPORTS_VHT_EXT_NSS_BW,
 
 	/* keep last, obviously */
 	NUM_IEEE80211_HW_FLAGS
@@ -5464,7 +5470,19 @@ struct ieee80211_tx_rate_control {
 	bool bss;
 };
 
+/**
+ * enum rate_control_capabilities - rate control capabilities
+ */
+enum rate_control_capabilities {
+	/**
+	 * @RATE_CTRL_CAPA_VHT_EXT_NSS_BW:
+	 *	support for extended NSS BW support (dot11VHTExtendedNSSCapable)
+	 */
+	RATE_CTRL_CAPA_VHT_EXT_NSS_BW = BIT(0),
+};
+
 struct rate_control_ops {
+	unsigned long capa;
 	const char *name;
 	void *(*alloc)(struct ieee80211_hw *hw, struct dentry *debugfsdir);
 	void (*free)(void *priv);
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 5fae001f286c..a431514ea01c 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -211,6 +211,7 @@ static const char *hw_flag_names[] = {
 	FLAG(TX_FRAG_LIST),
 	FLAG(REPORTS_LOW_ACK),
 	FLAG(SUPPORTS_TX_FRAG),
+	FLAG(SUPPORTS_VHT_EXT_NSS_BW),
 #undef FLAG
 };
 
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 159a1a733725..4047fc528977 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1217,6 +1217,9 @@ struct ieee80211_local {
 	/* number of RX chains the hardware has */
 	u8 rx_chains;
 
+	/* bitmap of which sbands were copied */
+	u8 sband_allocated;
+
 	int tx_headroom; /* required headroom for hardware/radiotap */
 
 	/* Tasklet and skb queue to process calls from IRQ mode. All frames
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 56fb47953b72..b83a1e2ba002 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1095,6 +1095,51 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 		goto fail_rate;
 	}
 
+	if (local->rate_ctrl) {
+		clear_bit(IEEE80211_HW_SUPPORTS_VHT_EXT_NSS_BW, hw->flags);
+		if (local->rate_ctrl->ops->capa & RATE_CTRL_CAPA_VHT_EXT_NSS_BW)
+			ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
+	}
+
+	/*
+	 * If the VHT capabilities don't have IEEE80211_VHT_EXT_NSS_BW_CAPABLE,
+	 * or have it when we don't, copy the sband structure and set/clear it.
+	 * This is necessary because rate scaling algorithms could be switched
+	 * and have different support values.
+	 * Print a message so that in the common case the reallocation can be
+	 * avoided.
+	 */
+	BUILD_BUG_ON(NUM_NL80211_BANDS > 8 * sizeof(local->sband_allocated));
+	for (band = 0; band < NUM_NL80211_BANDS; band++) {
+		struct ieee80211_supported_band *sband;
+		bool local_cap, ie_cap;
+
+		local_cap = ieee80211_hw_check(hw, SUPPORTS_VHT_EXT_NSS_BW);
+
+		sband = local->hw.wiphy->bands[band];
+		if (!sband || !sband->vht_cap.vht_supported)
+			continue;
+
+		ie_cap = !!(sband->vht_cap.vht_mcs.tx_highest &
+			    cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE));
+
+		if (local_cap == ie_cap)
+			continue;
+
+		sband = kmemdup(sband, sizeof(*sband), GFP_KERNEL);
+		if (!sband)
+			goto fail_rate;
+
+		wiphy_dbg(hw->wiphy, "copying sband (band %d) due to VHT EXT NSS BW flag\n",
+			  band);
+
+		sband->vht_cap.vht_mcs.tx_highest ^=
+			cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE);
+
+		local->hw.wiphy->bands[band] = sband;
+		local->sband_allocated |= BIT(band);
+	}
+
 	/* add one default STA interface if supported */
 	if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION) &&
 	    !ieee80211_hw_check(hw, NO_AUTO_VIF)) {
@@ -1216,6 +1261,7 @@ static int ieee80211_free_ack_frame(int id, void *p, void *data)
 void ieee80211_free_hw(struct ieee80211_hw *hw)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
+	enum nl80211_band band;
 
 	mutex_destroy(&local->iflist_mtx);
 	mutex_destroy(&local->mtx);
@@ -1231,6 +1277,12 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
 
 	ieee80211_free_led_names(local);
 
+	for (band = 0; band < NUM_NL80211_BANDS; band++) {
+		if (!(local->sband_allocated & BIT(band)))
+			continue;
+		kfree(local->hw.wiphy->bands[band]);
+	}
+
 	wiphy_free(local->hw.wiphy);
 }
 EXPORT_SYMBOL(ieee80211_free_hw);
-- 
2.9.3

^ permalink raw reply related

* [PATCH 2/5] mac80211: remove local pointer from rate_ctrl_ref
From: Johannes Berg @ 2017-02-15 14:02 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20170215140210.19393-1-johannes@sipsolutions.net>

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

This pointer really isn't needed, so remove it.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/mac80211/rate.c | 10 +++++-----
 net/mac80211/rate.h |  1 -
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index 206698bc93f4..094c15645228 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -208,7 +208,6 @@ static struct rate_control_ref *rate_control_alloc(const char *name,
 	ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL);
 	if (!ref)
 		return NULL;
-	ref->local = local;
 	ref->ops = ieee80211_rate_control_ops_get(name);
 	if (!ref->ops)
 		goto free;
@@ -229,13 +228,14 @@ static struct rate_control_ref *rate_control_alloc(const char *name,
 	return NULL;
 }
 
-static void rate_control_free(struct rate_control_ref *ctrl_ref)
+static void rate_control_free(struct ieee80211_local *local,
+			      struct rate_control_ref *ctrl_ref)
 {
 	ctrl_ref->ops->free(ctrl_ref->priv);
 
 #ifdef CONFIG_MAC80211_DEBUGFS
-	debugfs_remove_recursive(ctrl_ref->local->debugfs.rcdir);
-	ctrl_ref->local->debugfs.rcdir = NULL;
+	debugfs_remove_recursive(local->debugfs.rcdir);
+	local->debugfs.rcdir = NULL;
 #endif
 
 	kfree(ctrl_ref);
@@ -936,6 +936,6 @@ void rate_control_deinitialize(struct ieee80211_local *local)
 		return;
 
 	local->rate_ctrl = NULL;
-	rate_control_free(ref);
+	rate_control_free(local, ref);
 }
 
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h
index 8d3260785b94..d51a1cce4d4a 100644
--- a/net/mac80211/rate.h
+++ b/net/mac80211/rate.h
@@ -20,7 +20,6 @@
 #include "driver-ops.h"
 
 struct rate_control_ref {
-	struct ieee80211_local *local;
 	const struct rate_control_ops *ops;
 	void *priv;
 };
-- 
2.9.3

^ permalink raw reply related

* [PATCH 1/5] ieee80211: rename CCFS1/CCFS2 to CCFS0/CCFS1
From: Johannes Berg @ 2017-02-15 14:02 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg

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

This matches the spec, and otherwise things are really
confusing with the next patch adding CCFS2.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 drivers/net/wireless/marvell/mwifiex/tdls.c |  2 +-
 include/linux/ieee80211.h                   |  4 ++--
 net/mac80211/spectmgmt.c                    |  4 ++--
 net/mac80211/util.c                         | 22 +++++++++++-----------
 4 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c
index df9704de0715..5fc8319ed302 100644
--- a/drivers/net/wireless/marvell/mwifiex/tdls.c
+++ b/drivers/net/wireless/marvell/mwifiex/tdls.c
@@ -349,7 +349,7 @@ static int mwifiex_tdls_add_vht_oper(struct mwifiex_private *priv,
 		chan_bw = IEEE80211_VHT_CHANWIDTH_USE_HT;
 		break;
 	}
-	vht_oper->center_freq_seg1_idx =
+	vht_oper->center_freq_seg0_idx =
 			mwifiex_get_center_freq_index(priv, BAND_AAC,
 						      bss_desc->channel,
 						      chan_bw);
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 0dd9498c694f..4a15e77d9d66 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1525,14 +1525,14 @@ enum ieee80211_vht_chanwidth {
  * This structure is the "VHT operation element" as
  * described in 802.11ac D3.0 8.4.2.161
  * @chan_width: Operating channel width
+ * @center_freq_seg0_idx: center freq segment 0 index
  * @center_freq_seg1_idx: center freq segment 1 index
- * @center_freq_seg2_idx: center freq segment 2 index
  * @basic_mcs_set: VHT Basic MCS rate set
  */
 struct ieee80211_vht_operation {
 	u8 chan_width;
+	u8 center_freq_seg0_idx;
 	u8 center_freq_seg1_idx;
-	u8 center_freq_seg2_idx;
 	__le16 basic_mcs_set;
 } __packed;
 
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index 97f4c9d6b54c..0782e486fe89 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -132,9 +132,9 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
 		struct ieee80211_vht_operation vht_oper = {
 			.chan_width =
 				wide_bw_chansw_ie->new_channel_width,
-			.center_freq_seg1_idx =
+			.center_freq_seg0_idx =
 				wide_bw_chansw_ie->new_center_freq_seg0,
-			.center_freq_seg2_idx =
+			.center_freq_seg1_idx =
 				wide_bw_chansw_ie->new_center_freq_seg1,
 			/* .basic_mcs_set doesn't matter */
 		};
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index ac59fbd280df..7a37ce78bb38 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2413,13 +2413,13 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
 	*pos++ = WLAN_EID_VHT_OPERATION;
 	*pos++ = sizeof(struct ieee80211_vht_operation);
 	vht_oper = (struct ieee80211_vht_operation *)pos;
-	vht_oper->center_freq_seg1_idx = ieee80211_frequency_to_channel(
+	vht_oper->center_freq_seg0_idx = ieee80211_frequency_to_channel(
 							chandef->center_freq1);
 	if (chandef->center_freq2)
-		vht_oper->center_freq_seg2_idx =
+		vht_oper->center_freq_seg1_idx =
 			ieee80211_frequency_to_channel(chandef->center_freq2);
 	else
-		vht_oper->center_freq_seg2_idx = 0x00;
+		vht_oper->center_freq_seg1_idx = 0x00;
 
 	switch (chandef->width) {
 	case NL80211_CHAN_WIDTH_160:
@@ -2428,11 +2428,11 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
 		 * workaround.
 		 */
 		vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
-		vht_oper->center_freq_seg2_idx = vht_oper->center_freq_seg1_idx;
+		vht_oper->center_freq_seg1_idx = vht_oper->center_freq_seg0_idx;
 		if (chandef->chan->center_freq < chandef->center_freq1)
-			vht_oper->center_freq_seg1_idx -= 8;
+			vht_oper->center_freq_seg0_idx -= 8;
 		else
-			vht_oper->center_freq_seg1_idx += 8;
+			vht_oper->center_freq_seg0_idx += 8;
 		break;
 	case NL80211_CHAN_WIDTH_80P80:
 		/*
@@ -2491,9 +2491,9 @@ bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper,
 	if (!oper)
 		return false;
 
-	cf1 = ieee80211_channel_to_frequency(oper->center_freq_seg1_idx,
+	cf1 = ieee80211_channel_to_frequency(oper->center_freq_seg0_idx,
 					     chandef->chan->band);
-	cf2 = ieee80211_channel_to_frequency(oper->center_freq_seg2_idx,
+	cf2 = ieee80211_channel_to_frequency(oper->center_freq_seg1_idx,
 					     chandef->chan->band);
 
 	switch (oper->chan_width) {
@@ -2503,11 +2503,11 @@ bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper,
 		new.width = NL80211_CHAN_WIDTH_80;
 		new.center_freq1 = cf1;
 		/* If needed, adjust based on the newer interop workaround. */
-		if (oper->center_freq_seg2_idx) {
+		if (oper->center_freq_seg1_idx) {
 			unsigned int diff;
 
-			diff = abs(oper->center_freq_seg2_idx -
-				   oper->center_freq_seg1_idx);
+			diff = abs(oper->center_freq_seg1_idx -
+				   oper->center_freq_seg0_idx);
 			if (diff == 8) {
 				new.width = NL80211_CHAN_WIDTH_160;
 				new.center_freq1 = cf2;
-- 
2.9.3

^ permalink raw reply related

* [PATCH 3/5] cfg80211: refactor cfg80211_calculate_bitrate()
From: Johannes Berg @ 2017-02-15 14:02 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20170215140210.19393-1-johannes@sipsolutions.net>

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

This function contains the HT calculations, which makes no
sense - split that out into a separate function. As a side
effect, this makes the 60G flag independent from HT_MCS so
remove the MCS one from wil6210 (also deleting a duplicate
assignment.)

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 drivers/net/wireless/ath/wil6210/cfg80211.c |  3 +-
 net/wireless/util.c                         | 60 +++++++++++++++--------------
 2 files changed, 33 insertions(+), 30 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 83155b5ddbfb..79d107018eac 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -178,9 +178,8 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
 			BIT(NL80211_STA_INFO_RX_DROP_MISC) |
 			BIT(NL80211_STA_INFO_TX_FAILED);
 
-	sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
+	sinfo->txrate.flags = RATE_INFO_FLAGS_60G;
 	sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs);
-	sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
 	sinfo->rxrate.mcs = stats->last_mcs_rx;
 	sinfo->rx_bytes = stats->rx_bytes;
 	sinfo->rx_packets = stats->rx_packets;
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 68e5f2ecee1a..23ee3d66dfe0 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1097,6 +1097,35 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
 	return err;
 }
 
+static u32 cfg80211_calculate_bitrate_ht(struct rate_info *rate)
+{
+	int modulation, streams, bitrate;
+
+	/* the formula below does only work for MCS values smaller than 32 */
+	if (WARN_ON_ONCE(rate->mcs >= 32))
+		return 0;
+
+	modulation = rate->mcs & 7;
+	streams = (rate->mcs >> 3) + 1;
+
+	bitrate = (rate->bw == RATE_INFO_BW_40) ? 13500000 : 6500000;
+
+	if (modulation < 4)
+		bitrate *= (modulation + 1);
+	else if (modulation == 4)
+		bitrate *= (modulation + 2);
+	else
+		bitrate *= (modulation + 3);
+
+	bitrate *= streams;
+
+	if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
+		bitrate = (bitrate / 9) * 10;
+
+	/* do NOT round down here */
+	return (bitrate + 50000) / 100000;
+}
+
 static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate)
 {
 	static const u32 __mcs2bitrate[] = {
@@ -1230,39 +1259,14 @@ static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate)
 
 u32 cfg80211_calculate_bitrate(struct rate_info *rate)
 {
-	int modulation, streams, bitrate;
-
-	if (!(rate->flags & RATE_INFO_FLAGS_MCS) &&
-	    !(rate->flags & RATE_INFO_FLAGS_VHT_MCS))
-		return rate->legacy;
+	if (rate->flags & RATE_INFO_FLAGS_MCS)
+		return cfg80211_calculate_bitrate_ht(rate);
 	if (rate->flags & RATE_INFO_FLAGS_60G)
 		return cfg80211_calculate_bitrate_60g(rate);
 	if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)
 		return cfg80211_calculate_bitrate_vht(rate);
 
-	/* the formula below does only work for MCS values smaller than 32 */
-	if (WARN_ON_ONCE(rate->mcs >= 32))
-		return 0;
-
-	modulation = rate->mcs & 7;
-	streams = (rate->mcs >> 3) + 1;
-
-	bitrate = (rate->bw == RATE_INFO_BW_40) ? 13500000 : 6500000;
-
-	if (modulation < 4)
-		bitrate *= (modulation + 1);
-	else if (modulation == 4)
-		bitrate *= (modulation + 2);
-	else
-		bitrate *= (modulation + 3);
-
-	bitrate *= streams;
-
-	if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
-		bitrate = (bitrate / 9) * 10;
-
-	/* do NOT round down here */
-	return (bitrate + 50000) / 100000;
+	return rate->legacy;
 }
 EXPORT_SYMBOL(cfg80211_calculate_bitrate);
 
-- 
2.9.3

^ permalink raw reply related

* [PATCH 4/5] mac80211: encode rate type (legacy, HT, VHT) with fewer bits
From: Johannes Berg @ 2017-02-15 14:02 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20170215140210.19393-1-johannes@sipsolutions.net>

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

We don't really need three different bits for each, since the
types are mutually exclusive. Use just two bits for it.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/mac80211/sta_info.c | 11 ++++++++---
 net/mac80211/sta_info.h | 13 +++++++------
 2 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 4774e663a411..cd162be6024e 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -1960,14 +1960,17 @@ static void sta_stats_decode_rate(struct ieee80211_local *local, u16 rate,
 	rinfo->bw = (rate & STA_STATS_RATE_BW_MASK) >>
 		STA_STATS_RATE_BW_SHIFT;
 
-	if (rate & STA_STATS_RATE_VHT) {
+	switch (rate & STA_STATS_RATE_TYPE_MASK) {
+	case STA_STATS_RATE_TYPE_VHT:
 		rinfo->flags = RATE_INFO_FLAGS_VHT_MCS;
 		rinfo->mcs = rate & 0xf;
 		rinfo->nss = (rate & 0xf0) >> 4;
-	} else if (rate & STA_STATS_RATE_HT) {
+		break;
+	case STA_STATS_RATE_TYPE_HT:
 		rinfo->flags = RATE_INFO_FLAGS_MCS;
 		rinfo->mcs = rate & 0xff;
-	} else if (rate & STA_STATS_RATE_LEGACY) {
+		break;
+	case STA_STATS_RATE_TYPE_LEGACY: {
 		struct ieee80211_supported_band *sband;
 		u16 brate;
 		unsigned int shift;
@@ -1982,6 +1985,8 @@ static void sta_stats_decode_rate(struct ieee80211_local *local, u16 rate,
 		else
 			shift = 0;
 		rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift);
+		break;
+		}
 	}
 
 	if (rate & STA_STATS_RATE_SGI)
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 71fa41a1368a..1a9968aa6990 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -726,9 +726,10 @@ void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta);
 unsigned long ieee80211_sta_last_active(struct sta_info *sta);
 
 #define STA_STATS_RATE_INVALID		0
-#define STA_STATS_RATE_VHT		0x8000
-#define STA_STATS_RATE_HT		0x4000
-#define STA_STATS_RATE_LEGACY		0x2000
+#define STA_STATS_RATE_TYPE_MASK	0xC000
+#define STA_STATS_RATE_TYPE_LEGACY	0x4000
+#define STA_STATS_RATE_TYPE_HT		0x8000
+#define STA_STATS_RATE_TYPE_VHT		0xC000
 #define STA_STATS_RATE_SGI		0x1000
 #define STA_STATS_RATE_BW_SHIFT		9
 #define STA_STATS_RATE_BW_MASK		(0x7 << STA_STATS_RATE_BW_SHIFT)
@@ -754,11 +755,11 @@ static inline u16 sta_stats_encode_rate(struct ieee80211_rx_status *s)
 		r |= STA_STATS_RATE_SGI;
 
 	if (s->flag & RX_FLAG_VHT)
-		r |= STA_STATS_RATE_VHT | (s->vht_nss << 4);
+		r |= STA_STATS_RATE_TYPE_VHT | (s->vht_nss << 4);
 	else if (s->flag & RX_FLAG_HT)
-		r |= STA_STATS_RATE_HT;
+		r |= STA_STATS_RATE_TYPE_HT;
 	else
-		r |= STA_STATS_RATE_LEGACY | (s->band << 4);
+		r |= STA_STATS_RATE_TYPE_LEGACY | (s->band << 4);
 
 	return r;
 }
-- 
2.9.3

^ permalink raw reply related

* [PATCH 5/5] ieee80211: define HT operation CCFS2 field
From: Johannes Berg @ 2017-02-15 14:02 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20170215140210.19393-1-johannes@sipsolutions.net>

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

The Channel Center Frequency Segment 2 field is used in
802.11-2016 for encoding the actual channel position of
the 80+80/160 MHz channel, if the max NSS is restricted.
This is used for backwards compatibility.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 include/linux/ieee80211.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 4a15e77d9d66..4a7200c6c9ea 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1411,6 +1411,8 @@ struct ieee80211_ht_operation {
 #define		IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED	3
 #define IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT		0x0004
 #define IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT		0x0010
+#define IEEE80211_HT_OP_MODE_CCFS2_SHIFT		5
+#define IEEE80211_HT_OP_MODE_CCFS2_MASK			0x1fe0
 
 /* for stbc_param */
 #define IEEE80211_HT_STBC_PARAM_DUAL_BEACON		0x0040
-- 
2.9.3

^ permalink raw reply related

* [mac80211-next:vht-he 7/14] include/uapi/linux/kernel.h:12:49: warning: 'max_vht_nss' may be used uninitialized in this function
From: kbuild test robot @ 2017-02-15 13:43 UTC (permalink / raw)
  To: Johannes Berg; +Cc: kbuild-all, linux-wireless

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

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git vht-he
head:   fb4566483cf87f72333e1a3f65d99d9a24227b10
commit: 944d0b05ebf7bf2ae2cc4b7184e86d7cd3a9f18b [7/14] ieee80211: add new VHT capability fields/parsing
config: xtensa-allmodconfig (attached as .config)
compiler: xtensa-linux-gcc (GCC) 4.9.0
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        git checkout 944d0b05ebf7bf2ae2cc4b7184e86d7cd3a9f18b
        # save the attached .config to linux build tree
        make.cross ARCH=xtensa 

Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings

All warnings (new ones prefixed by >>):

   In file included from include/linux/cache.h:4:0,
                    from include/linux/printk.h:8,
                    from include/linux/kernel.h:13,
                    from include/linux/skbuff.h:17,
                    from include/linux/if_ether.h:23,
                    from include/linux/etherdevice.h:25,
                    from net/wireless/util.c:9:
   net/wireless/util.c: In function 'ieee80211_get_vht_max_nss':
>> include/uapi/linux/kernel.h:12:49: warning: 'max_vht_nss' may be used uninitialized in this function [-Wmaybe-uninitialized]
    #define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
                                                    ^
   net/wireless/util.c:1880:6: note: 'max_vht_nss' was declared here
     int max_vht_nss;
         ^

vim +/max_vht_nss +12 include/uapi/linux/kernel.h

607ca46e David Howells   2012-10-13   1  #ifndef _UAPI_LINUX_KERNEL_H
607ca46e David Howells   2012-10-13   2  #define _UAPI_LINUX_KERNEL_H
607ca46e David Howells   2012-10-13   3  
607ca46e David Howells   2012-10-13   4  #include <linux/sysinfo.h>
607ca46e David Howells   2012-10-13   5  
607ca46e David Howells   2012-10-13   6  /*
607ca46e David Howells   2012-10-13   7   * 'kernel.h' contains some often-used function prototypes etc
607ca46e David Howells   2012-10-13   8   */
607ca46e David Howells   2012-10-13   9  #define __ALIGN_KERNEL(x, a)		__ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
607ca46e David Howells   2012-10-13  10  #define __ALIGN_KERNEL_MASK(x, mask)	(((x) + (mask)) & ~(mask))
607ca46e David Howells   2012-10-13  11  
b5d3755a Nicolas Dichtel 2016-03-04 @12  #define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
607ca46e David Howells   2012-10-13  13  
607ca46e David Howells   2012-10-13  14  #endif /* _UAPI_LINUX_KERNEL_H */

:::::: The code at line 12 was first introduced by commit
:::::: b5d3755a22e0cc4c369c0985aef0c52c2477c1e7 uapi: define DIV_ROUND_UP for userland

:::::: TO: Nicolas Dichtel <nicolas.dichtel@6wind.com>
:::::: CC: David S. Miller <davem@davemloft.net>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 48181 bytes --]

^ permalink raw reply

* [mac80211-next:vht-he 7/14] net/wireless/util.c:1948:13: warning: 'max_vht_nss' may be used uninitialized in this function
From: kbuild test robot @ 2017-02-15 13:21 UTC (permalink / raw)
  To: Johannes Berg; +Cc: kbuild-all, linux-wireless

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

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git vht-he
head:   fb4566483cf87f72333e1a3f65d99d9a24227b10
commit: 944d0b05ebf7bf2ae2cc4b7184e86d7cd3a9f18b [7/14] ieee80211: add new VHT capability fields/parsing
config: x86_64-randconfig-x009-201707 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        git checkout 944d0b05ebf7bf2ae2cc4b7184e86d7cd3a9f18b
        # save the attached .config to linux build tree
        make ARCH=x86_64 

Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings

All warnings (new ones prefixed by >>):

   net/wireless/util.c: In function 'ieee80211_get_vht_max_nss':
>> net/wireless/util.c:1948:13: warning: 'max_vht_nss' may be used uninitialized in this function [-Wmaybe-uninitialized]
       return 2 * max_vht_nss;
              ~~^~~~~~~~~~~~~

vim +/max_vht_nss +1948 net/wireless/util.c

  1932		switch (bw) {
  1933		case IEEE80211_VHT_CHANWIDTH_USE_HT:
  1934		case IEEE80211_VHT_CHANWIDTH_80MHZ:
  1935			if ((supp_width == 1 || supp_width == 2) &&
  1936			    ext_nss_bw == 3)
  1937				return 2 * max_vht_nss;
  1938			break;
  1939		case IEEE80211_VHT_CHANWIDTH_160MHZ:
  1940			if (supp_width == 0 &&
  1941			    (ext_nss_bw == 1 || ext_nss_bw == 2))
  1942				return DIV_ROUND_UP(max_vht_nss, 2);
  1943			if (supp_width == 0 &&
  1944			    ext_nss_bw == 3)
  1945				return DIV_ROUND_UP(3 * max_vht_nss, 4);
  1946			if (supp_width == 1 &&
  1947			    ext_nss_bw == 3)
> 1948				return 2 * max_vht_nss;
  1949			break;
  1950		case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
  1951			if (supp_width == 0 &&
  1952			    ext_nss_bw == 2)
  1953				return DIV_ROUND_UP(max_vht_nss, 2);
  1954			if (supp_width == 0 &&
  1955			    ext_nss_bw == 3)
  1956				return DIV_ROUND_UP(3 * max_vht_nss, 4);

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 27562 bytes --]

^ permalink raw reply

* [PATCH] mac80211: Print text for disassociation reason
From: Arkadiusz Miśkiewicz @ 2017-02-15 13:21 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Arkadiusz Miśkiewicz

When disassociation happens only numeric reason is printed
in ieee80211_rx_mgmt_disassoc(). Add text variant, too.

Signed-off-by: Arkadiusz Miśkiewicz <arekm@maven.pl>
---
 net/mac80211/mlme.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 098ce9b179ee..fcf8d0aa66ec 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2801,8 +2801,9 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
 
 	reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
 
-	sdata_info(sdata, "disassociated from %pM (Reason: %u)\n",
-		   mgmt->sa, reason_code);
+	sdata_info(sdata, "disassociated from %pM (Reason: %u=%s)\n",
+		   mgmt->sa, reason_code,
+		   ieee80211_get_reason_code_string(reason_code));
 
 	ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
 
-- 
2.11.0

^ 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