Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [RFC PATCH v3 02/12] nl80211/cfg80211: Extended Key ID support
From: Alexander Wetzel @ 2019-02-17 19:19 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <790f69239a9635c62c9349323c069e4ac9ad51c9.camel@sipsolutions.net>

>> +/**
>> + * enum nl80211_key_install_mode - Key install mode
>> + *
>> + * @NL80211_KEY_RX_TX: Key must be installed for Rx and Tx
>> + * @NL80211_KEY_RX_ONLY: Allowed in combination with @NL80211_CMD_NEW_KEY:
>> + *	Unicast key has to be installed for Rx only.
>> + * @NL80211_KEY_SWITCH_TX: Allowed in combination with @NL80211_CMD_SET_KEY:
>> + *	Switch Tx to a Rx only, referenced by sta mac and idx.
> 
> Don't you mean the other way around? Or, well, what you say is true for
> the *other* keys?

I don't see the problem but I may simply be to set on my way to see 
it... So I'll just give an outline what's required of the API and how 
this implementation meets those. Hoping that answers your question or 
allowing you to pinpoint our differences in understanding. (I've added a 
  more than really required, it may be useful for other discussions to 
have that outlined in one piece, too.)

Extended Key ID has only two requirements for the kernel API:
1) Allow a key to be used for decryption first and switch it to a 
"normal" Rx/Tx key with a second call

2) Allow pairwise keys to use keyids 0 and 1 instead only 0.

"Legacy" key installs are using NL80211_CMD_NEW_KEY to install a new key 
and are allow to mark a key for WEP or management  default usages via 
NL80211_CMD_SET_KEY later.

With Extended Key ID we stick to a similar approach: NL80211_CMD_NEW_KEY 
is called to install the new key and nl80211_key_install_mode allows to 
select between a "legacy" or "extended" key install: NL80211_KEY_RX_TX 
for "legacy" or NL80211_KEY_RX_ONLY for "extended".

NL80211_KEY_SWITCH_TX is only allowed with NL80211_CMD_SET_KEY and is 
the only Extended Key ID action allowed for that function.

Any non-pairwise keys can only use NL80211_KEY_RX_TX which is of course 
always the default and also allowed for "legacy" pairwise keys.

A Extended Key Install will:
1) call NL80211_CMD_NEW_KEY with all the usual parameters of a new key 
install plus the flag NL80211_KEY_RX_ONLY set.

2) Once ready will call NL80211_CMD_SET_KEY with flag 
NL80211_KEY_SWITCH_TX to activate a specific key.


>>    *	by the %NL80211_SCAN_FLAG_MIN_PREQ_CONTENT flag.
>>    * @NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER: Driver supports enabling fine
>>    *	timing measurement responder role.
>> - *
> 
> no need to remove that :)

ok, I'll remove all the drive-by comment "cleanups".
It (often) looks kind of untidy and not really worth separate patches 
and I'm kind of responsible for (most) of them.. I see why you don't 
want to see those fixed drive-by...

My understanding is now that we prefer to not change those and I'll 
leave them alone.

> 
>> -	/* only support setting default key */
>> -	if (!key.def && !key.defmgmt)
>> +	/* Only support setting default key and
>> +	 * Extended Key ID action @NL80211_KEY_SWITCH_TX.
>> +	 */
> 
> you can remove the @, it's not a kernel-doc formatted comment
> 
>> -	}
>> +	} else if (key.p.install_mode == NL80211_KEY_SWITCH_TX &&
>> +		   wiphy_ext_feature_isset(&rdev->wiphy,
>> +					   NL80211_EXT_FEATURE_EXT_KEY_ID)) {
>> +		u8 *mac_addr = NULL;
>>   
>> +		if (info->attrs[NL80211_ATTR_MAC])
>> +			mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
>> +
>> +		if (!mac_addr || key.idx < 0 || key.idx > 1) {
>> +			err = -EINVAL;
>> +			goto out;
>> +		}
> 
> Really only 0 and 1 are allowed? Not 0-3?

Yes. Extended Key ID only allows to use Key ID 1 on top of the 
established ID 0. See "IEEE 802.11 - 2016 9.4.2.25.4 RSN capabilities":

Bit 13: Extended Key ID for Individually Addressed Frames. This subfield 
is set to 1 to indicate that the STA supports Key ID values in the range 
0 to 1 for a PTKSA and STKSA when the cipher suite is CCMP or GCMP. A 
value of 0 indicates that the STA only supports Key ID 0 for a PTKSA and
STKSA.

Or also "12.7.6.4 4-way handshake message 2":

If the Extended Key ID for Individually Addressed Frames subfield of the 
RSN Capabilities field is 1 for both the Authenticator and the 
Supplicant, then the Authenticator assigns a new Key ID for the PTKSA in
the range 0 to 1 that is different from the Key ID assigned in the 
previous handshake and uses the MLME-SETKEYS.request primitive to 
install the new key to receive individually addressed MPDUs protected by
the PTK with the assigned Key ID.

> 
>> +++ b/net/wireless/util.c
>> @@ -236,14 +236,22 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
>>   	case WLAN_CIPHER_SUITE_CCMP_256:
>>   	case WLAN_CIPHER_SUITE_GCMP:
>>   	case WLAN_CIPHER_SUITE_GCMP_256:
>> -		/* Disallow pairwise keys with non-zero index unless it's WEP
>> -		 * or a vendor specific cipher (because current deployments use
>> -		 * pairwise WEP keys with non-zero indices and for vendor
>> -		 * specific ciphers this should be validated in the driver or
>> -		 * hardware level - but 802.11i clearly specifies to use zero)
>> +		/* IEEE802.11-2016 allows only 0 and - when using Extended Key
>> +		 * ID - 1 as index for pairwise keys.
>> +		 * @NL80211_KEY_RX_ONLY is only allowed for pairwise keys when
>> +		 * the driver supports Extended Key ID.
>> +		 * @NL80211_KEY_SWITCH_TX must not be set when validating a key.
>>   		 */
>> -		if (pairwise && key_idx)
>> +		if (params->install_mode == NL80211_KEY_RX_ONLY) {
>> +			if (!wiphy_ext_feature_isset(&rdev->wiphy,
>> +						     NL80211_EXT_FEATURE_EXT_KEY_ID))
>> +				return -EINVAL;
>> +			else if (!pairwise || key_idx < 0 || key_idx > 1)
>> +				return -EINVAL;
> 
> same question here

same answer with one remark: The original code did only allow id 0 and 
and I made sure only with install mode NL80211_KEY_RX_ONLY is allowed to 
use non-zero IDs.

Alexander

^ permalink raw reply

* Re: [PATCH 2/2] mac80211: probe unexercised mesh links
From: Rajkumar Manoharan @ 2019-02-17 15:56 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, kevinhayes, julanhsu
In-Reply-To: <0541dec472c83b173a486a924983a450ede7e923.camel@sipsolutions.net>

On 2019-02-15 02:44, Johannes Berg wrote:
>>  void __ieee80211_subif_start_xmit(struct sk_buff *skb,
>>  				  struct net_device *dev,
>> -				  u32 info_flags);
>> +				  u32 info_flags,
>> +				  u32 ctrl_flags);
> 
> I'd feel better if we could avoid all this, but if you really can't 
> then
> I guess we should split this out to a separate patch.
> 
Hmm.. I don't see any options other than this. no free slot in 
info_flags.
Will split this change.

>> 
>> +	/* Allow injected packets to bypass mesh routing */
>> +	if (info->control.flags & IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP)
> 
> unlikely?
> 
>> +int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device 
>> *dev,
>> +			      const u8 *dest, const u8 *buf, size_t len)
>> +{
>> +	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
>> +	struct ieee80211_local *local = sdata->local;
>> +	struct sta_info *sta;
>> +	struct sk_buff *skb;
>> +	struct ethhdr *ehdr;
>> +
>> +	if (len < sizeof(*ehdr))
>> +		return -EINVAL;
>> +
>> +	mutex_lock(&local->sta_mtx);
>> +	sta = sta_info_get_bss(sdata, dest);
>> +	mutex_unlock(&local->sta_mtx);
>> +
>> +	if (!sta)
>> +		return -ENOENT;
> 
> better add a comment here that the locking is fine because you only
> check *existence* and don't use the sta pointer for anything else
> 
>> +	ehdr = (struct ethhdr *)buf;
>> +	if (!ether_addr_equal(ehdr->h_dest, dest) ||
> 
> that check could be in cfg80211, but then why even bother passing the
> "dest" separately?
> 
>> +	    !ether_addr_equal(ehdr->h_source, sdata->vif.addr) ||
> 
> probably this one too
> 
>> +	    is_multicast_ether_addr(ehdr->h_dest))
> 
> this one too
> 
Will move all the condition checks to cfg80211.

> But also, ehdr isn't packed I think, you might have alignment issues
> here as you don't know how the netlink message looks like? I think?
> 
>> +	if (ehdr->h_proto != htons(ETH_P_802_3))
>> +		return -EINVAL;
> 
> same here
> 
>> +	skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
> 
> you should make it a bit bigger so header conversion will fit, I guess?
> 
Hmm. I thought ieee80211_skb_resize in build_hdr will take care of it.

-Rajkumar

^ permalink raw reply

* Re: Kernel hangs on regulatory.db X.509 key initialization
From: Dominik Schmidt @ 2019-02-17 15:47 UTC (permalink / raw)
  To: Maciej S. Szmigiero; +Cc: james.morris, linux-wireless
In-Reply-To: <0ce6546d-0f1d-922c-0acd-796966c98aab@maciej.szmigiero.name>

Excerpts from Maciej S. Szmigiero's message of Februar 17, 2019 1:29 pm:
> Hi,
> 
> On 17.02.2019 10:38, Dominik Schmidt wrote:
>> Hi there!
>> 
>> I'm running a Gentoo Linux on an APU2C2-Board (AMD Jaguar GX-412TC x86_64), with
>> an Atheros QCA9882 (ath10k) and an Atheros AR9280 (ath9k) card.
>> 
>> The kernels after 4.18 do not reach userspace any longer. 
> 
> Did you test a more recent kernel like 4.20?

Yes, up to 4.20.7, yielding the same fault

>> They just somehow
>> "freeze" without emitting any oops or kernel panic. I've tracked the issue
>> down to the cfg80211 subsystem and a change in the X.509 parser:
>> 
>> * If I do not compile cfg80211 into the kernel, it starts perfectly (minus wireless)
>> 
>> * Bisecting the issue shows that it starts with
>> 	https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b65c32ec5a942ab3ada93a048089a938918aba7f
>> 
>> * The last message I see in the logs is this one:
>> 	cfg80211: Loading compiled-in X.509 certificates for regulatory database
>>   defined at
>> 	https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/wireless/reg.c#n770
>> 
>> * If I add another pr_notice to the end of that function, it is never displayed.
>> 
>> * It seems to get stuck at the call to key_create_or_update, here:
>> 	https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/wireless/reg.c#n735
>> 
>> * If I throw more pr_notices at key_create_or_update, the last one I see 
>>   is before this memset:
>> 	https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/security/keys/key.c#n843
>> 
>> * As an additional hindrance, this problem occurs only on the APU2 board,
>>   and not when running the same kernel in a Qemu-VM
>> 
>> Any idea what could be the cause of this, or hints as to how to
>> debug this further?
> 
> I see that you are using an AMD CPU-based board, with AMD CCP enabled
> in your kernel config.
> 
> Before my patch, that you bisected your problem to, such configuration
> would fail (early) in-kernel X.509 certificate signature verification
> as its length wasn't exactly correct.

Yes, it did/does actually fail with:

[    7.376473] cfg80211: Loading compiled-in X.509 certificates for regulatory database
[    7.388090] cfg80211: Problem loading in-kernel X.509 certificate (-22)
[    7.406107] cfg80211: failed to load regulatory.db

> Now, when this was fixed the CCP RSA implementation actually gets
> exercised (however, it works for me without problems on Ryzen).

In deed it seems that CCP might be the culprit here, nice catch.
If I remove the option, the kernel starts up nicely with:

[    7.097244] cfg80211: Loading compiled-in X.509 certificates for regulatory database
[    7.109893] cfg80211: Loaded X.509 cert 'sforshee: 00b28ddf47aef9cea7'
[    7.117763] platform regulatory.0: Direct firmware load for regulatory.db failed with error -2
[    7.129880] cfg80211: failed to load regulatory.db

> You can temporarily change CONFIG_CFG80211 in your kernel config to
> 'm' and compile the kernel with KASAN.
> Don't load any wireless modules at startup, this should at least
> defer the crash until you load them manually later when the system is
> idle and you can monitor it.
> 
> If you are lucky KASAN will give you information then where the bug
> might be.

Oh, this works marvellously:

[   23.301826] ==================================================================
[   23.309463] BUG: KASAN: slab-out-of-bounds in ccp_rsa_crypt+0x84/0x250
[   23.316092] Write of size 296 at addr ffff88805ba00c40 by task swapper/0/1
[   23.323030]
[   23.324633] CPU: 1 PID: 1 Comm: swapper/0 Tainted: G                T 4.20.7 #38
[   23.332121] Hardware name: PC Engines apu2/apu2, BIOS v4.9.0.1 01/09/2019
[   23.339051] Call Trace:
[   23.341610]  dump_stack+0xd1/0x160
[   23.345123]  ? dump_stack_print_info.cold.0+0x1b/0x1b
[   23.350321]  ? kmsg_dump_rewind_nolock+0x60/0x60
[   23.355093]  print_address_description.cold.3+0x9/0x26a
[   23.360465]  kasan_report.cold.4+0x65/0xa3
[   23.364662]  ? ccp_rsa_crypt+0x84/0x250
[   23.368605]  memset+0x2d/0x50
[   23.371681]  ccp_rsa_crypt+0x84/0x250
[   23.375506]  ? ccp_rsa_exit_tfm+0x10/0x10
[   23.379651]  pkcs1pad_verify+0x254/0x2c0
[   23.383706]  public_key_verify_signature+0x385/0x5b0
[   23.388800]  ? software_key_query+0x2f0/0x2f0
[   23.393285]  ? ret_from_fork+0x27/0x50
[   23.397157]  ? sha256_base_init+0xa0/0xa0
[   23.401319]  ? match_held_lock+0xb8/0x380
[   23.405485]  ? __lock_acquire+0x2d30/0x2d30
[   23.409807]  ? x509_get_sig_params+0x223/0x280
[   23.414385]  ? kasan_unpoison_shadow+0x3b/0x60
[   23.418931]  ? kasan_kmalloc+0xee/0x100
[   23.422929]  ? asymmetric_key_generate_id+0x3e/0xa0
[   23.427925]  x509_check_for_self_signed+0x183/0x20c
[   23.432919]  ? asymmetric_key_generate_id+0x77/0xa0
[   23.437930]  x509_cert_parse+0x315/0x3c0
[   23.441958]  x509_key_preparse+0x47/0x3a0
[   23.446084]  asymmetric_key_preparse+0x60/0x90
[   23.450648]  key_create_or_update+0x3aa/0x8b0
[   23.455107]  ? key_type_lookup+0x90/0x90
[   23.459195]  ? key_instantiate_and_link+0x250/0x2c0
[   23.464144]  ? key_user_put+0x50/0x50
[   23.467943]  regulatory_init_db+0x20d/0x386
[   23.472245]  ? regulatory_init+0x201/0x201
[   23.476471]  do_one_initcall+0xd5/0x458
[   23.480436]  ? perf_trace_initcall_level+0x370/0x370
[   23.485499]  ? strlen+0x5/0x40
[   23.488697]  ? next_arg+0x19c/0x220
[   23.492291]  ? strlen+0x1e/0x40
[   23.495508]  ? rcu_is_watching+0xa5/0xf0
[   23.499532]  ? __lock_is_held+0x38/0xd0
[   23.503472]  ? rcu_gpnum_ovf+0x210/0x210
[   23.507499]  ? rcu_read_lock_sched_held+0x70/0x80
[   23.512328]  ? trace_initcall_level+0x15b/0x1bc
[   23.516964]  ? do_one_initcall+0x400/0x458
[   23.521192]  ? up_write+0xcf/0x180
[   23.524674]  ? down_read_non_owner+0xb0/0xb0
[   23.529105]  ? kasan_unpoison_shadow+0x3b/0x60
[   23.533654]  kernel_init_freeable+0x511/0x60e
[   23.538103]  ? rest_init+0x2df/0x2df
[   23.541782]  kernel_init+0x7/0x121
[   23.545263]  ? rest_init+0x2df/0x2df
[   23.548912]  ret_from_fork+0x27/0x50
[   23.552583]
[   23.554173] Allocated by task 1:
[   23.557564]  kasan_kmalloc+0xee/0x100
[   23.561325]  __kmalloc+0x123/0x280
[   23.564859]  public_key_verify_signature+0x157/0x5b0
[   23.569893]  x509_check_for_self_signed+0x183/0x20c
[   23.574899]  x509_cert_parse+0x315/0x3c0
[   23.578913]  x509_key_preparse+0x47/0x3a0
[   23.582993]  asymmetric_key_preparse+0x60/0x90
[   23.587565]  key_create_or_update+0x3aa/0x8b0
[   23.592047]  regulatory_init_db+0x20d/0x386
[   23.596332]  do_one_initcall+0xd5/0x458
[   23.600273]  kernel_init_freeable+0x511/0x60e
[   23.604714]  kernel_init+0x7/0x121
[   23.608228]  ret_from_fork+0x27/0x50
[   23.611928]
[   23.613522] Freed by task 0:
[   23.616497] (stack is not available)
[   23.620158]
[   23.621740] The buggy address belongs to the object at ffff88805ba00b40
[   23.621740]  which belongs to the cache kmalloc-256 of size 256
[   23.634410] The buggy address is located 0 bytes to the right of
[   23.634410]  256-byte region [ffff88805ba00b40, ffff88805ba00c40)
[   23.646599] The buggy address belongs to the page:
[   23.651537] page:ffffea00016e8000 count:1 mapcount:0 mapping:ffff88805f803200 index:0x0 compound_mapcount: 0
[   23.661500] flags: 0x4000000000010200(slab|head)
[   23.666272] raw: 4000000000010200 dead000000000100 dead000000000200 ffff88805f803200
[   23.674178] raw: 0000000000000000 0000000080190019 00000001ffffffff 0000000000000000
[   23.682028] page dumped because: kasan: bad access detected
[   23.687724]
[   23.689329] Memory state around the buggy address:
[   23.694255]  ffff88805ba00b00: fc fc fc fc fc fc fc fc 00 00 00 00 00 00 00 00
[   23.701593]  ffff88805ba00b80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[   23.708926] >ffff88805ba00c00: 00 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc
[   23.716304]                                            ^
[   23.721725]  ffff88805ba00c80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[   23.729058]  ffff88805ba00d00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[   23.736370] ==================================================================
[   23.743664] Disabling lock debugging due to kernel taint

I will investigate further and start a new thread in linux-crypto once I find out more
(sorry about abusing linux-wireless :/)

Anyways, many thanks Maciej for looking into it, your help is much appreciated!

>> Cheers
>> Dominik
>> 
> 
> Maciej
> 

^ permalink raw reply

* [PATCH v2] ath10k: wait for vdev delete response from firmware
From: Rakesh Pillai @ 2019-02-17 13:51 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Rakesh Pillai

When we add an interface immediately after removing
the interface the vdev deletion in firmware might not
have been completed. We need to synchronize the vdev creation
with the firmware.

Wait for vdev delete response from firmware when we
remove an interface.

Tested HW: WCN3990
Tested FW: WLAN.HL.2.0-01188-QCAHLSWMTPLZ-1

Signed-off-by: Rakesh Pillai <pillair@codeaurora.org>
---
Changes from v1:
- Unlock conf_mutex in vdev delete failure case.
---
 drivers/net/wireless/ath/ath10k/core.c    |  4 +++-
 drivers/net/wireless/ath/ath10k/core.h    |  6 ++++--
 drivers/net/wireless/ath/ath10k/mac.c     | 15 +++++++++++++++
 drivers/net/wireless/ath/ath10k/wmi-tlv.c | 12 +++++++++++-
 drivers/net/wireless/ath/ath10k/wmi-tlv.h |  6 +++++-
 drivers/net/wireless/ath/ath10k/wmi.h     |  4 +++-
 6 files changed, 41 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 327a74c0..16d2d04 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2005-2011 Atheros Communications Inc.
  * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -2137,6 +2137,7 @@ static void ath10k_core_restart(struct work_struct *work)
 	complete(&ar->offchan_tx_completed);
 	complete(&ar->install_key_done);
 	complete(&ar->vdev_setup_done);
+	complete(&ar->vdev_delete_done);
 	complete(&ar->thermal.wmi_sync);
 	complete(&ar->bss_survey_done);
 	wake_up(&ar->htt.empty_tx_wq);
@@ -3093,6 +3094,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
 
 	init_completion(&ar->install_key_done);
 	init_completion(&ar->vdev_setup_done);
+	init_completion(&ar->vdev_delete_done);
 	init_completion(&ar->thermal.wmi_sync);
 	init_completion(&ar->bss_survey_done);
 
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 46e9c8c..ad1da95 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2005-2011 Atheros Communications Inc.
  * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -511,7 +511,8 @@ struct ath10k_sta {
 	u32 peer_ps_state;
 };
 
-#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ)
+#define ATH10K_VDEV_SETUP_TIMEOUT_HZ	(5 * HZ)
+#define ATH10K_VDEV_DELETE_TIMEOUT_HZ	(5 * HZ)
 
 enum ath10k_beacon_state {
 	ATH10K_BEACON_SCHEDULED = 0,
@@ -1058,6 +1059,7 @@ struct ath10k {
 
 	int last_wmi_vdev_start_status;
 	struct completion vdev_setup_done;
+	struct completion vdev_delete_done;
 
 	struct workqueue_struct *workqueue;
 	/* Auxiliary workqueue */
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 4dd64f3..02c17f4 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1022,6 +1022,7 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
 	arg.channel.max_antenna_gain = channel->max_antenna_gain * 2;
 
 	reinit_completion(&ar->vdev_setup_done);
+	reinit_completion(&ar->vdev_delete_done);
 
 	ret = ath10k_wmi_vdev_start(ar, &arg);
 	if (ret) {
@@ -1071,6 +1072,7 @@ static int ath10k_monitor_vdev_stop(struct ath10k *ar)
 			    ar->monitor_vdev_id, ret);
 
 	reinit_completion(&ar->vdev_setup_done);
+	reinit_completion(&ar->vdev_delete_done);
 
 	ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);
 	if (ret)
@@ -1412,6 +1414,7 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif)
 	lockdep_assert_held(&ar->conf_mutex);
 
 	reinit_completion(&ar->vdev_setup_done);
+	reinit_completion(&ar->vdev_delete_done);
 
 	ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id);
 	if (ret) {
@@ -1448,6 +1451,7 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif,
 	lockdep_assert_held(&ar->conf_mutex);
 
 	reinit_completion(&ar->vdev_setup_done);
+	reinit_completion(&ar->vdev_delete_done);
 
 	arg.vdev_id = arvif->vdev_id;
 	arg.dtim_period = arvif->dtim_period;
@@ -5397,6 +5401,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
 	struct ath10k *ar = hw->priv;
 	struct ath10k_vif *arvif = (void *)vif->drv_priv;
 	struct ath10k_peer *peer;
+	unsigned long time_left;
 	int ret;
 	int i;
 
@@ -5438,6 +5443,15 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
 		ath10k_warn(ar, "failed to delete WMI vdev %i: %d\n",
 			    arvif->vdev_id, ret);
 
+	if (test_bit(WMI_SERVICE_SYNC_DELETE_CMDS, ar->wmi.svc_map)) {
+		time_left = wait_for_completion_timeout(&ar->vdev_delete_done,
+							ATH10K_VDEV_DELETE_TIMEOUT_HZ);
+		if (time_left == 0) {
+			ath10k_warn(ar, "Timeout in receiving vdev delete response\n");
+			goto out:
+		}
+	}
+
 	/* Some firmware revisions don't notify host about self-peer removal
 	 * until after associated vdev is deleted.
 	 */
@@ -5488,6 +5502,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
 
 	ath10k_mac_txq_unref(ar, vif->txq);
 
+out:
 	mutex_unlock(&ar->conf_mutex);
 }
 
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index 90617e1..642d770 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2005-2011 Atheros Communications Inc.
  * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -222,6 +222,13 @@ static int ath10k_wmi_tlv_event_bcn_tx_status(struct ath10k *ar,
 	return 0;
 }
 
+static void ath10k_wmi_tlv_event_vdev_delete_resp(struct ath10k *ar,
+						  struct sk_buff *skb)
+{
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_DELETE_RESP_EVENTID\n");
+	complete(&ar->vdev_delete_done);
+}
+
 static int ath10k_wmi_tlv_event_diag_data(struct ath10k *ar,
 					  struct sk_buff *skb)
 {
@@ -524,6 +531,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
 	case WMI_TLV_VDEV_STOPPED_EVENTID:
 		ath10k_wmi_event_vdev_stopped(ar, skb);
 		break;
+	case WMI_TLV_VDEV_DELETE_RESP_EVENTID:
+		ath10k_wmi_tlv_event_vdev_delete_resp(ar, skb);
+		break;
 	case WMI_TLV_PEER_STA_KICKOUT_EVENTID:
 		ath10k_wmi_event_peer_sta_kickout(ar, skb);
 		break;
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
index 298d917..872da8e 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2005-2011 Atheros Communications Inc.
  * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -310,6 +310,8 @@ enum wmi_tlv_event_id {
 	WMI_TLV_VDEV_STOPPED_EVENTID,
 	WMI_TLV_VDEV_INSTALL_KEY_COMPLETE_EVENTID,
 	WMI_TLV_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID,
+	WMI_TLV_VDEV_TSF_REPORT_EVENTID,
+	WMI_TLV_VDEV_DELETE_RESP_EVENTID,
 	WMI_TLV_PEER_STA_KICKOUT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_PEER),
 	WMI_TLV_PEER_INFO_EVENTID,
 	WMI_TLV_PEER_TX_FAIL_CNT_THR_EVENTID,
@@ -1557,6 +1559,8 @@ wmi_tlv_svc_map(const __le32 *in, unsigned long *out, size_t len)
 	       WMI_SERVICE_SAP_AUTH_OFFLOAD, len);
 	SVCMAP(WMI_TLV_SERVICE_MGMT_TX_WMI,
 	       WMI_SERVICE_MGMT_TX_WMI, len);
+	SVCMAP(WMI_TLV_SERVICE_SYNC_DELETE_CMDS,
+	       WMI_SERVICE_SYNC_DELETE_CMDS, len);
 }
 
 static inline void
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 1f82f10..b941240 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2005-2011 Atheros Communications Inc.
  * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -208,6 +208,7 @@ enum wmi_service {
 	WMI_SERVICE_VDEV_DISABLE_4_ADDR_SRC_LRN_SUPPORT,
 	WMI_SERVICE_BB_TIMING_CONFIG_SUPPORT,
 	WMI_SERVICE_THERM_THROT,
+	WMI_SERVICE_SYNC_DELETE_CMDS,
 
 	/* keep last */
 	WMI_SERVICE_MAX,
@@ -483,6 +484,7 @@ static inline char *wmi_service_name(int service_id)
 	SVCSTR(WMI_SERVICE_RESET_CHIP);
 	SVCSTR(WMI_SERVICE_TX_DATA_ACK_RSSI);
 	SVCSTR(WMI_SERVICE_VDEV_DIFFERENT_BEACON_INTERVAL_SUPPORT);
+	SVCSTR(WMI_SERVICE_SYNC_DELETE_CMDS);
 	default:
 		return NULL;
 	}
-- 
2.7.4


^ permalink raw reply related

* Re: Kernel hangs on regulatory.db X.509 key initialization
From: Maciej S. Szmigiero @ 2019-02-17 12:29 UTC (permalink / raw)
  To: Dominik Schmidt; +Cc: linux-wireless, james.morris
In-Reply-To: <1549746752.q02fowo7n3.astroid@I7-2600.none>

Hi,

On 17.02.2019 10:38, Dominik Schmidt wrote:
> Hi there!
> 
> I'm running a Gentoo Linux on an APU2C2-Board (AMD Jaguar GX-412TC x86_64), with
> an Atheros QCA9882 (ath10k) and an Atheros AR9280 (ath9k) card.
> 
> The kernels after 4.18 do not reach userspace any longer. 

Did you test a more recent kernel like 4.20?

> They just somehow
> "freeze" without emitting any oops or kernel panic. I've tracked the issue
> down to the cfg80211 subsystem and a change in the X.509 parser:
> 
> * If I do not compile cfg80211 into the kernel, it starts perfectly (minus wireless)
> 
> * Bisecting the issue shows that it starts with
> 	https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b65c32ec5a942ab3ada93a048089a938918aba7f
> 
> * The last message I see in the logs is this one:
> 	cfg80211: Loading compiled-in X.509 certificates for regulatory database
>   defined at
> 	https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/wireless/reg.c#n770
> 
> * If I add another pr_notice to the end of that function, it is never displayed.
> 
> * It seems to get stuck at the call to key_create_or_update, here:
> 	https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/wireless/reg.c#n735
> 
> * If I throw more pr_notices at key_create_or_update, the last one I see 
>   is before this memset:
> 	https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/security/keys/key.c#n843
> 
> * As an additional hindrance, this problem occurs only on the APU2 board,
>   and not when running the same kernel in a Qemu-VM
> 
> Any idea what could be the cause of this, or hints as to how to
> debug this further?

I see that you are using an AMD CPU-based board, with AMD CCP enabled
in your kernel config.

Before my patch, that you bisected your problem to, such configuration
would fail (early) in-kernel X.509 certificate signature verification
as its length wasn't exactly correct.
Now, when this was fixed the CCP RSA implementation actually gets
exercised (however, it works for me without problems on Ryzen).

You can temporarily change CONFIG_CFG80211 in your kernel config to
'm' and compile the kernel with KASAN.
Don't load any wireless modules at startup, this should at least
defer the crash until you load them manually later when the system is
idle and you can monitor it.

If you are lucky KASAN will give you information then where the bug
might be.

> Cheers
> Dominik
> 

Maciej

^ permalink raw reply

* Re: [PATCH v2] wireless-regdb: Sync IN with G.S.R. 1048(E), October 2018
From: Seth Forshee @ 2019-02-17 10:55 UTC (permalink / raw)
  To: Felix Fietkau; +Cc: linux-wireless, Felix Fietkau, wireless-regdb
In-Reply-To: <20190209101947.4876-1-nbd@nbd.name>

On Sat, Feb 09, 2019 at 11:19:47AM +0100, Felix Fietkau wrote:
> From: Felix Fietkau <felix@wiowireless.com>
> 
> Add new frequency ranges, increase power, as documented in:
> http://wpc.dot.gov.in/WriteReadData/userfiles/License%20Exemption%20in%205%20GHz%20G_S_R_1048(E)%20dated%2022nd%20October,%202018.pdf
> 
> Signed-off-by: Felix Fietkau <felix@wiowireless.com>

Please also include wireless-regdb@lists.infradead.org on wireless-regdb
patches.

Applied, thanks!

^ permalink raw reply

* Re: [PATCH] wireless-regdb: update 60ghz band rules for us
From: Seth Forshee @ 2019-02-17 10:53 UTC (permalink / raw)
  To: Krishna Chaitanya; +Cc: wireless-regdb, linux-wireless
In-Reply-To: <CABPxzY+jbfoVGF_fta3reHa5yngmp_+dVKCiu3DR-8WzzxAPow@mail.gmail.com>

On Wed, Jan 23, 2019 at 04:19:26PM +0530, Krishna Chaitanya wrote:
> On Wed, Jan 23, 2019 at 2:43 AM Seth Forshee <seth.forshee@canonical.com> wrote:
> >
> > On Tue, Dec 18, 2018 at 01:38:15PM +0530, chaitanya.mgit@gmail.com wrote:
> > > From: Chaitanya Tata <Chaitanya.Mgit@gmail.com>
> > >
> > > Include channels 4, 5 & 6 for US in 60GHz band. FCC extended the
> > > 57-64GHz band till 71GHz with almost same rules.
> >
> > This looks right to me based on my research. You're missing one thing
> > though. You need to provide a Signed-off-by tag, please see the
> > CONTRIBUTING file for more information. If you reply with your tag I
> > will add it when I apply the patch. Thanks!
> 
> Sorry, didn't realize missed SO. You can use below. Thanks.
> Signed-off-by: Chaitanya Tata <Chaitanya.Tata@bluwireless.co.uk>

Sorry for the delay. Applied now, thanks!

^ permalink raw reply

* Kernel hangs on regulatory.db X.509 key initialization
From: Dominik Schmidt @ 2019-02-17  9:38 UTC (permalink / raw)
  To: linux-wireless; +Cc: mail, james.morris

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

Hi there!

I'm running a Gentoo Linux on an APU2C2-Board (AMD Jaguar GX-412TC x86_64), with
an Atheros QCA9882 (ath10k) and an Atheros AR9280 (ath9k) card.

The kernels after 4.18 do not reach userspace any longer. They just somehow
"freeze" without emitting any oops or kernel panic. I've tracked the issue
down to the cfg80211 subsystem and a change in the X.509 parser:

* If I do not compile cfg80211 into the kernel, it starts perfectly (minus wireless)

* Bisecting the issue shows that it starts with
	https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b65c32ec5a942ab3ada93a048089a938918aba7f

* The last message I see in the logs is this one:
	cfg80211: Loading compiled-in X.509 certificates for regulatory database
  defined at
	https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/wireless/reg.c#n770

* If I add another pr_notice to the end of that function, it is never displayed.

* It seems to get stuck at the call to key_create_or_update, here:
	https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/wireless/reg.c#n735

* If I throw more pr_notices at key_create_or_update, the last one I see 
  is before this memset:
	https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/security/keys/key.c#n843

* As an additional hindrance, this problem occurs only on the APU2 board,
  and not when running the same kernel in a Qemu-VM

Any idea what could be the cause of this, or hints as to how to
debug this further?

Cheers
Dominik

[-- Attachment #2: .config.bz2 --]
[-- Type: application/x-bzip, Size: 20579 bytes --]

^ permalink raw reply

* preparing for 802.11ah channels
From: thomas pedersen @ 2019-02-16 23:45 UTC (permalink / raw)
  To: linux-wireless

Hello,

I'm working on defining new channels for S1G PHYs in mac80211. These
are in the 900MHz range and center frequency for the 1MHz channels are
on a half MHz, while the existing channel definitions are in units of
MHz.

In order to support the new channels we could change the internal
center frequency units to KHz and extend the nl80211 API so
NL80211_FREQUENCY_ATTR_FREQ and NL80211_ATTR_WIPHY_FREQ get _KHZ
variants while renaming the original attributes to _MHZ to reflect the
units.

From looking at the code it looks like this should be fairly
straightforward, if involving a lot of changes since the driver
declarations would have to change too. Am I missing something
obviously wrong, or does this sound reasonable?

Thanks,

Thomas

^ permalink raw reply

* Re: [BUG] mt76x0u: Probing issues on Raspberry Pi 3 B+
From: Stefan Wahren @ 2019-02-16 19:17 UTC (permalink / raw)
  To: Stanislaw Gruszka
  Cc: Lorenzo Bianconi, Alan Stern, Felix Fietkau, Doug Anderson,
	Minas Harutyunyan, USB list, linux-wireless
In-Reply-To: <20190216140739.GA2236@redhat.com>

Hi Stanislaw,

> Stanislaw Gruszka <sgruszka@redhat.com> hat am 16. Februar 2019 um 15:07 geschrieben:
> 
> 
> On Sat, Feb 16, 2019 at 12:05:18PM +0100, Stefan Wahren wrote:
> > sorry for the delay, but i do this all in my spare time.
> 
> Stefan, thanks for sacrifing your spare time for testing this!
> 
> > The results for your recent patch series are better (no firmware timeout), but still no working wifi and still a warning:
> > https://gist.github.com/lategoodbye/c4864e446821717419cbe65df07f8d8d
> > 
> > I've identified the reason for the warning in dwc2:
> > 
> > /*
> >  * We assume that DMA is always aligned in non-split
> >  * case or split out case. Warn if not.
> >  */
> > WARN_ON_ONCE(hsotg->params.host_dma && (chan->xfer_dma & 0x3));
> 
> I think I understand why that happen, we first allocate 1024 mcu 
> buffer then standard 4096 rx buffers, that couse 4096 buffers are
> not contained in single page and need split by dwc2 driver.

this is a misunderstanding. The warning is about memory alignment to 32 bit addresses, not about page alignment. This is a typical ARM restriction. Maybe we need to make sure in mt76 that the DMA buffer needs to be aligned. But it's also possible that the warning isn't the root cause of our problem.

> 
> Attached patch should fix this, plese test, thanks in advance.

Anyway i tested the following patch combinations against next with the same results as 1,2,3 (no wifi, alignment warning):
1,3
1,2,3,4

> 
> > Btw i can confirm a regression was introduced after 4.19, because in 4.19 there was no firmware timeout but even no working wifi:
> 
> You ment 'no working wifi' or 'working wifi'?

Wifi is broken in 4.19, 4.20, 5.0 and next. It only worked with Lorenzo's SG avoid patches so far. Btw the regression (firmware timeout) started in 4.20. I also tested it today.

Thanks
Stefan

> 
> Stanislaw

^ permalink raw reply

* [PATCH 2/2] mt76: move txq qid dependency in driver specific code
From: lorenzo @ 2019-02-16 17:47 UTC (permalink / raw)
  To: nbd; +Cc: linux-wireless, sgruszka, ryder.lee, roychl666, Lorenzo Bianconi
In-Reply-To: <cover.1550336347.git.lorenzo@kernel.org>

From: Lorenzo Bianconi <lorenzo@kernel.org>

Move queue id dependency in driver specific tx queue initialization code
since new chipsets rely on a different tx queue enumeration scheme
Introduce mt76_sta_init_tx_queue utility routine

Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
 drivers/net/wireless/mediatek/mt76/mac80211.c | 27 ++++++++++++-------
 drivers/net/wireless/mediatek/mt76/mt76.h     | 12 ++++++++-
 .../net/wireless/mediatek/mt76/mt76x02_util.c |  2 ++
 drivers/net/wireless/mediatek/mt76/tx.c       | 16 +++--------
 4 files changed, 34 insertions(+), 23 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index c7abf4f54867..3d25b625b8cc 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -644,20 +644,12 @@ void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
 }
 EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
 
-static int
-mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif,
-	     struct ieee80211_sta *sta)
+void mt76_sta_init_tx_queue(struct mt76_dev *dev,
+			    struct ieee80211_sta *sta)
 {
 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
-	int ret;
 	int i;
 
-	mutex_lock(&dev->mutex);
-
-	ret = dev->drv->sta_add(dev, vif, sta);
-	if (ret)
-		goto out;
-
 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
 		struct mt76_txq *mtxq;
 
@@ -669,6 +661,21 @@ mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif,
 
 		mt76_txq_init(dev, sta->txq[i]);
 	}
+}
+EXPORT_SYMBOL_GPL(mt76_sta_init_tx_queue);
+
+static int
+mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif,
+	     struct ieee80211_sta *sta)
+{
+	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
+	int ret;
+
+	mutex_lock(&dev->mutex);
+
+	ret = dev->drv->sta_add(dev, vif, sta);
+	if (ret)
+		goto out;
 
 	ewma_signal_init(&wcid->rssi);
 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 53b85042b793..f6aab5ee782b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -639,6 +639,17 @@ static inline struct mt76_tx_cb *mt76_tx_skb_cb(struct sk_buff *skb)
 	return ((void *) IEEE80211_SKB_CB(skb)->status.status_driver_data);
 }
 
+void mt76_sta_init_tx_queue(struct mt76_dev *dev,
+			    struct ieee80211_sta *sta);
+void __mt76_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq, int qid);
+static inline void
+mt76_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq)
+{
+	int qid = txq->sta ? txq->ac : MT_TXQ_BE;
+
+	return __mt76_txq_init(dev, txq, qid);
+}
+
 int mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
 			  struct sk_buff *skb, struct mt76_wcid *wcid,
 			  struct ieee80211_sta *sta);
@@ -646,7 +657,6 @@ int mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
 void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb);
 void mt76_tx(struct mt76_dev *dev, struct ieee80211_sta *sta,
 	     struct mt76_wcid *wcid, struct sk_buff *skb, int qid);
-void mt76_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq);
 void mt76_txq_remove(struct mt76_dev *dev, struct ieee80211_txq *txq);
 void mt76_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
 void mt76_stop_tx_queues(struct mt76_dev *dev, struct ieee80211_sta *sta,
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
index 87ed00768bc7..c3a36519a942 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
@@ -251,6 +251,8 @@ int mt76x02_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
 	if (vif->type == NL80211_IFTYPE_AP)
 		set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags);
 
+	mt76_sta_init_tx_queue(mdev, sta);
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(mt76x02_sta_add);
diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c
index 3617de2c1325..142b12877a34 100644
--- a/drivers/net/wireless/mediatek/mt76/tx.c
+++ b/drivers/net/wireless/mediatek/mt76/tx.c
@@ -82,15 +82,6 @@ void mt76_tx_free(struct mt76_dev *dev)
 				 DMA_TO_DEVICE);
 }
 
-static int
-mt76_txq_get_qid(struct ieee80211_txq *txq)
-{
-	if (!txq->sta)
-		return MT_TXQ_BE;
-
-	return txq->ac;
-}
-
 static void
 mt76_check_agg_ssn(struct mt76_txq *mtxq, struct sk_buff *skb)
 {
@@ -604,16 +595,17 @@ void mt76_txq_remove(struct mt76_dev *dev, struct ieee80211_txq *txq)
 }
 EXPORT_SYMBOL_GPL(mt76_txq_remove);
 
-void mt76_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq)
+void __mt76_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq,
+		     int qid)
 {
 	struct mt76_txq *mtxq = (struct mt76_txq *) txq->drv_priv;
 
 	INIT_LIST_HEAD(&mtxq->list);
 	skb_queue_head_init(&mtxq->retry_q);
 
-	mtxq->hwq = &dev->q_tx[mt76_txq_get_qid(txq)];
+	mtxq->hwq = &dev->q_tx[qid];
 }
-EXPORT_SYMBOL_GPL(mt76_txq_init);
+EXPORT_SYMBOL_GPL(__mt76_txq_init);
 
 u8 mt76_ac_to_hwq(u8 ac)
 {
-- 
2.20.1


^ permalink raw reply related

* [PATCH 1/2] mt76: add qid parameter to mt76_tx signature
From: lorenzo @ 2019-02-16 17:47 UTC (permalink / raw)
  To: nbd; +Cc: linux-wireless, sgruszka, ryder.lee, roychl666, Lorenzo Bianconi
In-Reply-To: <cover.1550336347.git.lorenzo@kernel.org>

From: Lorenzo Bianconi <lorenzo@kernel.org>

Add queue id parameter to mt76_tx signature since new chipsets
rely on a different hw queue enumeration

Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
 drivers/net/wireless/mediatek/mt76/mt76.h         |  2 +-
 drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c |  8 +++++++-
 drivers/net/wireless/mediatek/mt76/tx.c           | 12 +++---------
 3 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 13f6febc9b0f..53b85042b793 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -645,7 +645,7 @@ int mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
 
 void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb);
 void mt76_tx(struct mt76_dev *dev, struct ieee80211_sta *sta,
-	     struct mt76_wcid *wcid, struct sk_buff *skb);
+	     struct mt76_wcid *wcid, struct sk_buff *skb, int qid);
 void mt76_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq);
 void mt76_txq_remove(struct mt76_dev *dev, struct ieee80211_txq *txq);
 void mt76_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c
index 94f47248c59f..fcabbd9c25f2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c
@@ -26,6 +26,7 @@ void mt76x02_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
 	struct mt76x02_dev *dev = hw->priv;
 	struct ieee80211_vif *vif = info->control.vif;
 	struct mt76_wcid *wcid = &dev->mt76.global_wcid;
+	int qid = skb_get_queue_mapping(skb);
 
 	if (control->sta) {
 		struct mt76x02_sta *msta;
@@ -39,7 +40,12 @@ void mt76x02_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
 		wcid = &mvif->group_wcid;
 	}
 
-	mt76_tx(&dev->mt76, control->sta, wcid, skb);
+	if (WARN_ON(qid >= MT_TXQ_PSD)) {
+		qid = MT_TXQ_BE;
+		skb_set_queue_mapping(skb, qid);
+	}
+
+	mt76_tx(&dev->mt76, control->sta, wcid, skb, qid);
 }
 EXPORT_SYMBOL_GPL(mt76x02_tx);
 
diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c
index ef38e8626da9..3617de2c1325 100644
--- a/drivers/net/wireless/mediatek/mt76/tx.c
+++ b/drivers/net/wireless/mediatek/mt76/tx.c
@@ -255,19 +255,13 @@ void mt76_tx_complete_skb(struct mt76_dev *dev, struct sk_buff *skb)
 }
 EXPORT_SYMBOL_GPL(mt76_tx_complete_skb);
 
-void
-mt76_tx(struct mt76_dev *dev, struct ieee80211_sta *sta,
-	struct mt76_wcid *wcid, struct sk_buff *skb)
+void mt76_tx(struct mt76_dev *dev, struct ieee80211_sta *sta,
+	     struct mt76_wcid *wcid, struct sk_buff *skb,
+	     int qid)
 {
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 	struct mt76_queue *q;
-	int qid = skb_get_queue_mapping(skb);
-
-	if (WARN_ON(qid >= MT_TXQ_PSD)) {
-		qid = MT_TXQ_BE;
-		skb_set_queue_mapping(skb, qid);
-	}
 
 	if (!wcid->tx_rate_set)
 		ieee80211_get_tx_rates(info->control.vif, sta, skb,
-- 
2.20.1


^ permalink raw reply related

* [PATCH 0/2] remove qid dependency from mt76-core code
From: lorenzo @ 2019-02-16 17:47 UTC (permalink / raw)
  To: nbd; +Cc: linux-wireless, sgruszka, ryder.lee, roychl666, Lorenzo Bianconi

From: Lorenzo Bianconi <lorenzo@kernel.org>

Move queue id dependency in driver specific tx queue initialization code
since new chipsets rely on a different tx queue enumeration scheme.
Add the possibility to specify qid in mt76_tx routine

Lorenzo Bianconi (2):
  mt76: add qid parameter to mt76_tx signature
  mt76: move txq qid dependency in driver specific code

 drivers/net/wireless/mediatek/mt76/mac80211.c | 27 +++++++++++-------
 drivers/net/wireless/mediatek/mt76/mt76.h     | 14 ++++++++--
 .../net/wireless/mediatek/mt76/mt76x02_txrx.c |  8 +++++-
 .../net/wireless/mediatek/mt76/mt76x02_util.c |  2 ++
 drivers/net/wireless/mediatek/mt76/tx.c       | 28 +++++--------------
 5 files changed, 45 insertions(+), 34 deletions(-)

-- 
2.20.1


^ permalink raw reply

* Re: [BUG] mt76x0u: Probing issues on Raspberry Pi 3 B+
From: Stanislaw Gruszka @ 2019-02-16 14:07 UTC (permalink / raw)
  To: Stefan Wahren
  Cc: Lorenzo Bianconi, Alan Stern, Felix Fietkau, Doug Anderson,
	Minas Harutyunyan, USB list, linux-wireless
In-Reply-To: <1411983628.668277.1550315118443@email.ionos.de>

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

On Sat, Feb 16, 2019 at 12:05:18PM +0100, Stefan Wahren wrote:
> sorry for the delay, but i do this all in my spare time.

Stefan, thanks for sacrifing your spare time for testing this!

> The results for your recent patch series are better (no firmware timeout), but still no working wifi and still a warning:
> https://gist.github.com/lategoodbye/c4864e446821717419cbe65df07f8d8d
> 
> I've identified the reason for the warning in dwc2:
> 
> /*
>  * We assume that DMA is always aligned in non-split
>  * case or split out case. Warn if not.
>  */
> WARN_ON_ONCE(hsotg->params.host_dma && (chan->xfer_dma & 0x3));

I think I understand why that happen, we first allocate 1024 mcu 
buffer then standard 4096 rx buffers, that couse 4096 buffers are
not contained in single page and need split by dwc2 driver.

Attached patch should fix this, plese test, thanks in advance.

> Btw i can confirm a regression was introduced after 4.19, because in 4.19 there was no firmware timeout but even no working wifi:

You ment 'no working wifi' or 'working wifi'?

Stanislaw

[-- Attachment #2: 0004-mt76usb-allocate-page-contained-rx-buffers.patch --]
[-- Type: text/plain, Size: 5102 bytes --]

From 35dadd09bd3193b33b10f56e0210da680c6d915f Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Sat, 16 Feb 2019 14:53:19 +0100
Subject: [PATCH] mt76usb: allocate page contained rx buffers

If we first allocate 1024 bytes buffer and then 4096 bytes
buffer via page_frag_alloc() the second buffer will be crossing
page boundaries what is most likely not appropriate for
dma_map_{sg/page} and make buffer split misalign issues on
dwc2 usb host driver.

Since patch changed arguments of mt76u_buf_alloc() function I also
changed name to indicate it is only used for RX allocation.

Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
 drivers/net/wireless/mediatek/mt76/mt76.h    |  5 ++---
 drivers/net/wireless/mediatek/mt76/usb.c     | 24 ++++++++++--------------
 drivers/net/wireless/mediatek/mt76/usb_mcu.c |  4 +---
 3 files changed, 13 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 364f3571c033..9e24f603664a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -364,7 +364,6 @@ enum mt76u_out_ep {
 #define MT_SG_MAX_SIZE		8
 #define MT_NUM_TX_ENTRIES	256
 #define MT_NUM_RX_ENTRIES	128
-#define MCU_RESP_URB_SIZE	1024
 struct mt76_usb {
 	struct mutex usb_ctrl_mtx;
 	u8 data[32];
@@ -753,8 +752,8 @@ void mt76u_single_wr(struct mt76_dev *dev, const u8 req,
 		     const u16 offset, const u32 val);
 int mt76u_init(struct mt76_dev *dev, struct usb_interface *intf);
 void mt76u_deinit(struct mt76_dev *dev);
-int mt76u_buf_alloc(struct mt76_dev *dev, struct mt76u_buf *buf,
-		    int nsgs, int len, int sglen, gfp_t gfp);
+int mt76u_rx_buf_alloc(struct mt76_dev *dev, struct mt76u_buf *buf, int nsgs,
+		       gfp_t gfp);
 void mt76u_buf_free(struct mt76u_buf *buf);
 int mt76u_submit_buf(struct mt76_dev *dev, int dir, int index,
 		     struct mt76u_buf *buf, gfp_t gfp,
diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c
index de906f07e85a..472642ef25a4 100644
--- a/drivers/net/wireless/mediatek/mt76/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/usb.c
@@ -271,11 +271,11 @@ mt76u_set_endpoints(struct usb_interface *intf,
 }
 
 static int
-mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76u_buf *buf,
-		 int nsgs, int len, int sglen)
+mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76u_buf *buf, int nsgs)
 {
 	struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN];
 	struct urb *urb = buf->urb;
+	int sglen = SKB_WITH_OVERHEAD(q->buf_size);
 	int i;
 
 	spin_lock_bh(&q->rx_page_lock);
@@ -284,7 +284,7 @@ mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76u_buf *buf,
 		void *data;
 		int offset;
 
-		data = page_frag_alloc(&q->rx_page, len, GFP_ATOMIC);
+		data = page_frag_alloc(&q->rx_page, q->buf_size, GFP_ATOMIC);
 		if (!data)
 			break;
 
@@ -309,8 +309,8 @@ mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76u_buf *buf,
 	return i ? : -ENOMEM;
 }
 
-int mt76u_buf_alloc(struct mt76_dev *dev, struct mt76u_buf *buf,
-		    int nsgs, int len, int sglen, gfp_t gfp)
+int mt76u_rx_buf_alloc(struct mt76_dev *dev, struct mt76u_buf *buf,
+		       int nsgs, gfp_t gfp)
 {
 	buf->urb = usb_alloc_urb(0, gfp);
 	if (!buf->urb)
@@ -325,7 +325,7 @@ int mt76u_buf_alloc(struct mt76_dev *dev, struct mt76u_buf *buf,
 	buf->dev = dev;
 	buf->num_sgs = nsgs;
 
-	return mt76u_fill_rx_sg(dev, buf, nsgs, len, sglen);
+	return mt76u_fill_rx_sg(dev, buf, nsgs);
 }
 
 void mt76u_buf_free(struct mt76u_buf *buf)
@@ -485,7 +485,7 @@ static void mt76u_rx_tasklet(unsigned long data)
 {
 	struct mt76_dev *dev = (struct mt76_dev *)data;
 	struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN];
-	int err, nsgs, buf_len = q->buf_size;
+	int err, nsgs;
 	struct mt76u_buf *buf;
 
 	rcu_read_lock();
@@ -497,9 +497,7 @@ static void mt76u_rx_tasklet(unsigned long data)
 
 		nsgs = mt76u_process_rx_entry(dev, buf->urb);
 		if (nsgs > 0) {
-			err = mt76u_fill_rx_sg(dev, buf, nsgs,
-					       buf_len,
-					       SKB_WITH_OVERHEAD(buf_len));
+			err = mt76u_fill_rx_sg(dev, buf, nsgs);
 			if (err < 0)
 				break;
 		}
@@ -556,10 +554,8 @@ static int mt76u_alloc_rx(struct mt76_dev *dev)
 	}
 
 	for (i = 0; i < MT_NUM_RX_ENTRIES; i++) {
-		err = mt76u_buf_alloc(dev, &q->entry[i].ubuf,
-				      nsgs, q->buf_size,
-				      SKB_WITH_OVERHEAD(q->buf_size),
-				      GFP_KERNEL);
+		err = mt76u_rx_buf_alloc(dev, &q->entry[i].ubuf, nsgs,
+					 GFP_KERNEL);
 		if (err < 0)
 			return err;
 	}
diff --git a/drivers/net/wireless/mediatek/mt76/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/usb_mcu.c
index 036be4163e69..7c43738f5a6e 100644
--- a/drivers/net/wireless/mediatek/mt76/usb_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/usb_mcu.c
@@ -29,9 +29,7 @@ int mt76u_mcu_init_rx(struct mt76_dev *dev)
 	struct mt76_usb *usb = &dev->usb;
 	int err;
 
-	err = mt76u_buf_alloc(dev, &usb->mcu.res, 1,
-			      MCU_RESP_URB_SIZE, MCU_RESP_URB_SIZE,
-			      GFP_KERNEL);
+	err = mt76u_rx_buf_alloc(dev, &usb->mcu.res, 1, GFP_KERNEL);
 	if (err < 0)
 		return err;
 
-- 
2.7.5


^ permalink raw reply related

* -Wimplicit-fallthrough not working with ccache
From: Kalle Valo @ 2019-02-16 11:21 UTC (permalink / raw)
  To: Gustavo A. R. Silva
  Cc: netdev, linux-wireless, linux-kernel, ath10k, David S. Miller,
	linux-kbuild
In-Reply-To: <20180613114059.DAC95601D2@smtp.codeaurora.org>

(replying to an old thread but renaming it)

Kalle Valo <kvalo@codeaurora.org> writes:

> "Gustavo A. R. Silva" <gustavo@embeddedor.com> wrote:
>
>> In preparation to enabling -Wimplicit-fallthrough, mark switch cases
>> where we are expecting to fall through.
>> 
>> Notice that in this particular case, I replaced "pass through" with
>> a proper "fall through" comment, which is what GCC is expecting
>> to find.
>> 
>> Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
>> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
>
> Patch applied to ath-next branch of ath.git, thanks.
>
> f1d270ae10ff ath10k: htt_tx: mark expected switch fall-throughs

Gustavo, I enabled W=1 on my ath10k build checks and it took me a while
to figure out why GCC was warning about fall through annotations missing
even I knew you had fixed them. Finally I figured out that the reason
was ccache, which I need because I work with different branches and need
to recompile the kernel quite often.

If the plan is to enable -Wimplicit-fallthrough by default in the kernel
IMHO this might become an issue, as otherwise people using ccache start
seeing lots of invalid warnings. Apparently CCACHE_COMMENTS=1 will fix
that but my version of ccache doesn't support it, and how would everyone
learn that trick anyway? Or maybe CCACHE_COMMENTS can enabled through
kernel Makefile?

-- 
Kalle Valo

^ permalink raw reply

* Re: [BUG] mt76x0u: Probing issues on Raspberry Pi 3 B+
From: Stefan Wahren @ 2019-02-16 11:05 UTC (permalink / raw)
  To: Stanislaw Gruszka
  Cc: Lorenzo Bianconi, Alan Stern, Felix Fietkau, Doug Anderson,
	Minas Harutyunyan, USB list, linux-wireless
In-Reply-To: <20190215071226.GA2372@redhat.com>

Hi Stanislaw,

> Stanislaw Gruszka <sgruszka@redhat.com> hat am 15. Februar 2019 um 08:12 geschrieben:
> 
> 
> On Thu, Feb 14, 2019 at 10:48:15AM +0100, Stefan Wahren wrote:
> > Hi Stanislaw,
> > 
> > Am 14.02.19 um 10:25 schrieb Stanislaw Gruszka:
> > > On Thu, Feb 14, 2019 at 07:49:57AM +0100, Stefan Wahren wrote:
> > >> Hi Stanislaw,
> > >>
> > >>> Stanislaw Gruszka <sgruszka@redhat.com> hat am 12. Februar 2019 um 10:30 geschrieben:
> > >>>
> > >>>
> > >>>
> > >>> In usb_sg_init() urb->num_sgs is set 0 for sg_tablesize = 0 controllers.
> > >>> In mt76 we set urb->num_sgs to 1. I thought it is fine, but now I think
> > >>> this is bug. We can fix that without changing allocation method and
> > >>> still use SG allocation. Attached patch do this, please check if it works
> > >>> on rpi. Patch is on top of your error path fixes.
> > >> your patch didn't apply cleanly to yesterdays next. After some minor manual fixup, i was able to build them and here are the results starting from boot (please ignore the invalid time in the kernel log):
> > >> https://gist.github.com/lategoodbye/33bd5bc75b9fc935faa231bc472defa8
> > > I think this is due to urb->transfer_length and sg[0]->length mismatch,
> > > which should be addressed by my other patch. I'm attaching the patch
> > > rebased on -next with this line integrated, please test. 
> > >
> > > But there could be other bug's in mt76-usb SG code.
> 
> I found another bug in mt76usb SG code. We set sg->offset bigger than
> PAGE_SIZE that actually make sg point to memory in different page than
> sg->page. Correcting this with another patch that avoid using sg
> mapping with sg->length > PAGE_SIZE, fixed mt76x0u with AMD IOMMU:
> https://bugzilla.kernel.org/show_bug.cgi?id=202241
> 
> I'm attaching 3 patches, they should also fix issue on rpi.
> It's also possible that only 2 patches are sufficient:
> 
> 0001-mt76usb-do-not-set-urb-num_sgs-to-1-for-non-SG-usb-h.patch
> 0003-mt76usb-do-not-use-compound-head-page-for-SG-I-O.patch
> 
> to fix the issue, if doing dma_map_{page,sg} is fine with
> sg->offset == 0 and sg->length bigger than one page.
> 
> Please test, thanks.
> 

sorry for the delay, but i do this all in my spare time.

The results for your recent patch series are better (no firmware timeout), but still no working wifi and still a warning:
https://gist.github.com/lategoodbye/c4864e446821717419cbe65df07f8d8d

I've identified the reason for the warning in dwc2:

/*
 * We assume that DMA is always aligned in non-split
 * case or split out case. Warn if not.
 */
WARN_ON_ONCE(hsotg->params.host_dma && (chan->xfer_dma & 0x3));

Btw i can confirm a regression was introduced after 4.19, because in 4.19 there was no firmware timeout but even no working wifi:

Feb 15 19:10:51 raspberrypi kernel: [   79.818414] usb 1-1.3: new high-speed USB device number 6 using dwc2
Feb 15 19:10:51 raspberrypi kernel: [   80.178470] usb 1-1.3: reset high-speed USB device number 6 using dwc2
Feb 15 19:10:51 raspberrypi kernel: [   80.314388] mt76x0 1-1.3:1.0: ASIC revision: 76100002 MAC revision: 76502000
Feb 15 19:10:52 raspberrypi kernel: [   81.118751] BBP version f000f200
Feb 15 19:10:52 raspberrypi kernel: [   81.152995] mt76x0 1-1.3:1.0: EEPROM ver:02 fae:01
Feb 15 19:10:52 raspberrypi kernel: [   81.153232] mt76x0 1-1.3:1.0: EEPROM country region 01 (channels 1-13)
Feb 15 19:10:52 raspberrypi kernel: [   81.176968] ieee80211 phy0: Selected rate control algorithm 'minstrel_ht'
Feb 15 19:10:52 raspberrypi kernel: [   81.178255] usbcore: registered new interface driver mt76x0
Feb 15 19:10:53 raspberrypi kernel: [   81.578982] IPv6: ADDRCONF(NETDEV_UP): wlan0: link is not ready

Stefan

> Stanislaw

^ permalink raw reply

* [PATCH net-next] cfg80211: pmsr: use eth_broadcast_addr() to assign broadcast address
From: Mao Wenan @ 2019-02-16  9:47 UTC (permalink / raw)
  To: johannes, linux-wireless, kernel-janitors, netdev

This patch is to use eth_broadcast_addr() to assign broadcast address
insetad of memset().

Signed-off-by: Mao Wenan <maowenan@huawei.com>
---
 net/wireless/pmsr.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/wireless/pmsr.c b/net/wireless/pmsr.c
index de9286703280..21139b82749f 100644
--- a/net/wireless/pmsr.c
+++ b/net/wireless/pmsr.c
@@ -258,7 +258,7 @@ int nl80211_pmsr_start(struct sk_buff *skb, struct genl_info *info)
 	} else {
 		memcpy(req->mac_addr, nla_data(info->attrs[NL80211_ATTR_MAC]),
 		       ETH_ALEN);
-		memset(req->mac_addr_mask, 0xff, ETH_ALEN);
+		eth_broadcast_addr(req->mac_addr_mask);
 	}
 
 	idx = 0;
-- 
2.20.1


^ permalink raw reply related

* Re: [PATCH] cfg80211/nl80211: Offload OWE processing to user space in AP mode
From: Sergey Matyukevich @ 2019-02-16  4:11 UTC (permalink / raw)
  To: Srinivas Dasari
  Cc: johannes@sipsolutions.net, linux-wireless@vger.kernel.org,
	Sunil Dutt, Liangwei Dong
In-Reply-To: <1550258078-13504-1-git-send-email-dasaris@codeaurora.org>

Hi Srinivas,

>  include/net/cfg80211.h       | 42 ++++++++++++++++++++++++++
>  include/uapi/linux/nl80211.h |  7 +++++
>  net/wireless/nl80211.c       | 72 ++++++++++++++++++++++++++++++++++++++++++++
>  net/wireless/rdev-ops.h      | 13 ++++++++
>  net/wireless/trace.h         | 38 +++++++++++++++++++++++
>  5 files changed, 172 insertions(+)

...

> +void cfg80211_update_owe_info_event(struct net_device *netdev,
> +                                   struct cfg80211_update_owe_info *owe_info,
> +                                   gfp_t gfp)
> +{
> +       struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy;
> +       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
> +       struct sk_buff *msg;
> +       void *hdr;
> +
> +       trace_cfg80211_update_owe_info_event(wiphy, netdev, owe_info);
> +
> +       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
> +       if (!msg)
> +               return;
> +
> +       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_UPDATE_OWE_INFO);
> +       if (!hdr)
> +               goto nla_put_failure;
> +
> +       if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
> +           nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
> +           nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, owe_info->peer))
> +               goto nla_put_failure;
> +
> +       if (nla_put(msg, NL80211_ATTR_IE, owe_info->ie_len, owe_info->ie))
> +               goto nla_put_failure;

Maybe worth adding sanity check if IE length is non-zero ?


Reviewed-by: Sergey Matyukevich <sergey.matyukevich.os@quantenna.com>

Regards,
Sergey

^ permalink raw reply

* Re: pull-request: mac80211 2019-02-15
From: David Miller @ 2019-02-16  3:42 UTC (permalink / raw)
  To: johannes; +Cc: netdev, linux-wireless
In-Reply-To: <20190215125146.18856-1-johannes@sipsolutions.net>

From: Johannes Berg <johannes@sipsolutions.net>
Date: Fri, 15 Feb 2019 13:51:45 +0100

> It's clear things are winding down, this is basically just the stuff
> from Herbert that we've been discussing. I threw in a simple error
> path fix, mostly because it's simple :-)
> 
> Please pull and let me know if there's any problem.

Ok, pulled, thanks Johannes.

^ permalink raw reply

* Re: [Make-wifi-fast] [RFC/RFT] mac80211: Switch to a virtual time-based airtime scheduler
From: Dave Taht @ 2019-02-15 19:44 UTC (permalink / raw)
  To: Toke Høiland-Jørgensen
  Cc: Make-Wifi-fast, linux-wireless, Kan Yan, Rajkumar Manoharan,
	Felix Fietkau
In-Reply-To: <20190215170512.31512-1-toke@redhat.com>

On Fri, Feb 15, 2019 at 9:05 AM Toke Høiland-Jørgensen <toke@redhat.com> wrote:
>
> This switches the airtime scheduler in mac80211 to use a virtual time-based
> scheduler instead of the round-robin scheduler used before. This has a
> couple of advantages:
>
> - No need to sync up the round-robin scheduler in firmware/hardware with
>   the round-robin airtime scheduler.
>
> - If several stations are eligible for transmission we can schedule both of
>   them; no need to hard-block the scheduling rotation until the head of the
>   queue has used up its quantum.

This sounds like this will support some concepts in 802.11ax much better?

Do we have any feedback from ax folk (any platform - qca, intel,
mediatek, broadcom) as to whether this will help?

> - The check of whether a station is eligible for transmission becomes
>   simpler (in ieee80211_txq_may_transmit()).
>
> The drawback is that scheduling becomes slightly more expensive, as we need
> to maintain an rbtree of TXQs sorted by virtual time. This means that
> ieee80211_register_airtime() becomes O(logN) in the number of currently
> scheduled TXQs. However, hopefully this number rarely grows too big (it's
> only TXQs currently backlogged, not all associated stations), so it
> shouldn't be too big of an issue.

SGTM.

> Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
> ---
> This is basically the idea I mentioned earlier for a different way to
> handle the airtime scheduling.
>
> I've tested it on ath9k, where it achieves the same fairness and
> weighing properties as the old scheduler. It would be good if you could
> test it on your ath10k setup, Rajkumar; and all of you please comment on
> whether you agree that this is better from an API point of view.
>
>  net/mac80211/debugfs.c     |  49 ++++++++-
>  net/mac80211/debugfs_sta.c |  16 +--
>  net/mac80211/ieee80211_i.h |  15 ++-
>  net/mac80211/main.c        |   2 +-
>  net/mac80211/sta_info.c    |  19 +++-
>  net/mac80211/sta_info.h    |   3 +-
>  net/mac80211/tx.c          | 217 ++++++++++++++++++++++++-------------
>  7 files changed, 225 insertions(+), 96 deletions(-)
>
> diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
> index 343ad0a915e4..93b9ed2f9451 100644
> --- a/net/mac80211/debugfs.c
> +++ b/net/mac80211/debugfs.c
> @@ -150,6 +150,47 @@ static const struct file_operations aqm_ops = {
>         .llseek = default_llseek,
>  };
>
> +static ssize_t airtime_read(struct file *file,
> +                           char __user *user_buf,
> +                           size_t count,
> +                           loff_t *ppos)
> +{
> +       struct ieee80211_local *local = file->private_data;
> +       char buf[200];
> +       u64 v_t[IEEE80211_NUM_ACS];
> +       u64 wt[IEEE80211_NUM_ACS];
> +       int len = 0, ac;
> +
> +       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
> +               spin_lock_bh(&local->active_txq_lock[ac]);
> +               v_t[ac] = local->airtime_v_t[ac];
> +               wt[ac] = local->airtime_weight_sum[ac];
> +               spin_unlock_bh(&local->active_txq_lock[ac]);
> +       }
> +       len = scnprintf(buf, sizeof(buf),
> +                       "\tVO         VI         BE         BK\n"
> +                       "Virt-t\t%-10llu %-10llu %-10llu %-10llu\n"
> +                       "Weight\t%-10llu %-10llu %-10llu %-10llu\n",
> +                       v_t[0],
> +                       v_t[1],
> +                       v_t[2],
> +                       v_t[3],
> +                       wt[0],
> +                       wt[1],
> +                       wt[2],
> +                       wt[3]);
> +
> +       return simple_read_from_buffer(user_buf, count, ppos,
> +                                      buf, len);
> +}
> +
> +static const struct file_operations airtime_ops = {
> +       .read = airtime_read,
> +       .open = simple_open,
> +       .llseek = default_llseek,
> +};
> +
> +
>  #ifdef CONFIG_PM
>  static ssize_t reset_write(struct file *file, const char __user *user_buf,
>                            size_t count, loff_t *ppos)
> @@ -384,8 +425,12 @@ void debugfs_hw_add(struct ieee80211_local *local)
>         if (local->ops->wake_tx_queue)
>                 DEBUGFS_ADD_MODE(aqm, 0600);
>
> -       debugfs_create_u16("airtime_flags", 0600,
> -                          phyd, &local->airtime_flags);
> +       if (wiphy_ext_feature_isset(local->hw.wiphy,
> +                                   NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) {
> +               DEBUGFS_ADD_MODE(airtime, 0600);
> +               debugfs_create_u16("airtime_flags", 0600,
> +                                  phyd, &local->airtime_flags);
> +       }
>
>         statsd = debugfs_create_dir("statistics", phyd);
>
> diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
> index 3aa618dcc58e..80028da27b98 100644
> --- a/net/mac80211/debugfs_sta.c
> +++ b/net/mac80211/debugfs_sta.c
> @@ -203,7 +203,7 @@ static ssize_t sta_airtime_read(struct file *file, char __user *userbuf,
>         size_t bufsz = 200;
>         char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf;
>         u64 rx_airtime = 0, tx_airtime = 0;
> -       s64 deficit[IEEE80211_NUM_ACS];
> +       u64 v_t[IEEE80211_NUM_ACS];
>         ssize_t rv;
>         int ac;
>
> @@ -214,20 +214,20 @@ static ssize_t sta_airtime_read(struct file *file, char __user *userbuf,
>                 spin_lock_bh(&local->active_txq_lock[ac]);
>                 rx_airtime += sta->airtime[ac].rx_airtime;
>                 tx_airtime += sta->airtime[ac].tx_airtime;
> -               deficit[ac] = sta->airtime[ac].deficit;
> +               v_t[ac] = sta->airtime[ac].v_t;
>                 spin_unlock_bh(&local->active_txq_lock[ac]);
>         }
>
>         p += scnprintf(p, bufsz + buf - p,
>                 "RX: %llu us\nTX: %llu us\nWeight: %u\n"
> -               "Deficit: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n",
> +               "Virt-T: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n",
>                 rx_airtime,
>                 tx_airtime,
>                 sta->airtime_weight,
> -               deficit[0],
> -               deficit[1],
> -               deficit[2],
> -               deficit[3]);
> +               v_t[0],
> +               v_t[1],
> +               v_t[2],
> +               v_t[3]);
>
>         rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
>         kfree(buf);
> @@ -245,7 +245,7 @@ static ssize_t sta_airtime_write(struct file *file, const char __user *userbuf,
>                 spin_lock_bh(&local->active_txq_lock[ac]);
>                 sta->airtime[ac].rx_airtime = 0;
>                 sta->airtime[ac].tx_airtime = 0;
> -               sta->airtime[ac].deficit = sta->airtime_weight;
> +               sta->airtime[ac].v_t = 0;
>                 spin_unlock_bh(&local->active_txq_lock[ac]);
>         }
>
> diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
> index 056b16bce3b0..994a70ee0ec0 100644
> --- a/net/mac80211/ieee80211_i.h
> +++ b/net/mac80211/ieee80211_i.h
> @@ -840,8 +840,7 @@ struct txq_info {
>         struct codel_vars def_cvars;
>         struct codel_stats cstats;
>         struct sk_buff_head frags;
> -       struct list_head schedule_order;
> -       u16 schedule_round;
> +       struct rb_node schedule_order;
>         unsigned long flags;
>
>         /* keep last! */
> @@ -1135,8 +1134,10 @@ struct ieee80211_local {
>
>         /* protects active_txqs and txqi->schedule_order */
>         spinlock_t active_txq_lock[IEEE80211_NUM_ACS];
> -       struct list_head active_txqs[IEEE80211_NUM_ACS];
> -       u16 schedule_round[IEEE80211_NUM_ACS];
> +       struct rb_root_cached active_txqs[IEEE80211_NUM_ACS];
> +       struct rb_node *schedule_pos[IEEE80211_NUM_ACS];
> +       u64 airtime_v_t[IEEE80211_NUM_ACS];
> +       u64 airtime_weight_sum[IEEE80211_NUM_ACS];
>
>         u16 airtime_flags;
>
> @@ -1765,6 +1766,12 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
>                               const u8 *buf, size_t len,
>                               const u8 *dest, __be16 proto, bool unencrypted);
>
> +void ieee80211_resort_txq(struct ieee80211_hw *hw,
> +                         struct ieee80211_txq *txq);
> +void ieee80211_unschedule_txq(struct ieee80211_hw *hw,
> +                             struct ieee80211_txq *txq);
> +
> +
>  /* HT */
>  void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
>                                      struct ieee80211_sta_ht_cap *ht_cap);
> diff --git a/net/mac80211/main.c b/net/mac80211/main.c
> index 71005b6dfcd1..f207bc284921 100644
> --- a/net/mac80211/main.c
> +++ b/net/mac80211/main.c
> @@ -666,7 +666,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
>         spin_lock_init(&local->queue_stop_reason_lock);
>
>         for (i = 0; i < IEEE80211_NUM_ACS; i++) {
> -               INIT_LIST_HEAD(&local->active_txqs[i]);
> +               local->active_txqs[i] = RB_ROOT_CACHED;
>                 spin_lock_init(&local->active_txq_lock[i]);
>         }
>         local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX;
> diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
> index 11f058987a54..9d01fdd86e2d 100644
> --- a/net/mac80211/sta_info.c
> +++ b/net/mac80211/sta_info.c
> @@ -389,7 +389,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
>         for (i = 0; i < IEEE80211_NUM_ACS; i++) {
>                 skb_queue_head_init(&sta->ps_tx_buf[i]);
>                 skb_queue_head_init(&sta->tx_filtered[i]);
> -               sta->airtime[i].deficit = sta->airtime_weight;
>         }
>
>         for (i = 0; i < IEEE80211_NUM_TIDS; i++)
> @@ -1831,18 +1830,32 @@ void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid,
>  {
>         struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
>         struct ieee80211_local *local = sta->sdata->local;
> +       struct ieee80211_txq *txq = sta->sta.txq[tid];
>         u8 ac = ieee80211_ac_from_tid(tid);
> -       u32 airtime = 0;
> +       u64 airtime = 0, weight_sum;
> +
> +       if (!txq)
> +               return;
>
>         if (sta->local->airtime_flags & AIRTIME_USE_TX)
>                 airtime += tx_airtime;
>         if (sta->local->airtime_flags & AIRTIME_USE_RX)
>                 airtime += rx_airtime;
>
> +       /* Weights scale so the unit weight is 256 */
> +       airtime <<= 8;
> +
>         spin_lock_bh(&local->active_txq_lock[ac]);
> +
>         sta->airtime[ac].tx_airtime += tx_airtime;
>         sta->airtime[ac].rx_airtime += rx_airtime;
> -       sta->airtime[ac].deficit -= airtime;
> +
> +       weight_sum = local->airtime_weight_sum[ac] ?: sta->airtime_weight;
> +
> +       local->airtime_v_t[ac] += airtime / weight_sum;
> +       sta->airtime[ac].v_t += airtime / sta->airtime_weight;
> +       ieee80211_resort_txq(&local->hw, txq);
> +
>         spin_unlock_bh(&local->active_txq_lock[ac]);
>  }
>  EXPORT_SYMBOL(ieee80211_sta_register_airtime);
> diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
> index 05647d835894..4b901a2a998e 100644
> --- a/net/mac80211/sta_info.h
> +++ b/net/mac80211/sta_info.h
> @@ -130,11 +130,12 @@ enum ieee80211_agg_stop_reason {
>  /* Debugfs flags to enable/disable use of RX/TX airtime in scheduler */
>  #define AIRTIME_USE_TX         BIT(0)
>  #define AIRTIME_USE_RX         BIT(1)
> +#define AIRTIME_GRACE 500 /* usec of grace period before reset */
>
>  struct airtime_info {
>         u64 rx_airtime;
>         u64 tx_airtime;
> -       s64 deficit;
> +       u64 v_t;
>  };
>
>  struct sta_info;
> diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
> index 61c7ea9de2cc..8e125df8ade0 100644
> --- a/net/mac80211/tx.c
> +++ b/net/mac80211/tx.c
> @@ -1449,7 +1449,7 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
>         codel_vars_init(&txqi->def_cvars);
>         codel_stats_init(&txqi->cstats);
>         __skb_queue_head_init(&txqi->frags);
> -       INIT_LIST_HEAD(&txqi->schedule_order);
> +       RB_CLEAR_NODE(&txqi->schedule_order);
>
>         txqi->txq.vif = &sdata->vif;
>
> @@ -1493,9 +1493,7 @@ void ieee80211_txq_purge(struct ieee80211_local *local,
>         ieee80211_purge_tx_queue(&local->hw, &txqi->frags);
>         spin_unlock_bh(&fq->lock);
>
> -       spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]);
> -       list_del_init(&txqi->schedule_order);
> -       spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]);
> +       ieee80211_unschedule_txq(&local->hw, &txqi->txq);
>  }
>
>  void ieee80211_txq_set_params(struct ieee80211_local *local)
> @@ -3640,126 +3638,191 @@ EXPORT_SYMBOL(ieee80211_tx_dequeue);
>  struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
>  {
>         struct ieee80211_local *local = hw_to_local(hw);
> +       struct rb_node *node = local->schedule_pos[ac];
>         struct txq_info *txqi = NULL;
> +       bool first = false;
>
>         lockdep_assert_held(&local->active_txq_lock[ac]);
>
> - begin:
> -       txqi = list_first_entry_or_null(&local->active_txqs[ac],
> -                                       struct txq_info,
> -                                       schedule_order);
> -       if (!txqi)
> +       if (!node) {
> +               node = rb_first_cached(&local->active_txqs[ac]);
> +               first = true;
> +       } else
> +               node = rb_next(node);
> +
> +       if (!node)
>                 return NULL;
>
> +       txqi = container_of(node, struct txq_info, schedule_order);
> +
>         if (txqi->txq.sta) {
>                 struct sta_info *sta = container_of(txqi->txq.sta,
>                                                 struct sta_info, sta);
>
> -               if (sta->airtime[txqi->txq.ac].deficit < 0) {
> -                       sta->airtime[txqi->txq.ac].deficit +=
> -                               sta->airtime_weight;
> -                       list_move_tail(&txqi->schedule_order,
> -                                      &local->active_txqs[txqi->txq.ac]);
> -                       goto begin;
> +               if (sta->airtime[ac].v_t > local->airtime_v_t[ac]) {
> +                       if (first)
> +                               local->airtime_v_t[ac] = sta->airtime[ac].v_t;
> +                       else
> +                               return NULL;
>                 }
>         }
>
>
> -       if (txqi->schedule_round == local->schedule_round[ac])
> -               return NULL;
> -
> -       list_del_init(&txqi->schedule_order);
> -       txqi->schedule_round = local->schedule_round[ac];
> +       local->schedule_pos[ac] = node;
>         return &txqi->txq;
>  }
>  EXPORT_SYMBOL(ieee80211_next_txq);
>
> -void ieee80211_return_txq(struct ieee80211_hw *hw,
> +static void __ieee80211_insert_txq(struct rb_root_cached *root,
> +                                  struct txq_info *txqi, u8 ac)
> +{
> +       struct rb_node **new = &root->rb_root.rb_node;
> +       struct rb_node *parent = NULL;
> +       struct txq_info *__txqi;
> +       bool leftmost = true;
> +
> +       while (*new) {
> +               parent = *new;
> +               __txqi = rb_entry(parent, struct txq_info, schedule_order);
> +
> +               if (!txqi->txq.sta) {
> +                       /* new txqi has no sta - insert to the left */
> +                       new = &parent->rb_left;
> +               } else if (!__txqi->txq.sta) {
> +                       /* existing txqi has no sta - insert to the right */
> +                       new = &parent->rb_right;
> +                       leftmost = false;
> +               } else {
> +                       struct sta_info *old_sta = container_of(__txqi->txq.sta,
> +                                                               struct sta_info,
> +                                                               sta);
> +                       struct sta_info *new_sta = container_of(txqi->txq.sta,
> +                                                               struct sta_info,
> +                                                               sta);
> +
> +                       if (new_sta->airtime[ac].v_t <= old_sta->airtime[ac].v_t)
> +                               new = &parent->rb_left;
> +                       else {
> +                               new = &parent->rb_right;
> +                               leftmost = false;
> +                       }
> +
> +               }
> +       }
> +
> +       rb_link_node(&txqi->schedule_order, parent, new);
> +       rb_insert_color_cached(&txqi->schedule_order, root, leftmost);
> +}
> +
> +void ieee80211_schedule_txq(struct ieee80211_hw *hw,
> +                           struct ieee80211_txq *txq)
> +       __acquires(txq_lock) __releases(txq_lock)
> +{
> +       struct ieee80211_local *local = hw_to_local(hw);
> +       struct txq_info *txqi = to_txq_info(txq);
> +       u8 ac = txq->ac;
> +
> +       spin_lock_bh(&local->active_txq_lock[ac]);
> +
> +       if (!RB_EMPTY_NODE(&txqi->schedule_order))
> +               goto out;
> +
> +       if (txq->sta) {
> +               struct sta_info *sta = container_of(txq->sta,
> +                                                   struct sta_info, sta);
> +
> +               local->airtime_weight_sum[ac] += sta->airtime_weight;
> +               if (local->airtime_v_t[ac] > AIRTIME_GRACE)
> +                       sta->airtime[ac].v_t = max(local->airtime_v_t[ac] - AIRTIME_GRACE,
> +                                                  sta->airtime[ac].v_t);
> +       }
> +
> +       __ieee80211_insert_txq(&local->active_txqs[ac], txqi, ac);
> +
> + out:
> +       spin_unlock_bh(&local->active_txq_lock[ac]);
> +}
> +EXPORT_SYMBOL(ieee80211_schedule_txq);
> +
> +void ieee80211_resort_txq(struct ieee80211_hw *hw,
>                           struct ieee80211_txq *txq)
>  {
>         struct ieee80211_local *local = hw_to_local(hw);
>         struct txq_info *txqi = to_txq_info(txq);
> +       u8 ac = txq->ac;
> +
> +       if (!RB_EMPTY_NODE(&txqi->schedule_order)) {
> +               rb_erase_cached(&txqi->schedule_order,
> +                               &local->active_txqs[ac]);
> +               RB_CLEAR_NODE(&txqi->schedule_order);
> +               __ieee80211_insert_txq(&local->active_txqs[ac], txqi, ac);
> +       }
> +}
> +
> +static void __ieee80211_unschedule_txq(struct ieee80211_hw *hw,
> +                                      struct ieee80211_txq *txq)
> +{
> +       struct ieee80211_local *local = hw_to_local(hw);
> +       struct txq_info *txqi = to_txq_info(txq);
> +       u8 ac = txq->ac;
>
>         lockdep_assert_held(&local->active_txq_lock[txq->ac]);
>
> -       if (list_empty(&txqi->schedule_order) &&
> -           (!skb_queue_empty(&txqi->frags) || txqi->tin.backlog_packets)) {
> -               /* If airtime accounting is active, always enqueue STAs at the
> -                * head of the list to ensure that they only get moved to the
> -                * back by the airtime DRR scheduler once they have a negative
> -                * deficit. A station that already has a negative deficit will
> -                * get immediately moved to the back of the list on the next
> -                * call to ieee80211_next_txq().
> -                */
> -               if (txqi->txq.sta &&
> -                   wiphy_ext_feature_isset(local->hw.wiphy,
> -                                           NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
> -                       list_add(&txqi->schedule_order,
> -                                &local->active_txqs[txq->ac]);
> -               else
> -                       list_add_tail(&txqi->schedule_order,
> -                                     &local->active_txqs[txq->ac]);
> +       if (RB_EMPTY_NODE(&txqi->schedule_order))
> +               return;
> +
> +       if (txq->sta) {
> +               struct sta_info *sta = container_of(txq->sta,
> +                                                   struct sta_info, sta);
> +
> +               local->airtime_weight_sum[ac] -= sta->airtime_weight;
>         }
> +
> +       rb_erase_cached(&txqi->schedule_order,
> +                       &local->active_txqs[txq->ac]);
> +       RB_CLEAR_NODE(&txqi->schedule_order);
>  }
> -EXPORT_SYMBOL(ieee80211_return_txq);
>
> -void ieee80211_schedule_txq(struct ieee80211_hw *hw,
> -                           struct ieee80211_txq *txq)
> +void ieee80211_unschedule_txq(struct ieee80211_hw *hw,
> +                             struct ieee80211_txq *txq)
>         __acquires(txq_lock) __releases(txq_lock)
>  {
>         struct ieee80211_local *local = hw_to_local(hw);
>
>         spin_lock_bh(&local->active_txq_lock[txq->ac]);
> -       ieee80211_return_txq(hw, txq);
> +       __ieee80211_unschedule_txq(hw, txq);
>         spin_unlock_bh(&local->active_txq_lock[txq->ac]);
>  }
> -EXPORT_SYMBOL(ieee80211_schedule_txq);
> +
> +void ieee80211_return_txq(struct ieee80211_hw *hw,
> +                         struct ieee80211_txq *txq)
> +{
> +       struct ieee80211_local *local = hw_to_local(hw);
> +       struct txq_info *txqi = to_txq_info(txq);
> +
> +       lockdep_assert_held(&local->active_txq_lock[txq->ac]);
> +
> +       if (!RB_EMPTY_NODE(&txqi->schedule_order) &&
> +           (skb_queue_empty(&txqi->frags) && !txqi->tin.backlog_packets))
> +               __ieee80211_unschedule_txq(hw, txq);
> +}
> +EXPORT_SYMBOL(ieee80211_return_txq);
>
>  bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
>                                 struct ieee80211_txq *txq)
>  {
>         struct ieee80211_local *local = hw_to_local(hw);
> -       struct txq_info *iter, *tmp, *txqi = to_txq_info(txq);
> +       struct txq_info *txqi = to_txq_info(txq);
>         struct sta_info *sta;
>         u8 ac = txq->ac;
>
>         lockdep_assert_held(&local->active_txq_lock[ac]);
>
>         if (!txqi->txq.sta)
> -               goto out;
> -
> -       if (list_empty(&txqi->schedule_order))
> -               goto out;
> -
> -       list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac],
> -                                schedule_order) {
> -               if (iter == txqi)
> -                       break;
> -
> -               if (!iter->txq.sta) {
> -                       list_move_tail(&iter->schedule_order,
> -                                      &local->active_txqs[ac]);
> -                       continue;
> -               }
> -               sta = container_of(iter->txq.sta, struct sta_info, sta);
> -               if (sta->airtime[ac].deficit < 0)
> -                       sta->airtime[ac].deficit += sta->airtime_weight;
> -               list_move_tail(&iter->schedule_order, &local->active_txqs[ac]);
> -       }
> +               return true;
>
>         sta = container_of(txqi->txq.sta, struct sta_info, sta);
> -       if (sta->airtime[ac].deficit >= 0)
> -               goto out;
> -
> -       sta->airtime[ac].deficit += sta->airtime_weight;
> -       list_move_tail(&txqi->schedule_order, &local->active_txqs[ac]);
> -
> -       return false;
> -out:
> -       if (!list_empty(&txqi->schedule_order))
> -               list_del_init(&txqi->schedule_order);
> -
> -       return true;
> +       return (sta->airtime[ac].v_t <= local->airtime_v_t[ac]);
>  }
>  EXPORT_SYMBOL(ieee80211_txq_may_transmit);
>
> @@ -3769,7 +3832,6 @@ void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
>         struct ieee80211_local *local = hw_to_local(hw);
>
>         spin_lock_bh(&local->active_txq_lock[ac]);
> -       local->schedule_round[ac]++;
>  }
>  EXPORT_SYMBOL(ieee80211_txq_schedule_start);
>
> @@ -3778,6 +3840,7 @@ void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
>  {
>         struct ieee80211_local *local = hw_to_local(hw);
>
> +       local->schedule_pos[ac] = NULL;
>         spin_unlock_bh(&local->active_txq_lock[ac]);
>  }
>  EXPORT_SYMBOL(ieee80211_txq_schedule_end);
> --
> 2.20.1
>
> _______________________________________________
> Make-wifi-fast mailing list
> Make-wifi-fast@lists.bufferbloat.net
> https://lists.bufferbloat.net/listinfo/make-wifi-fast



-- 

Dave Täht
CTO, TekLibre, LLC
http://www.teklibre.com
Tel: 1-831-205-9740

^ permalink raw reply

* [PATCH] cfg80211/nl80211: Offload OWE processing to user space in AP mode
From: Srinivas Dasari @ 2019-02-15 19:14 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Sunil Dutt, Liangwei Dong, Srinivas Dasari

From: Sunil Dutt <usdutt@codeaurora.org>

This interface allows the host driver to offload OWE processing
to user space. This intends to support OWE (Opportunistic Wireless
Encryption) AKM by the drivers that implement SME but rely on the
user space for the cryptographic/OWE processing in AP mode. Such
drivers are not capable of processing/deriving the DH IE.

A new NL80211 command - NL80211_CMD_UPDATE_OWE_INFO is introduced
to send the request/event between the host driver and user space.

The driver shall use the event to notify the OWE info of the peer
to the user space for the cryptographic processing of the DH IE.
Accordingly, the user space shall update the OWE info/DH IE to
the driver.

Following is the sequence in AP mode for OWE authentication.

Driver passes the OWE info obtained from the peer in the
Association Request to the user space through the event
cfg80211_update_owe_info_event. User space shall process the
OWE info received and generate new OWE info. This OWE info is
passed to the driver through NL80211_CMD_UPDATE_OWE_INFO
request. Driver eventually uses this OWE info to send the
Association Response to the peer.

This OWE info in the command interface carries the IEs that include
PMKID of the peer if the PMKSA is still valid or an updated DH IE
for generating a new PMKSA with the peer.

Signed-off-by: Liangwei Dong <liangwei@codeaurora.org>
Signed-off-by: Sunil Dutt <usdutt@codeaurora.org>
Signed-off-by: Srinivas Dasari <dasaris@codeaurora.org>
---
 include/net/cfg80211.h       | 42 ++++++++++++++++++++++++++
 include/uapi/linux/nl80211.h |  7 +++++
 net/wireless/nl80211.c       | 72 ++++++++++++++++++++++++++++++++++++++++++++
 net/wireless/rdev-ops.h      | 13 ++++++++
 net/wireless/trace.h         | 38 +++++++++++++++++++++++
 5 files changed, 172 insertions(+)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index f81677f..9a314ee 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3100,6 +3100,32 @@ struct cfg80211_pmsr_request {
 };
 
 /**
+ * struct cfg80211_update_owe_info - OWE Information
+ *
+ * This structure provides information needed for the drivers to offload OWE
+ * (Opportunistic Wireless Encryption) processing to the user space.
+ *
+ * Commonly used across update_owe_info request and event interfaces.
+ *
+ * @peer: MAC address of the peer device for which the OWE processing
+ *	has to be done.
+ * @status: status code, %WLAN_STATUS_SUCCESS for successful OWE info
+ *	processing, use %WLAN_STATUS_UNSPECIFIED_FAILURE if user space
+ *	cannot give you the real status code for failures. Used only for
+ *	OWE update request command interface (user space to driver).
+ * @ie: IEs obtained from the peer or constructed by the user space. These are
+ *	the IEs of the remote peer in the event from the host driver and
+ *	the constructed IEs by the user space in the request interface.
+ * @ie_len: Length of IEs in octets.
+ */
+struct cfg80211_update_owe_info {
+	u8 peer[ETH_ALEN] __aligned(2);
+	u16 status;
+	const u8 *ie;
+	size_t ie_len;
+};
+
+/**
  * struct cfg80211_ops - backend description for wireless configuration
  *
  * This struct is registered by fullmac card drivers and/or wireless stacks
@@ -3436,6 +3462,10 @@ struct cfg80211_pmsr_request {
  *	Statistics should be cumulative, currently no way to reset is provided.
  * @start_pmsr: start peer measurement (e.g. FTM)
  * @abort_pmsr: abort peer measurement
+ *
+ * @update_owe_info: Provide updated OWE info to driver. Driver implementing SME
+ *	but offloading OWE processing to the user space will get the updated
+ *	DH IE through this interface.
  */
 struct cfg80211_ops {
 	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -3750,6 +3780,8 @@ struct cfg80211_ops {
 			      struct cfg80211_pmsr_request *request);
 	void	(*abort_pmsr)(struct wiphy *wiphy, struct wireless_dev *wdev,
 			      struct cfg80211_pmsr_request *request);
+	int	(*update_owe_info)(struct wiphy *wiphy, struct net_device *dev,
+				   struct cfg80211_update_owe_info *owe_info);
 };
 
 /*
@@ -7160,4 +7192,14 @@ void cfg80211_pmsr_complete(struct wireless_dev *wdev,
 #define wiphy_WARN(wiphy, format, args...)			\
 	WARN(1, "wiphy: %s\n" format, wiphy_name(wiphy), ##args);
 
+/**
+ * cfg80211_update_owe_info_event - Notify the peer's OWE info to user space
+ * @netdev: network device
+ * @owe_info: peer's owe info
+ * @gfp: allocation flags
+ */
+void cfg80211_update_owe_info_event(struct net_device *netdev,
+				    struct cfg80211_update_owe_info *owe_info,
+				    gfp_t gfp);
+
 #endif /* __NET_CFG80211_H */
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index dd4f86e..26aa319 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1065,6 +1065,11 @@
  *	indicated by %NL80211_ATTR_WIPHY_FREQ and other attributes
  *	determining the width and type.
  *
+ * @NL80211_CMD_UPDATE_OWE_INFO: This interface allows the host driver to
+ *	offload OWE processing to user space. This intends to support
+ *	OWE AKM by the host drivers that implement SME but rely
+ *	on the user space for the cryptographic/DH IE processing in AP mode.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -1285,6 +1290,8 @@ enum nl80211_commands {
 
 	NL80211_CMD_NOTIFY_RADAR,
 
+	NL80211_CMD_UPDATE_OWE_INFO,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 80878b4..2fe0421 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -13241,6 +13241,31 @@ static int nl80211_get_ftm_responder_stats(struct sk_buff *skb,
 	return -ENOBUFS;
 }
 
+static int nl80211_update_owe_info(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct cfg80211_update_owe_info owe_info;
+	struct net_device *dev = info->user_ptr[1];
+
+	if (!rdev->ops->update_owe_info)
+		return -EOPNOTSUPP;
+
+	if (!info->attrs[NL80211_ATTR_STATUS_CODE] ||
+	    !info->attrs[NL80211_ATTR_MAC])
+		return -EINVAL;
+
+	memset(&owe_info, 0, sizeof(owe_info));
+	owe_info.status = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
+	nla_memcpy(owe_info.peer, info->attrs[NL80211_ATTR_MAC], ETH_ALEN);
+
+	if (info->attrs[NL80211_ATTR_IE]) {
+		owe_info.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+		owe_info.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+	}
+
+	return rdev_update_owe_info(rdev, dev, &owe_info);
+}
+
 #define NL80211_FLAG_NEED_WIPHY		0x01
 #define NL80211_FLAG_NEED_NETDEV	0x02
 #define NL80211_FLAG_NEED_RTNL		0x04
@@ -14175,6 +14200,14 @@ static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
+	{
+		.cmd = NL80211_CMD_UPDATE_OWE_INFO,
+		.doit = nl80211_update_owe_info,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+				  NL80211_FLAG_NEED_RTNL,
+	},
 };
 
 static struct genl_family nl80211_fam __ro_after_init = {
@@ -16340,6 +16373,45 @@ int cfg80211_external_auth_request(struct net_device *dev,
 }
 EXPORT_SYMBOL(cfg80211_external_auth_request);
 
+void cfg80211_update_owe_info_event(struct net_device *netdev,
+				    struct cfg80211_update_owe_info *owe_info,
+				    gfp_t gfp)
+{
+	struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy;
+	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+	struct sk_buff *msg;
+	void *hdr;
+
+	trace_cfg80211_update_owe_info_event(wiphy, netdev, owe_info);
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+	if (!msg)
+		return;
+
+	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_UPDATE_OWE_INFO);
+	if (!hdr)
+		goto nla_put_failure;
+
+	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
+	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, owe_info->peer))
+		goto nla_put_failure;
+
+	if (nla_put(msg, NL80211_ATTR_IE, owe_info->ie_len, owe_info->ie))
+		goto nla_put_failure;
+
+	genlmsg_end(msg, hdr);
+
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+				NL80211_MCGRP_MLME, gfp);
+	return;
+
+nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	nlmsg_free(msg);
+}
+EXPORT_SYMBOL(cfg80211_update_owe_info_event);
+
 /* initialisation/exit functions */
 
 int __init nl80211_init(void)
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 5cb48d1..c1e3210 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -1272,4 +1272,17 @@ static inline int rdev_del_pmk(struct cfg80211_registered_device *rdev,
 	trace_rdev_return_void(&rdev->wiphy);
 }
 
+static inline int rdev_update_owe_info(struct cfg80211_registered_device *rdev,
+				       struct net_device *dev,
+				       struct cfg80211_update_owe_info *oweinfo)
+{
+	int ret = -EOPNOTSUPP;
+
+	trace_rdev_update_owe_info(&rdev->wiphy, dev, oweinfo);
+	if (rdev->ops->update_owe_info)
+		ret = rdev->ops->update_owe_info(&rdev->wiphy, dev, oweinfo);
+	trace_rdev_return_int(&rdev->wiphy, ret);
+	return ret;
+}
+
 #endif /* __CFG80211_RDEV_OPS */
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 44b2ce1..2dda529 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -3362,6 +3362,44 @@
 		  WIPHY_PR_ARG, WDEV_PR_ARG,
 		  (unsigned long long)__entry->cookie)
 );
+
+TRACE_EVENT(rdev_update_owe_info,
+	    TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+		     struct cfg80211_update_owe_info *owe_info),
+	    TP_ARGS(wiphy, netdev, owe_info),
+	    TP_STRUCT__entry(WIPHY_ENTRY
+			     NETDEV_ENTRY
+			     MAC_ENTRY(peer)
+			     __field(u16, status)
+			     __dynamic_array(u8, ie, owe_info->ie_len)),
+	    TP_fast_assign(WIPHY_ASSIGN;
+			   NETDEV_ASSIGN;
+			   MAC_ASSIGN(peer, owe_info->peer);
+			   __entry->status = owe_info->status;
+			   memcpy(__get_dynamic_array(ie),
+				  owe_info->ie, owe_info->ie_len);),
+	    TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT
+		  " status %d", WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer),
+		  __entry->status)
+);
+
+TRACE_EVENT(cfg80211_update_owe_info_event,
+	    TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+		     struct cfg80211_update_owe_info *owe_info),
+	    TP_ARGS(wiphy, netdev, owe_info),
+	    TP_STRUCT__entry(WIPHY_ENTRY
+			     NETDEV_ENTRY
+			     MAC_ENTRY(peer)
+			     __dynamic_array(u8, ie, owe_info->ie_len)),
+	    TP_fast_assign(WIPHY_ASSIGN;
+			   NETDEV_ASSIGN;
+			   MAC_ASSIGN(peer, owe_info->peer);
+			   memcpy(__get_dynamic_array(ie), owe_info->ie,
+				  owe_info->ie_len);),
+	    TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT,
+		      WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer))
+);
+
 #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
 
 #undef TRACE_INCLUDE_PATH
-- 
1.9.1


^ permalink raw reply related

* [RFC/RFT] mac80211: Switch to a virtual time-based airtime scheduler
From: Toke Høiland-Jørgensen @ 2019-02-15 17:05 UTC (permalink / raw)
  To: make-wifi-fast, linux-wireless
  Cc: Felix Fietkau, Rajkumar Manoharan, Kan Yan,
	Toke Høiland-Jørgensen

This switches the airtime scheduler in mac80211 to use a virtual time-based
scheduler instead of the round-robin scheduler used before. This has a
couple of advantages:

- No need to sync up the round-robin scheduler in firmware/hardware with
  the round-robin airtime scheduler.

- If several stations are eligible for transmission we can schedule both of
  them; no need to hard-block the scheduling rotation until the head of the
  queue has used up its quantum.

- The check of whether a station is eligible for transmission becomes
  simpler (in ieee80211_txq_may_transmit()).

The drawback is that scheduling becomes slightly more expensive, as we need
to maintain an rbtree of TXQs sorted by virtual time. This means that
ieee80211_register_airtime() becomes O(logN) in the number of currently
scheduled TXQs. However, hopefully this number rarely grows too big (it's
only TXQs currently backlogged, not all associated stations), so it
shouldn't be too big of an issue.

Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
---
This is basically the idea I mentioned earlier for a different way to
handle the airtime scheduling.

I've tested it on ath9k, where it achieves the same fairness and
weighing properties as the old scheduler. It would be good if you could
test it on your ath10k setup, Rajkumar; and all of you please comment on
whether you agree that this is better from an API point of view.

 net/mac80211/debugfs.c     |  49 ++++++++-
 net/mac80211/debugfs_sta.c |  16 +--
 net/mac80211/ieee80211_i.h |  15 ++-
 net/mac80211/main.c        |   2 +-
 net/mac80211/sta_info.c    |  19 +++-
 net/mac80211/sta_info.h    |   3 +-
 net/mac80211/tx.c          | 217 ++++++++++++++++++++++++-------------
 7 files changed, 225 insertions(+), 96 deletions(-)

diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 343ad0a915e4..93b9ed2f9451 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -150,6 +150,47 @@ static const struct file_operations aqm_ops = {
 	.llseek = default_llseek,
 };
 
+static ssize_t airtime_read(struct file *file,
+			    char __user *user_buf,
+			    size_t count,
+			    loff_t *ppos)
+{
+	struct ieee80211_local *local = file->private_data;
+	char buf[200];
+	u64 v_t[IEEE80211_NUM_ACS];
+	u64 wt[IEEE80211_NUM_ACS];
+	int len = 0, ac;
+
+	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+		spin_lock_bh(&local->active_txq_lock[ac]);
+		v_t[ac] = local->airtime_v_t[ac];
+		wt[ac] = local->airtime_weight_sum[ac];
+		spin_unlock_bh(&local->active_txq_lock[ac]);
+	}
+	len = scnprintf(buf, sizeof(buf),
+			"\tVO         VI         BE         BK\n"
+			"Virt-t\t%-10llu %-10llu %-10llu %-10llu\n"
+			"Weight\t%-10llu %-10llu %-10llu %-10llu\n",
+			v_t[0],
+			v_t[1],
+			v_t[2],
+			v_t[3],
+			wt[0],
+			wt[1],
+			wt[2],
+			wt[3]);
+
+	return simple_read_from_buffer(user_buf, count, ppos,
+				       buf, len);
+}
+
+static const struct file_operations airtime_ops = {
+	.read = airtime_read,
+	.open = simple_open,
+	.llseek = default_llseek,
+};
+
+
 #ifdef CONFIG_PM
 static ssize_t reset_write(struct file *file, const char __user *user_buf,
 			   size_t count, loff_t *ppos)
@@ -384,8 +425,12 @@ void debugfs_hw_add(struct ieee80211_local *local)
 	if (local->ops->wake_tx_queue)
 		DEBUGFS_ADD_MODE(aqm, 0600);
 
-	debugfs_create_u16("airtime_flags", 0600,
-			   phyd, &local->airtime_flags);
+	if (wiphy_ext_feature_isset(local->hw.wiphy,
+				    NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) {
+		DEBUGFS_ADD_MODE(airtime, 0600);
+		debugfs_create_u16("airtime_flags", 0600,
+				   phyd, &local->airtime_flags);
+	}
 
 	statsd = debugfs_create_dir("statistics", phyd);
 
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 3aa618dcc58e..80028da27b98 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -203,7 +203,7 @@ static ssize_t sta_airtime_read(struct file *file, char __user *userbuf,
 	size_t bufsz = 200;
 	char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf;
 	u64 rx_airtime = 0, tx_airtime = 0;
-	s64 deficit[IEEE80211_NUM_ACS];
+	u64 v_t[IEEE80211_NUM_ACS];
 	ssize_t rv;
 	int ac;
 
@@ -214,20 +214,20 @@ static ssize_t sta_airtime_read(struct file *file, char __user *userbuf,
 		spin_lock_bh(&local->active_txq_lock[ac]);
 		rx_airtime += sta->airtime[ac].rx_airtime;
 		tx_airtime += sta->airtime[ac].tx_airtime;
-		deficit[ac] = sta->airtime[ac].deficit;
+		v_t[ac] = sta->airtime[ac].v_t;
 		spin_unlock_bh(&local->active_txq_lock[ac]);
 	}
 
 	p += scnprintf(p, bufsz + buf - p,
 		"RX: %llu us\nTX: %llu us\nWeight: %u\n"
-		"Deficit: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n",
+		"Virt-T: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n",
 		rx_airtime,
 		tx_airtime,
 		sta->airtime_weight,
-		deficit[0],
-		deficit[1],
-		deficit[2],
-		deficit[3]);
+		v_t[0],
+		v_t[1],
+		v_t[2],
+		v_t[3]);
 
 	rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
 	kfree(buf);
@@ -245,7 +245,7 @@ static ssize_t sta_airtime_write(struct file *file, const char __user *userbuf,
 		spin_lock_bh(&local->active_txq_lock[ac]);
 		sta->airtime[ac].rx_airtime = 0;
 		sta->airtime[ac].tx_airtime = 0;
-		sta->airtime[ac].deficit = sta->airtime_weight;
+		sta->airtime[ac].v_t = 0;
 		spin_unlock_bh(&local->active_txq_lock[ac]);
 	}
 
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 056b16bce3b0..994a70ee0ec0 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -840,8 +840,7 @@ struct txq_info {
 	struct codel_vars def_cvars;
 	struct codel_stats cstats;
 	struct sk_buff_head frags;
-	struct list_head schedule_order;
-	u16 schedule_round;
+	struct rb_node schedule_order;
 	unsigned long flags;
 
 	/* keep last! */
@@ -1135,8 +1134,10 @@ struct ieee80211_local {
 
 	/* protects active_txqs and txqi->schedule_order */
 	spinlock_t active_txq_lock[IEEE80211_NUM_ACS];
-	struct list_head active_txqs[IEEE80211_NUM_ACS];
-	u16 schedule_round[IEEE80211_NUM_ACS];
+	struct rb_root_cached active_txqs[IEEE80211_NUM_ACS];
+	struct rb_node *schedule_pos[IEEE80211_NUM_ACS];
+	u64 airtime_v_t[IEEE80211_NUM_ACS];
+	u64 airtime_weight_sum[IEEE80211_NUM_ACS];
 
 	u16 airtime_flags;
 
@@ -1765,6 +1766,12 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
 			      const u8 *buf, size_t len,
 			      const u8 *dest, __be16 proto, bool unencrypted);
 
+void ieee80211_resort_txq(struct ieee80211_hw *hw,
+			  struct ieee80211_txq *txq);
+void ieee80211_unschedule_txq(struct ieee80211_hw *hw,
+			      struct ieee80211_txq *txq);
+
+
 /* HT */
 void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
 				     struct ieee80211_sta_ht_cap *ht_cap);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 71005b6dfcd1..f207bc284921 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -666,7 +666,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
 	spin_lock_init(&local->queue_stop_reason_lock);
 
 	for (i = 0; i < IEEE80211_NUM_ACS; i++) {
-		INIT_LIST_HEAD(&local->active_txqs[i]);
+		local->active_txqs[i] = RB_ROOT_CACHED;
 		spin_lock_init(&local->active_txq_lock[i]);
 	}
 	local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX;
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 11f058987a54..9d01fdd86e2d 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -389,7 +389,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
 	for (i = 0; i < IEEE80211_NUM_ACS; i++) {
 		skb_queue_head_init(&sta->ps_tx_buf[i]);
 		skb_queue_head_init(&sta->tx_filtered[i]);
-		sta->airtime[i].deficit = sta->airtime_weight;
 	}
 
 	for (i = 0; i < IEEE80211_NUM_TIDS; i++)
@@ -1831,18 +1830,32 @@ void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid,
 {
 	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
 	struct ieee80211_local *local = sta->sdata->local;
+	struct ieee80211_txq *txq = sta->sta.txq[tid];
 	u8 ac = ieee80211_ac_from_tid(tid);
-	u32 airtime = 0;
+	u64 airtime = 0, weight_sum;
+
+	if (!txq)
+		return;
 
 	if (sta->local->airtime_flags & AIRTIME_USE_TX)
 		airtime += tx_airtime;
 	if (sta->local->airtime_flags & AIRTIME_USE_RX)
 		airtime += rx_airtime;
 
+	/* Weights scale so the unit weight is 256 */
+	airtime <<= 8;
+
 	spin_lock_bh(&local->active_txq_lock[ac]);
+
 	sta->airtime[ac].tx_airtime += tx_airtime;
 	sta->airtime[ac].rx_airtime += rx_airtime;
-	sta->airtime[ac].deficit -= airtime;
+
+	weight_sum = local->airtime_weight_sum[ac] ?: sta->airtime_weight;
+
+	local->airtime_v_t[ac] += airtime / weight_sum;
+	sta->airtime[ac].v_t += airtime / sta->airtime_weight;
+	ieee80211_resort_txq(&local->hw, txq);
+
 	spin_unlock_bh(&local->active_txq_lock[ac]);
 }
 EXPORT_SYMBOL(ieee80211_sta_register_airtime);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 05647d835894..4b901a2a998e 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -130,11 +130,12 @@ enum ieee80211_agg_stop_reason {
 /* Debugfs flags to enable/disable use of RX/TX airtime in scheduler */
 #define AIRTIME_USE_TX		BIT(0)
 #define AIRTIME_USE_RX		BIT(1)
+#define AIRTIME_GRACE 500 /* usec of grace period before reset */
 
 struct airtime_info {
 	u64 rx_airtime;
 	u64 tx_airtime;
-	s64 deficit;
+	u64 v_t;
 };
 
 struct sta_info;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 61c7ea9de2cc..8e125df8ade0 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1449,7 +1449,7 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
 	codel_vars_init(&txqi->def_cvars);
 	codel_stats_init(&txqi->cstats);
 	__skb_queue_head_init(&txqi->frags);
-	INIT_LIST_HEAD(&txqi->schedule_order);
+	RB_CLEAR_NODE(&txqi->schedule_order);
 
 	txqi->txq.vif = &sdata->vif;
 
@@ -1493,9 +1493,7 @@ void ieee80211_txq_purge(struct ieee80211_local *local,
 	ieee80211_purge_tx_queue(&local->hw, &txqi->frags);
 	spin_unlock_bh(&fq->lock);
 
-	spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]);
-	list_del_init(&txqi->schedule_order);
-	spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]);
+	ieee80211_unschedule_txq(&local->hw, &txqi->txq);
 }
 
 void ieee80211_txq_set_params(struct ieee80211_local *local)
@@ -3640,126 +3638,191 @@ EXPORT_SYMBOL(ieee80211_tx_dequeue);
 struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
+	struct rb_node *node = local->schedule_pos[ac];
 	struct txq_info *txqi = NULL;
+	bool first = false;
 
 	lockdep_assert_held(&local->active_txq_lock[ac]);
 
- begin:
-	txqi = list_first_entry_or_null(&local->active_txqs[ac],
-					struct txq_info,
-					schedule_order);
-	if (!txqi)
+	if (!node) {
+		node = rb_first_cached(&local->active_txqs[ac]);
+		first = true;
+	} else
+		node = rb_next(node);
+
+	if (!node)
 		return NULL;
 
+	txqi = container_of(node, struct txq_info, schedule_order);
+
 	if (txqi->txq.sta) {
 		struct sta_info *sta = container_of(txqi->txq.sta,
 						struct sta_info, sta);
 
-		if (sta->airtime[txqi->txq.ac].deficit < 0) {
-			sta->airtime[txqi->txq.ac].deficit +=
-				sta->airtime_weight;
-			list_move_tail(&txqi->schedule_order,
-				       &local->active_txqs[txqi->txq.ac]);
-			goto begin;
+		if (sta->airtime[ac].v_t > local->airtime_v_t[ac]) {
+			if (first)
+				local->airtime_v_t[ac] = sta->airtime[ac].v_t;
+			else
+				return NULL;
 		}
 	}
 
 
-	if (txqi->schedule_round == local->schedule_round[ac])
-		return NULL;
-
-	list_del_init(&txqi->schedule_order);
-	txqi->schedule_round = local->schedule_round[ac];
+	local->schedule_pos[ac] = node;
 	return &txqi->txq;
 }
 EXPORT_SYMBOL(ieee80211_next_txq);
 
-void ieee80211_return_txq(struct ieee80211_hw *hw,
+static void __ieee80211_insert_txq(struct rb_root_cached *root,
+				   struct txq_info *txqi, u8 ac)
+{
+	struct rb_node **new = &root->rb_root.rb_node;
+	struct rb_node *parent = NULL;
+	struct txq_info *__txqi;
+	bool leftmost = true;
+
+	while (*new) {
+		parent = *new;
+		__txqi = rb_entry(parent, struct txq_info, schedule_order);
+
+		if (!txqi->txq.sta) {
+			/* new txqi has no sta - insert to the left */
+			new = &parent->rb_left;
+		} else if (!__txqi->txq.sta) {
+			/* existing txqi has no sta - insert to the right */
+			new = &parent->rb_right;
+			leftmost = false;
+		} else {
+			struct sta_info *old_sta = container_of(__txqi->txq.sta,
+								struct sta_info,
+								sta);
+			struct sta_info *new_sta = container_of(txqi->txq.sta,
+								struct sta_info,
+								sta);
+
+			if (new_sta->airtime[ac].v_t <= old_sta->airtime[ac].v_t)
+				new = &parent->rb_left;
+			else {
+				new = &parent->rb_right;
+				leftmost = false;
+			}
+
+		}
+	}
+
+	rb_link_node(&txqi->schedule_order, parent, new);
+	rb_insert_color_cached(&txqi->schedule_order, root, leftmost);
+}
+
+void ieee80211_schedule_txq(struct ieee80211_hw *hw,
+			    struct ieee80211_txq *txq)
+	__acquires(txq_lock) __releases(txq_lock)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct txq_info *txqi = to_txq_info(txq);
+	u8 ac = txq->ac;
+
+	spin_lock_bh(&local->active_txq_lock[ac]);
+
+	if (!RB_EMPTY_NODE(&txqi->schedule_order))
+		goto out;
+
+	if (txq->sta) {
+		struct sta_info *sta = container_of(txq->sta,
+						    struct sta_info, sta);
+
+		local->airtime_weight_sum[ac] += sta->airtime_weight;
+		if (local->airtime_v_t[ac] > AIRTIME_GRACE)
+			sta->airtime[ac].v_t = max(local->airtime_v_t[ac] - AIRTIME_GRACE,
+						   sta->airtime[ac].v_t);
+	}
+
+	__ieee80211_insert_txq(&local->active_txqs[ac], txqi, ac);
+
+ out:
+	spin_unlock_bh(&local->active_txq_lock[ac]);
+}
+EXPORT_SYMBOL(ieee80211_schedule_txq);
+
+void ieee80211_resort_txq(struct ieee80211_hw *hw,
 			  struct ieee80211_txq *txq)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct txq_info *txqi = to_txq_info(txq);
+	u8 ac = txq->ac;
+
+	if (!RB_EMPTY_NODE(&txqi->schedule_order)) {
+		rb_erase_cached(&txqi->schedule_order,
+				&local->active_txqs[ac]);
+		RB_CLEAR_NODE(&txqi->schedule_order);
+		__ieee80211_insert_txq(&local->active_txqs[ac], txqi, ac);
+	}
+}
+
+static void __ieee80211_unschedule_txq(struct ieee80211_hw *hw,
+				       struct ieee80211_txq *txq)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct txq_info *txqi = to_txq_info(txq);
+	u8 ac = txq->ac;
 
 	lockdep_assert_held(&local->active_txq_lock[txq->ac]);
 
-	if (list_empty(&txqi->schedule_order) &&
-	    (!skb_queue_empty(&txqi->frags) || txqi->tin.backlog_packets)) {
-		/* If airtime accounting is active, always enqueue STAs at the
-		 * head of the list to ensure that they only get moved to the
-		 * back by the airtime DRR scheduler once they have a negative
-		 * deficit. A station that already has a negative deficit will
-		 * get immediately moved to the back of the list on the next
-		 * call to ieee80211_next_txq().
-		 */
-		if (txqi->txq.sta &&
-		    wiphy_ext_feature_isset(local->hw.wiphy,
-					    NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
-			list_add(&txqi->schedule_order,
-				 &local->active_txqs[txq->ac]);
-		else
-			list_add_tail(&txqi->schedule_order,
-				      &local->active_txqs[txq->ac]);
+	if (RB_EMPTY_NODE(&txqi->schedule_order))
+		return;
+
+	if (txq->sta) {
+		struct sta_info *sta = container_of(txq->sta,
+						    struct sta_info, sta);
+
+		local->airtime_weight_sum[ac] -= sta->airtime_weight;
 	}
+
+	rb_erase_cached(&txqi->schedule_order,
+			&local->active_txqs[txq->ac]);
+	RB_CLEAR_NODE(&txqi->schedule_order);
 }
-EXPORT_SYMBOL(ieee80211_return_txq);
 
-void ieee80211_schedule_txq(struct ieee80211_hw *hw,
-			    struct ieee80211_txq *txq)
+void ieee80211_unschedule_txq(struct ieee80211_hw *hw,
+			      struct ieee80211_txq *txq)
 	__acquires(txq_lock) __releases(txq_lock)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 
 	spin_lock_bh(&local->active_txq_lock[txq->ac]);
-	ieee80211_return_txq(hw, txq);
+	__ieee80211_unschedule_txq(hw, txq);
 	spin_unlock_bh(&local->active_txq_lock[txq->ac]);
 }
-EXPORT_SYMBOL(ieee80211_schedule_txq);
+
+void ieee80211_return_txq(struct ieee80211_hw *hw,
+			  struct ieee80211_txq *txq)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct txq_info *txqi = to_txq_info(txq);
+
+	lockdep_assert_held(&local->active_txq_lock[txq->ac]);
+
+	if (!RB_EMPTY_NODE(&txqi->schedule_order) &&
+	    (skb_queue_empty(&txqi->frags) && !txqi->tin.backlog_packets))
+		__ieee80211_unschedule_txq(hw, txq);
+}
+EXPORT_SYMBOL(ieee80211_return_txq);
 
 bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
 				struct ieee80211_txq *txq)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
-	struct txq_info *iter, *tmp, *txqi = to_txq_info(txq);
+	struct txq_info *txqi = to_txq_info(txq);
 	struct sta_info *sta;
 	u8 ac = txq->ac;
 
 	lockdep_assert_held(&local->active_txq_lock[ac]);
 
 	if (!txqi->txq.sta)
-		goto out;
-
-	if (list_empty(&txqi->schedule_order))
-		goto out;
-
-	list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac],
-				 schedule_order) {
-		if (iter == txqi)
-			break;
-
-		if (!iter->txq.sta) {
-			list_move_tail(&iter->schedule_order,
-				       &local->active_txqs[ac]);
-			continue;
-		}
-		sta = container_of(iter->txq.sta, struct sta_info, sta);
-		if (sta->airtime[ac].deficit < 0)
-			sta->airtime[ac].deficit += sta->airtime_weight;
-		list_move_tail(&iter->schedule_order, &local->active_txqs[ac]);
-	}
+		return true;
 
 	sta = container_of(txqi->txq.sta, struct sta_info, sta);
-	if (sta->airtime[ac].deficit >= 0)
-		goto out;
-
-	sta->airtime[ac].deficit += sta->airtime_weight;
-	list_move_tail(&txqi->schedule_order, &local->active_txqs[ac]);
-
-	return false;
-out:
-	if (!list_empty(&txqi->schedule_order))
-		list_del_init(&txqi->schedule_order);
-
-	return true;
+	return (sta->airtime[ac].v_t <= local->airtime_v_t[ac]);
 }
 EXPORT_SYMBOL(ieee80211_txq_may_transmit);
 
@@ -3769,7 +3832,6 @@ void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
 	struct ieee80211_local *local = hw_to_local(hw);
 
 	spin_lock_bh(&local->active_txq_lock[ac]);
-	local->schedule_round[ac]++;
 }
 EXPORT_SYMBOL(ieee80211_txq_schedule_start);
 
@@ -3778,6 +3840,7 @@ void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 
+	local->schedule_pos[ac] = NULL;
 	spin_unlock_bh(&local->active_txq_lock[ac]);
 }
 EXPORT_SYMBOL(ieee80211_txq_schedule_end);
-- 
2.20.1


^ permalink raw reply related

* [PATCH] ath9k: Make sure to zero status.tx_time before reporting TX status
From: Toke Høiland-Jørgensen @ 2019-02-15 16:48 UTC (permalink / raw)
  To: make-wifi-fast, linux-wireless; +Cc: Toke Høiland-Jørgensen

Since ath9k reports airtime usage directly using the
ieee80211_report_airtime() callback, it shouldn't also report it using the
tx_time in status. Make sure the field is zeroed before TX status is
reported to avoid spurious airtime being accounted by bits being left over
from earlier uses of the cb.

Fixes: 89cea7493a34 ("ath9k: Switch to mac80211 TXQ scheduling and airtime APIs")
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
---
 drivers/net/wireless/ath/ath9k/xmit.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 06e0c5a6fab6..773d428ff1b0 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -2552,6 +2552,9 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
 	}
 
 	tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
+
+	/* we report airtime in ath_tx_count_airtime(), don't report twice */
+	tx_info->status.tx_time = 0;
 }
 
 static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
-- 
2.20.1


^ permalink raw reply related

* [BUG] ath10k firmware crash 100% recreated this way
From: Chaoxing Lin @ 2019-02-15 15:45 UTC (permalink / raw)
  To: ath10k@lists.infradead.org, linux-wireless@vger.kernel.org

Hello ath10k firmware maintainers,

I saw ath10k firmware crash very often (~170 times in 20hours) 
on our wireless AP/bridge environment below:
 	arm64 board	 
	kernel 4.14.16 
	hostapd-2.6 run in 4-address mode
	Qualcomm Atheros QCA986x/988x 802.11ac Wireless Network Adapter
	ath10k_core.ko in software crypto mode
	running RSTP (Rapid Spanning Tree Protocol)

I also consistently recreated this firmware crash on Linux PC acting as AP 
as follows. Please take a look.

"must" conditions:

1. ath10k_core.ko MUST be in software crypto mode 
   ("modprobe ath10k_core cryptmode=1")

2. MUST run our proprietary RSTP bridge module 3ebridge.ko 
   (I can provide binary complied for kernel 4.14.16 on X86_64 PC)

3. STP must be on. 
   ("brctl stp brg0 on", by default 3ebridge.ko would turn STP on. Just a note 
    that if STP is turned off, you won't see firmware crash)

4. hostapd-2.6 MUST be configured in 4-address mode 
   (put "wds_sta=1" in hostapd.conf) 

5. Linux PC wireless client must be in 4-address mode. 
   (run "iw wlan0 set 4addr on" before starting wpa_supplicant)
   To 100% recreate this firmware crash RIGHT AWAY, use the following WiFi 
   client.

	root@Dell-D620:~# lspci
		0c:00.0 Network controller: Intel Corporation PRO/Wireless 3945ABG 
        [Golan] Network Connection (rev 02)
	You can find such radio card in very old (~15 years old) laptop.
         I can send you this radio card if you cannot find it.

ath10k firmware crashes right away when this 4-address client associates with 
the PC acting as AP.

FYI: What's known special about this wireless client? 
     Our experiments show this client does not really work in 4 address mode. 
     It successfully associates with AP but no traffic is possible in 
	 4-address mode.
     Packets sniffed in the air show that this client (when in 4 address mode) 
     does NOT send ACK packets to AP on receiving from AP packet whose RA is 
     client MAC and DA is multicast MAC (e.g. BPDU)
     NOTE: Don't be distracted by what I saw about this wireless client. 
           It may not be related to the firmware crash. 


The following are DONT-CARE in re-creating the firmware crash.

1. WiFi encryption: 
   The firmare crash happens even in bypass/no-encryption mode, although 
   ath10k_core.ko MUST be put in software crypto mode to see the crash.

2. ath10k firmware version: 
   As long as it supports software crypto mode (i.e. support raw mode), 
   the above procedure can crash it. I tried various firmware versions from 
   the initial version that supports raw mode to the latest 
   firmware-5.bin_10.2.4.70.69 dated 18-Dec-2018. They all crashed.

3. Linux wireless client distribution/OS is a don't care.
   As long as the WiFi adapter is "Intel Corporation PRO/Wireless 3945AB"  
   Tried distributions below. They both make firmare crash right away on 
   PC AP side
		Slackware 14.2 (kernel 4.4.14-smp)
		Ubuntu 18.04.01 live (kernel 4.15.0-29-generic)

4. Radio channel setting is a don't care.
   Tried with/without 11n/11ac/ and different channel width. 
   They all crash firmware.


I can provide all configurations/binary as below.
	hostapd.conf  [see later in this message]
	wpa_supplicant.conf  [see later in this message]
	3ebridge.ko (RSTP bridge binary compiled for 
				 mainline kernel 4.14.16 X86_64. 
                 Please "modprobe -r bridge" before "insmod 3ebridge.ko")


Below is the syslog/messages related to the ath10k firmware crash.
For easier reading, Timestamps are removed. line edited just to wrap around 
at 80char 


/var/log/messages 
---------------------------------------------------------------------------
ath10k_pci 0000:03:00.0: pci irq msi oper_irq_mode 2 irq_mode 0 reset_mode 0
ath10k_pci 0000:03:00.0: qca988x hw2.0 target 0x4100016c chip_id 0x043202ff 
                         sub 0000:0000
ath10k_pci 0000:03:00.0: kconfig debug 0 debugfs 1 tracing 0 dfs 0 testmode 0
ath10k_pci 0000:03:00.0: firmware ver 10.2.4.70.69 api 5 features no-p2p,
                         raw-mode,mfp,allows-mesh-bcast crc32 edfb196a
ath10k_pci 0000:03:00.0: board_file api 1 bmi_id N/A crc32 bebc7c08
ath10k_pci 0000:03:00.0: htt-ver 2.1 wmi-op 5 htt-op 2 cal otp max-sta 128 
                         raw 1 hwcrypto 0
ath10k_pci 0000:03:00.0 wlan50: renamed from wlan0
ath10k_pci 0000:03:00.0 wlan4: renamed from wlan50
IPv6: ADDRCONF(NETDEV_UP): phy0ap: link is not ready
device phy0ap entered promiscuous mode
IPv6: ADDRCONF(NETDEV_CHANGE): phy0ap: link becomes ready
device phy0ap.sta1 entered promiscuous mode
ath10k_pci 0000:03:00.0: qca988x hw2.0 target 0x4100016c chip_id 0x043202ff 
                         sub 0000:0000
ath10k_pci 0000:03:00.0: kconfig debug 0 debugfs 1 tracing 0 dfs 0 testmode 0
ath10k_pci 0000:03:00.0: firmware ver 10.2.4.70.69 api 5 features no-p2p,
                         raw-mode,mfp,allows-mesh-bcast crc32 edfb196a
ath10k_pci 0000:03:00.0: board_file api 1 bmi_id N/A crc32 bebc7c08
ath10k_pci 0000:03:00.0: htt-ver 2.1 wmi-op 5 htt-op 2 cal otp max-sta 128 
                         raw 1 hwcrypto 0
ieee80211 phy0: Hardware restart was requested
ath10k_pci 0000:03:00.0: device successfully recovered


/var/log/syslog
----------------------------------------------------------------------------
ath10k_pci 0000:03:00.0: firmware crashed! 
                         (guid 64627eb3-5b90-491a-8181-6972fc50d317)
ath10k_pci 0000:03:00.0: firmware register dump:
ath10k_pci 0000:03:00.0: [00]: 0x4100016C 0x000015B3 0x0099901F 0x00955B31
ath10k_pci 0000:03:00.0: [04]: 0x0099901F 0x00060130 0x00000020 0x000FFFFF
ath10k_pci 0000:03:00.0: [08]: 0x00427D80 0x00000003 0x00000000 0x00401C3C
ath10k_pci 0000:03:00.0: [12]: 0x00000009 0xFFFFFFFF 0x00958360 0x0095836B
ath10k_pci 0000:03:00.0: [16]: 0x00958080 0x0094085D 0x00000000 0x00000000
ath10k_pci 0000:03:00.0: [20]: 0x4099901F 0x0040AA94 0x00000001 0x00100000
ath10k_pci 0000:03:00.0: [24]: 0x80996254 0x0040AAF4 0x00409418 0xC099901F
ath10k_pci 0000:03:00.0: [28]: 0x8099A4BD 0x0040AB44 0x00427D80 0x00439BC0
ath10k_pci 0000:03:00.0: [32]: 0x8099A62C 0x0040ACE4 0x00000000 0x0042E648
ath10k_pci 0000:03:00.0: [36]: 0x8099A5BC 0x0040AD14 0x00000002 0x0042E648
ath10k_pci 0000:03:00.0: [40]: 0x8099A7AC 0x0040AD44 0x00439BC0 0x0042E648
ath10k_pci 0000:03:00.0: [44]: 0x8099885F 0x0040AD64 0x00439BC0 0x00000002
ath10k_pci 0000:03:00.0: [48]: 0x8099AF6D 0x0040AD84 0x0042066C 0x0042621C
ath10k_pci 0000:03:00.0: [52]: 0x809BF051 0x0040AEE4 0x00424D5C 0x00000002
ath10k_pci 0000:03:00.0: [56]: 0x80940F18 0x0040AF14 0x00000005 0x004039E4
ath10k_pci 0000:03:00.0: Copy Engine register dump:
ath10k_pci 0000:03:00.0: [00]: 0x00057400   1   1   3   3
ath10k_pci 0000:03:00.0: [01]: 0x00057800  14  14 241 242
ath10k_pci 0000:03:00.0: [02]: 0x00057c00  56  56  55  56
ath10k_pci 0000:03:00.0: [03]: 0x00058000  12  12  14  12
ath10k_pci 0000:03:00.0: [04]: 0x00058400  24  24  62  22
ath10k_pci 0000:03:00.0: [05]: 0x00058800   7   7 326 327
ath10k_pci 0000:03:00.0: [06]: 0x00058c00  19  19  19  19
ath10k_pci 0000:03:00.0: [07]: 0x00059000   0   0   0   0

phy0ap.sta1:  Failed check-sdata-in-driver check, flags: 0x0
------------[ cut here ]------------
WARNING: CPU: 1 PID: 30409 at net/mac80211/driver-ops.h:18 
         ieee80211_assign_chanctx.part.16+0x15e/0x170 [mac80211]
Modules linked in: ath10k_pci ath10k_core ath mac80211 cfg80211 3ebridge(O) 
nfnetlink_queue nfnetlink_log nfnetlink bluetooth ecdh_generic rfkill ipv6 
fuse hid_generic usbhid hid i2c_dev dell_wmi dell_smbios sparse_keymap 
gpio_ich wmi_bmof ppdev evdev dcdbas snd_hda_codec_analog snd_hda_codec_generic
coretemp snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_pcm kvm_intel 
kvm snd_timer hwmon psmouse irqbypass serio_raw snd i915 i2c_i801 uhci_hcd 
video drm_kms_helper drm lpc_ich i2c_algo_bit fb_sys_fops syscopyarea 
sysfillrect sysimgblt i2c_core ehci_pci e100 mii tpm_tis tpm_tis_core tpm wmi 
soundcore parport_pc parport ehci_hcd intel_agp intel_gtt button agpgart 
shpchp e1000e acpi_cpufreq loop [last unloaded: cfg80211]
CPU: 1 PID: 30409 Comm: kworker/1:2 Tainted: G        W  O    4.14.16 #2
Hardware name: Dell Inc. OptiPlex 780  /0C27VV, BIOS A05 08/11/2010
Workqueue: events_freezable ieee80211_restart_work [mac80211]
task: ffff8ed6d13b0c80 task.stack: ffffaec64372c000
RIP: 0010:ieee80211_assign_chanctx.part.16+0x15e/0x170 [mac80211]
RSP: 0018:ffffaec64372fdb0 EFLAGS: 00010282
RAX: 000000000000003c RBX: ffff8ed682380780 RCX: 0000000000000000
RDX: ffff8ed6fd85d130 RSI: ffff8ed6fd855518 RDI: ffff8ed6fd855518
RBP: ffff8ed682380780 R08: 0000000000000001 R09: 0000000000000779
R10: ffff8ed682381560 R11: 0000000000000779 R12: ffff8ed6f5b0e8c0
R13: ffff8ed682381198 R14: ffff8ed6f5b92f58 R15: ffff8ed6f5b0e8c0
FS:  0000000000000000(0000) GS:ffff8ed6fd840000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007fe13bcba00a CR3: 000000005d140000 CR4: 00000000000406e0
Call Trace:
 ieee80211_reconfig+0xc7f/0x1300 [mac80211]
 ? try_to_del_timer_sync+0x3d/0x50
 ieee80211_restart_work+0x99/0xc0 [mac80211]
 process_one_work+0x139/0x400
 worker_thread+0x47/0x430
 kthread+0xfc/0x130
 ? process_one_work+0x400/0x400
 ? kthread_create_on_node+0x40/0x40
 ret_from_fork+0x35/0x40
Code: 45 31 e4 e9 46 ff ff ff 49 8b 84 24 00 04 00 00 49 8d b4 24 20 04 00 00 48 c7 c7 70 71 77 c0 48 85 c0 48 0f 45 f0 e8 0d 19 9b df <0f> ff e9 26 ff ff ff 90 66 2e 0f 1f 84 00 00 00 00 00 66 66 66 
---[ end trace d5e6e93890bc3ea5 ]---



hostapd.conf
---------------------------------------------------------------------------
interface=phy0ap
bridge=brg0
driver=nl80211
logger_syslog=-1
logger_syslog_level=4
logger_stdout=-1
logger_stdout_level=4
country_code=US
ieee80211d=1
hw_mode=a

wds_sta=1

channel=36
ctrl_interface=/var/run/hostapd
ctrl_interface_group=0
beacon_int=200

ap_table_max_size=63
ap_table_expiration_time=300
local_pwr_constraint=3
ieee80211h=1

bssid=04:f0:21:3b:2f:78
ctrl_interface=/var/run/hostapd
ctrl_interface_group=0
ssid=4-addr-ap
dtim_period=2
max_num_sta=64
macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
wmm_enabled=1
ap_max_inactivity=300

ieee80211w=0
ieee8021x=0
#---------end of hostapd.conf---------------------------------------------




wpa_supplicant.conf
#------------------------------------------------------------------------
ctrl_interface=/var/run/wpa_supplicant

network={
	ssid="4-addr-ap"
	scan_ssid=1
	key_mgmt=NONE
}
#---------end of wpa_supplicant.conf------------------------------------


BTW: The Linux distribution should not matter. I use Slackware Linux on the PC 
	acting as AP because Slackware Linux use exact mainline kernel source 
	without any patching. Kernel source from kernel.org can be just compiled
    and dropped in.
I can also send you the radio card "Intel

^ permalink raw reply

* [PATCH] ath10k: Fix length of wmi tlv command for protected mgmt frames
From: Surabhi Vishnoi @ 2019-02-15 15:19 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Surabhi Vishnoi

The length of wmi tlv command for management tx send is calculated
incorrectly in case of protected management frames as there is addition
of IEEE80211_CCMP_MIC_LEN twice. This leads to improper behaviour of
firmware as the wmi tlv mgmt tx send command for protected mgmt frames
is formed wrongly.

Fix the length calculation of wmi tlv command for mgmt tx send in case
of protected management frames by adding the IEEE80211_CCMP_MIC_LEN only
once.

Tested HW: WCN3990
Tested FW: WLAN.HL.3.1-00784-QCAHLSWMTPLZ-1

Fixes: 1807da49733e "ath10k: wmi: add management tx by reference support over wmi"
Signed-off-by: Surabhi Vishnoi <svishnoi@codeaurora.org>
---
 drivers/net/wireless/ath/ath10k/wmi-tlv.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index 5d05bff..a1c28c1 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -2764,10 +2764,8 @@ static void *ath10k_wmi_tlv_put_wmm(void *ptr,
 	if ((ieee80211_is_action(hdr->frame_control) ||
 	     ieee80211_is_deauth(hdr->frame_control) ||
 	     ieee80211_is_disassoc(hdr->frame_control)) &&
-	     ieee80211_has_protected(hdr->frame_control)) {
-		len += IEEE80211_CCMP_MIC_LEN;
+	     ieee80211_has_protected(hdr->frame_control))
 		buf_len += IEEE80211_CCMP_MIC_LEN;
-	}
 
 	buf_len = min_t(u32, buf_len, WMI_TLV_MGMT_TX_FRAME_MAX_LEN);
 	buf_len = round_up(buf_len, 4);
-- 
1.9.1


^ 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