Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: pull-request: mac80211 2017-10-16
From: Jason A. Donenfeld @ 2017-10-16 23:30 UTC (permalink / raw)
  To: Johannes Berg; +Cc: David Miller, netdev, linux-wireless
In-Reply-To: <20171016134618.30810-1-johannes@sipsolutions.net>

Mobile phone right now, so not able to write patch, but you probably
should be using crypto_memneq for comparing those two keys, not
memcmp.

Jason

^ permalink raw reply

* [PATCH] staging/wilc1000: Convert timers to use timer_setup()
From: Kees Cook @ 2017-10-16 23:24 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Aditya Shankar, Ganesh Krishna, linux-wireless, devel,
	linux-kernel

As part of removing the timer_list.data field, this converts the wilc1000
driver to using from_timer and an explicit per-timer data field, since
there doesn't appear to be a way to sanely resolve vif from hif_drv.

Cc: Aditya Shankar <aditya.shankar@microchip.com>
Cc: Ganesh Krishna <ganesh.krishna@microchip.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-wireless@vger.kernel.org
Cc: devel@driverdev.osuosl.org
Signed-off-by: Kees Cook <keescook@chromium.org>
---
 drivers/staging/wilc1000/host_interface.c         | 39 +++++++++++++----------
 drivers/staging/wilc1000/host_interface.h         |  5 +++
 drivers/staging/wilc1000/wilc_wfi_cfgoperations.c |  4 +--
 3 files changed, 28 insertions(+), 20 deletions(-)

diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c
index 7b620658ec38..c16f96308a97 100644
--- a/drivers/staging/wilc1000/host_interface.c
+++ b/drivers/staging/wilc1000/host_interface.c
@@ -238,6 +238,7 @@ static struct completion hif_driver_comp;
 static struct completion hif_wait_response;
 static struct mutex hif_deinit_lock;
 static struct timer_list periodic_rssi;
+static struct wilc_vif *periodic_rssi_vif;
 
 u8 wilc_multicast_mac_addr_list[WILC_MULTICAST_TABLE_SIZE][ETH_ALEN];
 
@@ -2272,7 +2273,7 @@ static int Handle_RemainOnChan(struct wilc_vif *vif,
 ERRORHANDLER:
 	{
 		P2P_LISTEN_STATE = 1;
-		hif_drv->remain_on_ch_timer.data = (unsigned long)vif;
+		hif_drv->remain_on_ch_timer_vif = vif;
 		mod_timer(&hif_drv->remain_on_ch_timer,
 			  jiffies +
 			  msecs_to_jiffies(pstrHostIfRemainOnChan->duration));
@@ -2360,11 +2361,13 @@ static u32 Handle_ListenStateExpired(struct wilc_vif *vif,
 	return result;
 }
 
-static void ListenTimerCB(unsigned long arg)
+static void ListenTimerCB(struct timer_list *t)
 {
+	struct host_if_drv *hif_drv = from_timer(hif_drv, t,
+						      remain_on_ch_timer);
+	struct wilc_vif *vif = hif_drv->remain_on_ch_timer_vif;
 	s32 result = 0;
 	struct host_if_msg msg;
-	struct wilc_vif *vif = (struct wilc_vif *)arg;
 
 	del_timer(&vif->hif_drv->remain_on_ch_timer);
 
@@ -2643,9 +2646,10 @@ static void host_if_work(struct work_struct *work)
 	complete(&hif_thread_comp);
 }
 
-static void TimerCB_Scan(unsigned long arg)
+static void TimerCB_Scan(struct timer_list *t)
 {
-	struct wilc_vif *vif = (struct wilc_vif *)arg;
+	struct host_if_drv *hif_drv = from_timer(hif_drv, t, scan_timer);
+	struct wilc_vif *vif = hif_drv->scan_timer_vif;
 	struct host_if_msg msg;
 
 	memset(&msg, 0, sizeof(struct host_if_msg));
@@ -2655,9 +2659,11 @@ static void TimerCB_Scan(unsigned long arg)
 	wilc_enqueue_cmd(&msg);
 }
 
-static void TimerCB_Connect(unsigned long arg)
+static void TimerCB_Connect(struct timer_list *t)
 {
-	struct wilc_vif *vif = (struct wilc_vif *)arg;
+	struct host_if_drv *hif_drv = from_timer(hif_drv, t,
+						      connect_timer);
+	struct wilc_vif *vif = hif_drv->connect_timer_vif;
 	struct host_if_msg msg;
 
 	memset(&msg, 0, sizeof(struct host_if_msg));
@@ -3040,7 +3046,7 @@ int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ssid,
 		return -EFAULT;
 	}
 
-	hif_drv->connect_timer.data = (unsigned long)vif;
+	hif_drv->connect_timer_vif = vif;
 	mod_timer(&hif_drv->connect_timer,
 		  jiffies + msecs_to_jiffies(HOST_IF_CONNECT_TIMEOUT));
 
@@ -3283,7 +3289,7 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
 		return -EINVAL;
 	}
 
-	hif_drv->scan_timer.data = (unsigned long)vif;
+	hif_drv->scan_timer_vif = vif;
 	mod_timer(&hif_drv->scan_timer,
 		  jiffies + msecs_to_jiffies(HOST_IF_SCAN_TIMEOUT));
 
@@ -3309,9 +3315,9 @@ int wilc_hif_set_cfg(struct wilc_vif *vif,
 	return wilc_enqueue_cmd(&msg);
 }
 
-static void GetPeriodicRSSI(unsigned long arg)
+static void GetPeriodicRSSI(struct timer_list *unused)
 {
-	struct wilc_vif *vif = (struct wilc_vif *)arg;
+	struct wilc_vif *vif = periodic_rssi_vif;
 
 	if (!vif->hif_drv) {
 		netdev_err(vif->ndev, "Driver handler is NULL\n");
@@ -3321,7 +3327,6 @@ static void GetPeriodicRSSI(unsigned long arg)
 	if (vif->hif_drv->hif_state == HOST_IF_CONNECTED)
 		wilc_get_statistics(vif, &vif->wilc->dummy_statistics);
 
-	periodic_rssi.data = (unsigned long)vif;
 	mod_timer(&periodic_rssi, jiffies + msecs_to_jiffies(5000));
 }
 
@@ -3374,14 +3379,14 @@ int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler)
 			goto _fail_;
 		}
 
-		setup_timer(&periodic_rssi, GetPeriodicRSSI,
-			    (unsigned long)vif);
+		periodic_rssi_vif = vif;
+		timer_setup(&periodic_rssi, GetPeriodicRSSI, 0);
 		mod_timer(&periodic_rssi, jiffies + msecs_to_jiffies(5000));
 	}
 
-	setup_timer(&hif_drv->scan_timer, TimerCB_Scan, 0);
-	setup_timer(&hif_drv->connect_timer, TimerCB_Connect, 0);
-	setup_timer(&hif_drv->remain_on_ch_timer, ListenTimerCB, 0);
+	timer_setup(&hif_drv->scan_timer, TimerCB_Scan, 0);
+	timer_setup(&hif_drv->connect_timer, TimerCB_Connect, 0);
+	timer_setup(&hif_drv->remain_on_ch_timer, ListenTimerCB, 0);
 
 	mutex_init(&hif_drv->cfg_values_lock);
 	mutex_lock(&hif_drv->cfg_values_lock);
diff --git a/drivers/staging/wilc1000/host_interface.h b/drivers/staging/wilc1000/host_interface.h
index 1ce5ead318c7..65734c38bf43 100644
--- a/drivers/staging/wilc1000/host_interface.h
+++ b/drivers/staging/wilc1000/host_interface.h
@@ -279,8 +279,13 @@ struct host_if_drv {
 	struct completion comp_inactive_time;
 
 	struct timer_list scan_timer;
+	struct wilc_vif *scan_timer_vif;
+
 	struct timer_list connect_timer;
+	struct wilc_vif *connect_timer_vif;
+
 	struct timer_list remain_on_ch_timer;
+	struct wilc_vif *remain_on_ch_timer_vif;
 
 	bool IFC_UP;
 	int driver_handler_id;
diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
index e7882b24a338..9241a387f528 100644
--- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
+++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
@@ -266,7 +266,7 @@ static void update_scan_time(void)
 		last_scanned_shadow[i].time_scan = jiffies;
 }
 
-static void remove_network_from_shadow(unsigned long arg)
+static void remove_network_from_shadow(unsigned long unused)
 {
 	unsigned long now = jiffies;
 	int i, j;
@@ -287,7 +287,6 @@ static void remove_network_from_shadow(unsigned long arg)
 	}
 
 	if (last_scanned_cnt != 0) {
-		hAgingTimer.data = arg;
 		mod_timer(&hAgingTimer, jiffies + msecs_to_jiffies(AGING_TIME));
 	}
 }
@@ -304,7 +303,6 @@ static int is_network_in_shadow(struct network_info *pstrNetworkInfo,
 	int i;
 
 	if (last_scanned_cnt == 0) {
-		hAgingTimer.data = (unsigned long)user_void;
 		mod_timer(&hAgingTimer, jiffies + msecs_to_jiffies(AGING_TIME));
 		state = -1;
 	} else {
-- 
2.7.4


-- 
Kees Cook
Pixel Security

^ permalink raw reply related

* Re: [PATCH] bcma: use bcma_debug and pr_cont in MIPS driver
From: Hauke Mehrtens @ 2017-10-16 21:21 UTC (permalink / raw)
  To: Rafał Miłecki, Kalle Valo, linux-wireless
  Cc: Rafał Miłecki
In-Reply-To: <20171016125432.11655-1-zajec5@gmail.com>

On 10/16/2017 02:54 PM, Rafał Miłecki wrote:
> From: Rafał Miłecki <rafal@milecki.pl>
> 
> Using bcma_debug gives a device-specific prefix for messages and pr_cont
> is a common helper for continuing a line.
> 
> Signed-off-by: Rafał Miłecki <rafal@milecki.pl>

Acked-By: Hauke Mehrtens <hauke@hauke-m.de>

> ---
>  drivers/bcma/driver_mips.c | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c
> index 89af807cf29c..5904ef1aa624 100644
> --- a/drivers/bcma/driver_mips.c
> +++ b/drivers/bcma/driver_mips.c
> @@ -184,10 +184,11 @@ static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
>  {
>  	int i;
>  	static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
> -	printk(KERN_DEBUG KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
> +
> +	bcma_debug(dev->bus, "core 0x%04x, irq :", dev->id.id);
>  	for (i = 0; i <= 6; i++)
> -		printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
> -	printk("\n");
> +		pr_cont(" %s%s", irq_name[i], i == irq ? "*" : " ");
> +	pr_cont("\n");
>  }
>  
>  static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
> 

^ permalink raw reply

* Re: pull-request: mac80211 2017-10-16
From: David Miller @ 2017-10-16 20:29 UTC (permalink / raw)
  To: johannes; +Cc: netdev, linux-wireless
In-Reply-To: <20171016134618.30810-1-johannes@sipsolutions.net>

From: Johannes Berg <johannes@sipsolutions.net>
Date: Mon, 16 Oct 2017 15:46:17 +0200

> Here's a fix, for a small part of the "KRACK" announced today
> (krackattacks.com).
> 
> Please pull and let me know if there's any problem.

Pulled.

^ permalink raw reply

* Re: [PATCH 0/8] qtnfmac: misc small features and fixes
From: Igor Mitsyanko @ 2017-10-16 19:22 UTC (permalink / raw)
  To: Sergey Matyukevich, linux-wireless; +Cc: Avinash Patil, Vasily Ulyanov
In-Reply-To: <20171015205327.9966-1-sergey.matyukevich.os@quantenna.com>

On 10/15/2017 01:53 PM, Sergey Matyukevich wrote:
> Hello Kalle, Igor, and all
> 
> This patch series includes a number of small features and fixes
> for qtnfmac driver.
> 
> Igor Mitsyanko (1):
>   qtnfmac: advertise support of inactivity timeout
> 
> Sergey Matyukevich (4):
>   qtnfmac: modify full Tx queue error reporting
>   qtnfmac: enable registration of more mgmt frames
>   qtnfmac: drop nonexistent function declaration
>   qtnfmac: modify full Tx queue recovery
> 
> 
>   drivers/net/wireless/quantenna/qtnfmac/cfg80211.c            |   17 +++++++++++++++--
>   drivers/net/wireless/quantenna/qtnfmac/commands.c            |    5 +++--
>   drivers/net/wireless/quantenna/qtnfmac/core.c                |   27 +++++++++++++++++++++++++++
>   drivers/net/wireless/quantenna/qtnfmac/core.h                |    4 +---
>   drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c          |   15 +++++++++------
>   drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h |    1 +
>   drivers/net/wireless/quantenna/qtnfmac/qlink.h               |   11 ++++++++++-
>   7 files changed, 66 insertions(+), 14 deletions(-)
> 

Reviewed-by: Igor Mitsyanko <igor.mitsyanko.os@quantenna.com>

^ permalink raw reply

* Re: [PATCH] iw: add command to register and capture mgmt frames
From: Igor Mitsyanko @ 2017-10-16 19:17 UTC (permalink / raw)
  To: Johannes Berg, Sergey Matyukevich
  Cc: Steve deRosier, linux-wireless, Avinash Patil, Julian Calaby
In-Reply-To: <1508145899.10607.30.camel@sipsolutions.net>

On 10/16/2017 02:24 AM, Johannes Berg wrote:
> 
> 
> Right, and I didn't originally see the patch as such, just that the
> discussion (and in particular Julian's suggestion) veered off in that
> direction.
> 
>> Nevertheless in certain cases it is handy to dump selected types of
>> mgmt frames while system is up and running without adding the whole
>> monitor overhead. The idea was that NL80211_CMD_REGISTER_FRAME and iw
>> are the right tools for that task. Anyway, iw is something like a
>> 'swiss-army-knife' tool for various tasks related to
>> mac80211/cfg80211 reporting and troubleshooting.
> 
> I'd see this particular feature in iw more as a way to debug the
> registrations, but whatever you ultimately want to use it for I neither
> can nor want to control :-)
> 

Maybe we could add an additional nl attribute to 
NL80211_CMD_REGISTER_FRAME command to allow applications to advertise 
what is their intention, something like NL80211_ATTR_MGMT_LISTENER_TYPE. 
Only allow to register more then one listener if it explicitly specifies 
that it will not try to answer (TYPE_LISTEN_ONLY or smth like that).
This will preserve behavior for existing userspace.

^ permalink raw reply

* [PATCH 1/2] mac80211: Add TXQ scheduling API
From: Toke Høiland-Jørgensen @ 2017-10-16 16:09 UTC (permalink / raw)
  To: make-wifi-fast, linux-wireless; +Cc: Toke Høiland-Jørgensen

This adds an API to mac80211 to handle scheduling of TXQs and changes the
interface between driver and mac80211 for TXQ handling as follows:

- The wake_tx_queue callback interface no longer includes the TXQ. Instead, the
  driver is expected to retrieve that from ieee80211_next_txq()

- Two new mac80211 functions are added: ieee80211_next_txq() and
  ieee80211_schedule_txq(). The former returns the next TXQ that should be
  scheduled, and is how the driver gets a queue to pull packets from. The latter
  is called internally by mac80211 to start scheduling a queue, and the driver
  is supposed to call it to re-schedule the TXQ after it is finished pulling
  packets from it (unless the queue emptied).

The ath9k and ath10k drivers are changed to use the new API.

Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
---
Changes since the RFC:

- Don't call wake_tx_queue() if the TXQ was already scheduled.
- Fold ath9k and ath9k patches into this one.
- Don't mess with the powersave buffering behaviour, but keep the old
  driver behaviour for that (haven't tested with powersave enabled,
  though...).
- A couple of adjustments to ath9k behaviour after testing.

I don't have ath10k hardware handy, so this is untested on ath10k.
However, ath10k required way less surgery to support the new API than
ath9k did....

 drivers/net/wireless/ath/ath10k/core.c |   2 -
 drivers/net/wireless/ath/ath10k/core.h |   3 -
 drivers/net/wireless/ath/ath10k/mac.c  |  54 +++------
 drivers/net/wireless/ath/ath9k/ath9k.h |   6 +-
 drivers/net/wireless/ath/ath9k/main.c  |   2 +-
 drivers/net/wireless/ath/ath9k/xmit.c  | 209 ++++++++-------------------------
 include/net/mac80211.h                 |  35 +++++-
 net/mac80211/agg-tx.c                  |   6 +-
 net/mac80211/driver-ops.h              |  12 +-
 net/mac80211/ieee80211_i.h             |   4 +
 net/mac80211/main.c                    |   3 +
 net/mac80211/sta_info.c                |   5 +-
 net/mac80211/trace.h                   |  21 +---
 net/mac80211/tx.c                      |  48 +++++++-
 14 files changed, 167 insertions(+), 243 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index a4f635820f35..759df3297d48 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -2561,9 +2561,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
 
 	mutex_init(&ar->conf_mutex);
 	spin_lock_init(&ar->data_lock);
-	spin_lock_init(&ar->txqs_lock);
 
-	INIT_LIST_HEAD(&ar->txqs);
 	INIT_LIST_HEAD(&ar->peers);
 	init_waitqueue_head(&ar->peer_mapping_wq);
 	init_waitqueue_head(&ar->htt.empty_tx_wq);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 949ebb3e967b..e7fc241addf6 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -892,10 +892,7 @@ struct ath10k {
 
 	/* protects shared structure data */
 	spinlock_t data_lock;
-	/* protects: ar->txqs, artxq->list */
-	spinlock_t txqs_lock;
 
-	struct list_head txqs;
 	struct list_head arvifs;
 	struct list_head peers;
 	struct ath10k_peer *peer_map[ATH10K_MAX_NUM_PEER_IDS];
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 5683f1a5330e..43ea23af8255 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -3825,7 +3825,6 @@ static void ath10k_mac_txq_init(struct ieee80211_txq *txq)
 
 static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq)
 {
-	struct ath10k_txq *artxq;
 	struct ath10k_skb_cb *cb;
 	struct sk_buff *msdu;
 	int msdu_id;
@@ -3833,12 +3832,6 @@ static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq)
 	if (!txq)
 		return;
 
-	artxq = (void *)txq->drv_priv;
-	spin_lock_bh(&ar->txqs_lock);
-	if (!list_empty(&artxq->list))
-		list_del_init(&artxq->list);
-	spin_unlock_bh(&ar->txqs_lock);
-
 	spin_lock_bh(&ar->htt.tx_lock);
 	idr_for_each_entry(&ar->htt.pending_tx, msdu, msdu_id) {
 		cb = ATH10K_SKB_CB(msdu);
@@ -3968,23 +3961,17 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw,
 void ath10k_mac_tx_push_pending(struct ath10k *ar)
 {
 	struct ieee80211_hw *hw = ar->hw;
-	struct ieee80211_txq *txq;
-	struct ath10k_txq *artxq;
-	struct ath10k_txq *last;
+	struct ieee80211_txq *txq, *first = NULL;
 	int ret;
 	int max;
 
 	if (ar->htt.num_pending_tx >= (ar->htt.max_num_pending_tx / 2))
 		return;
 
-	spin_lock_bh(&ar->txqs_lock);
 	rcu_read_lock();
 
-	last = list_last_entry(&ar->txqs, struct ath10k_txq, list);
-	while (!list_empty(&ar->txqs)) {
-		artxq = list_first_entry(&ar->txqs, struct ath10k_txq, list);
-		txq = container_of((void *)artxq, struct ieee80211_txq,
-				   drv_priv);
+	txq = ieee80211_next_txq(hw);
+	while (txq) {
 
 		/* Prevent aggressive sta/tid taking over tx queue */
 		max = 16;
@@ -3995,18 +3982,21 @@ void ath10k_mac_tx_push_pending(struct ath10k *ar)
 				break;
 		}
 
-		list_del_init(&artxq->list);
 		if (ret != -ENOENT)
-			list_add_tail(&artxq->list, &ar->txqs);
+			ieee80211_schedule_txq(hw, txq);
 
 		ath10k_htt_tx_txq_update(hw, txq);
 
-		if (artxq == last || (ret < 0 && ret != -ENOENT))
+		if (first == txq || (ret < 0 && ret != -ENOENT))
 			break;
+
+		if (!first)
+			first = txq;
+
+		txq = ieee80211_next_txq(hw);
 	}
 
 	rcu_read_unlock();
-	spin_unlock_bh(&ar->txqs_lock);
 }
 
 /************/
@@ -4240,34 +4230,22 @@ static void ath10k_mac_op_tx(struct ieee80211_hw *hw,
 	}
 }
 
-static void ath10k_mac_op_wake_tx_queue(struct ieee80211_hw *hw,
-					struct ieee80211_txq *txq)
+static void ath10k_mac_op_wake_tx_queue(struct ieee80211_hw *hw)
 {
-	struct ath10k *ar = hw->priv;
-	struct ath10k_txq *artxq = (void *)txq->drv_priv;
-	struct ieee80211_txq *f_txq;
-	struct ath10k_txq *f_artxq;
+	struct ieee80211_txq *txq;
 	int ret = 0;
 	int max = 16;
 
-	spin_lock_bh(&ar->txqs_lock);
-	if (list_empty(&artxq->list))
-		list_add_tail(&artxq->list, &ar->txqs);
-
-	f_artxq = list_first_entry(&ar->txqs, struct ath10k_txq, list);
-	f_txq = container_of((void *)f_artxq, struct ieee80211_txq, drv_priv);
-	list_del_init(&f_artxq->list);
+	txq = ieee80211_next_txq(hw);
 
-	while (ath10k_mac_tx_can_push(hw, f_txq) && max--) {
-		ret = ath10k_mac_tx_push_txq(hw, f_txq);
+	while (ath10k_mac_tx_can_push(hw, txq) && max--) {
+		ret = ath10k_mac_tx_push_txq(hw, txq);
 		if (ret)
 			break;
 	}
 	if (ret != -ENOENT)
-		list_add_tail(&f_artxq->list, &ar->txqs);
-	spin_unlock_bh(&ar->txqs_lock);
+		ieee80211_schedule_txq(hw, txq);
 
-	ath10k_htt_tx_txq_update(hw, f_txq);
 	ath10k_htt_tx_txq_update(hw, txq);
 }
 
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index cf076719c27e..f6c53df78856 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -246,7 +246,6 @@ struct ath_atx_tid {
 	s8 bar_index;
 	bool active;
 	bool clear_ps_filter;
-	bool has_queued;
 };
 
 void __ath_tx_queue_tid(struct ath_softc *sc, struct ath_atx_tid *tid);
@@ -591,8 +590,7 @@ bool ath_drain_all_txq(struct ath_softc *sc);
 void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq);
 void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
 void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
-void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
-void ath_txq_schedule_all(struct ath_softc *sc);
+void ath_txq_schedule(struct ath_softc *sc);
 int ath_tx_init(struct ath_softc *sc, int nbufs);
 int ath_txq_update(struct ath_softc *sc, int qnum,
 		   struct ath9k_tx_queue_info *q);
@@ -618,7 +616,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
 				   u16 tids, int nframes,
 				   enum ieee80211_frame_release_type reason,
 				   bool more_data);
-void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue);
+void ath9k_wake_tx_queue(struct ieee80211_hw *hw);
 
 /********/
 /* VIFs */
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 8b4ac7f0a09b..7c2ba21fd972 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -265,7 +265,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
 		}
 	work:
 		ath_restart_work(sc);
-		ath_txq_schedule_all(sc);
+		ath_txq_schedule(sc);
 	}
 
 	sc->gtt_cnt = 0;
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 396bf05c6bf6..4256701500ff 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -112,62 +112,11 @@ void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq)
 		ath_tx_status(hw, skb);
 }
 
-void __ath_tx_queue_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
-{
-	struct ath_vif *avp = (struct ath_vif *) tid->an->vif->drv_priv;
-	struct ath_chanctx *ctx = avp->chanctx;
-	struct ath_acq *acq;
-	struct list_head *tid_list;
-	u8 acno = TID_TO_WME_AC(tid->tidno);
-
-	if (!ctx || !list_empty(&tid->list))
-		return;
-
-
-	acq = &ctx->acq[acno];
-	if ((sc->airtime_flags & AIRTIME_USE_NEW_QUEUES) &&
-	    tid->an->airtime_deficit[acno] > 0)
-		tid_list = &acq->acq_new;
-	else
-		tid_list = &acq->acq_old;
-
-	list_add_tail(&tid->list, tid_list);
-}
-
-void ath_tx_queue_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
-{
-	struct ath_vif *avp = (struct ath_vif *) tid->an->vif->drv_priv;
-	struct ath_chanctx *ctx = avp->chanctx;
-	struct ath_acq *acq;
-
-	if (!ctx || !list_empty(&tid->list))
-		return;
-
-	acq = &ctx->acq[TID_TO_WME_AC(tid->tidno)];
-	spin_lock_bh(&acq->lock);
-	__ath_tx_queue_tid(sc, tid);
-	spin_unlock_bh(&acq->lock);
-}
-
-
-void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue)
+void ath9k_wake_tx_queue(struct ieee80211_hw *hw)
 {
 	struct ath_softc *sc = hw->priv;
-	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-	struct ath_atx_tid *tid = (struct ath_atx_tid *) queue->drv_priv;
-	struct ath_txq *txq = tid->txq;
-
-	ath_dbg(common, QUEUE, "Waking TX queue: %pM (%d)\n",
-		queue->sta ? queue->sta->addr : queue->vif->addr,
-		tid->tidno);
-
-	ath_txq_lock(sc, txq);
-
-	tid->has_queued = true;
-	ath_tx_queue_tid(sc, tid);
-	ath_txq_schedule(sc, txq);
 
-	ath_txq_unlock(sc, txq);
+	ath_txq_schedule(sc);
 }
 
 static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
@@ -230,14 +179,9 @@ ath_tid_pull(struct ath_atx_tid *tid)
 	struct ath_frame_info *fi;
 	int q;
 
-	if (!tid->has_queued)
-		return NULL;
-
 	skb = ieee80211_tx_dequeue(hw, txq);
-	if (!skb) {
-		tid->has_queued = false;
+	if (!skb)
 		return NULL;
-	}
 
 	if (ath_tx_prepare(hw, skb, &txctl)) {
 		ieee80211_free_txskb(hw, skb);
@@ -254,12 +198,6 @@ ath_tid_pull(struct ath_atx_tid *tid)
 	return skb;
  }
 
-
-static bool ath_tid_has_buffered(struct ath_atx_tid *tid)
-{
-	return !skb_queue_empty(&tid->retry_q) || tid->has_queued;
-}
-
 static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid)
 {
 	struct sk_buff *skb;
@@ -671,7 +609,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 
 		skb_queue_splice_tail(&bf_pending, &tid->retry_q);
 		if (!an->sleeping) {
-			ath_tx_queue_tid(sc, tid);
+			struct ieee80211_txq *queue = container_of((void*)tid, struct ieee80211_txq, drv_priv);
+			ieee80211_schedule_txq(sc->hw, queue);
 
 			if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY))
 				tid->clear_ps_filter = true;
@@ -719,8 +658,6 @@ static void ath_tx_count_airtime(struct ath_softc *sc, struct ath_node *an,
 
 		spin_lock_bh(&acq->lock);
 		an->airtime_deficit[q] -= airtime;
-		if (an->airtime_deficit[q] <= 0)
-			__ath_tx_queue_tid(sc, tid);
 		spin_unlock_bh(&acq->lock);
 	}
 	ath_debug_airtime(sc, an, 0, airtime);
@@ -770,8 +707,6 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
 	} else
 		ath_tx_complete_aggr(sc, txq, bf, bf_head, sta, tid, ts, txok);
 
-	if (!flush)
-		ath_txq_schedule(sc, txq);
 }
 
 static bool ath_lookup_legacy(struct ath_buf *bf)
@@ -1506,7 +1441,7 @@ ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
 	} while (1);
 }
 
-static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
+static int ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
 			      struct ath_atx_tid *tid)
 {
 	struct ath_buf *bf;
@@ -1515,21 +1450,18 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
 	int aggr_len = 0;
 	bool aggr;
 
-	if (!ath_tid_has_buffered(tid))
-		return false;
-
 	INIT_LIST_HEAD(&bf_q);
 
 	bf = ath_tx_get_tid_subframe(sc, txq, tid);
 	if (!bf)
-		return false;
+		return -ENOENT;
 
 	tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
 	aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
 	if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) ||
 	    (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) {
 		__skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
-		return false;
+		return -ENOBUFS;
 	}
 
 	ath_set_rates(tid->an->vif, tid->an->sta, bf);
@@ -1539,7 +1471,7 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
 		ath_tx_form_burst(sc, txq, tid, &bf_q, bf);
 
 	if (list_empty(&bf_q))
-		return false;
+		return -ENOENT;
 
 	if (tid->clear_ps_filter || tid->an->no_ps_filter) {
 		tid->clear_ps_filter = false;
@@ -1548,7 +1480,7 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
 
 	ath_tx_fill_desc(sc, bf, txq, aggr_len);
 	ath_tx_txqaddbuf(sc, txq, &bf_q, false);
-	return true;
+	return 0;
 }
 
 int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
@@ -1611,53 +1543,49 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
 {
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_atx_tid *tid;
-	struct ath_txq *txq;
+	struct ieee80211_txq *queue;
 	int tidno;
 
 	ath_dbg(common, XMIT, "%s called\n", __func__);
 
 	for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
 		tid = ath_node_to_tid(an, tidno);
-		txq = tid->txq;
-
-		ath_txq_lock(sc, txq);
-
-		if (list_empty(&tid->list)) {
-			ath_txq_unlock(sc, txq);
-			continue;
-		}
+		queue = container_of((void*)tid, struct ieee80211_txq, drv_priv);
 
 		if (!skb_queue_empty(&tid->retry_q))
 			ieee80211_sta_set_buffered(sta, tid->tidno, true);
 
-		list_del_init(&tid->list);
-
-		ath_txq_unlock(sc, txq);
 	}
 }
 
 void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
 {
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct ieee80211_txq *queue;
 	struct ath_atx_tid *tid;
 	struct ath_txq *txq;
 	int tidno;
+	bool sched, wake = false;
 
 	ath_dbg(common, XMIT, "%s called\n", __func__);
 
 	for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
 		tid = ath_node_to_tid(an, tidno);
 		txq = tid->txq;
+		queue = container_of((void*)tid, struct ieee80211_txq, drv_priv);
 
 		ath_txq_lock(sc, txq);
 		tid->clear_ps_filter = true;
-		if (ath_tid_has_buffered(tid)) {
-			ath_tx_queue_tid(sc, tid);
-			ath_txq_schedule(sc, txq);
-		}
-		ath_txq_unlock_complete(sc, txq);
-	}
-}
+		sched = !skb_queue_empty(&tid->retry_q);
+		ath_txq_unlock(sc, txq);
+
+		if (sched)
+			wake = wake || ieee80211_schedule_txq(sc->hw, queue);
+ 	}
+	if (wake)
+		ath_txq_schedule(sc);
+ }
+
 
 void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
 				   struct ieee80211_sta *sta,
@@ -1948,86 +1876,44 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
 /* For each acq entry, for each tid, try to schedule packets
  * for transmit until ampdu_depth has reached min Q depth.
  */
-void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
+void ath_txq_schedule(struct ath_softc *sc)
 {
+	struct ieee80211_hw *hw = sc->hw;
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct ieee80211_txq *queue;
 	struct ath_atx_tid *tid;
-	struct list_head *tid_list;
-	struct ath_acq *acq;
-	bool active = AIRTIME_ACTIVE(sc->airtime_flags);
+	struct ath_txq *txq;
+	int ret = 0;
 
-	if (txq->mac80211_qnum < 0)
+	if (test_bit(ATH_OP_HW_RESET, &common->op_flags))
 		return;
 
-	if (test_bit(ATH_OP_HW_RESET, &common->op_flags))
+	queue = ieee80211_next_txq(hw);
+	if (!queue)
 		return;
 
-	spin_lock_bh(&sc->chan_lock);
-	rcu_read_lock();
-	acq = &sc->cur_chan->acq[txq->mac80211_qnum];
+	tid = (struct ath_atx_tid *)queue->drv_priv;
+	txq = tid->txq;
 
-	if (sc->cur_chan->stopped)
+	ath_txq_lock(sc, txq);
+	if (txq->mac80211_qnum < 0)
 		goto out;
 
-begin:
-	tid_list = &acq->acq_new;
-	if (list_empty(tid_list)) {
-		tid_list = &acq->acq_old;
-		if (list_empty(tid_list))
-			goto out;
-	}
-	tid = list_first_entry(tid_list, struct ath_atx_tid, list);
-
-	if (active && tid->an->airtime_deficit[txq->mac80211_qnum] <= 0) {
-		spin_lock_bh(&acq->lock);
-		tid->an->airtime_deficit[txq->mac80211_qnum] += ATH_AIRTIME_QUANTUM;
-		list_move_tail(&tid->list, &acq->acq_old);
-		spin_unlock_bh(&acq->lock);
-		goto begin;
-	}
-
-	if (!ath_tid_has_buffered(tid)) {
-		spin_lock_bh(&acq->lock);
-		if ((tid_list == &acq->acq_new) && !list_empty(&acq->acq_old))
-			list_move_tail(&tid->list, &acq->acq_old);
-		else {
-			list_del_init(&tid->list);
-		}
-		spin_unlock_bh(&acq->lock);
-		goto begin;
-	}
+	spin_lock_bh(&sc->chan_lock);
+	rcu_read_lock();
 
+	if (!sc->cur_chan->stopped)
+		ret = ath_tx_sched_aggr(sc, txq, tid);
 
-	/*
-	 * If we succeed in scheduling something, immediately restart to make
-	 * sure we keep the HW busy.
-	 */
-	if(ath_tx_sched_aggr(sc, txq, tid)) {
-		if (!active) {
-			spin_lock_bh(&acq->lock);
-			list_move_tail(&tid->list, &acq->acq_old);
-			spin_unlock_bh(&acq->lock);
-		}
-		goto begin;
-	}
-
-out:
 	rcu_read_unlock();
 	spin_unlock_bh(&sc->chan_lock);
-}
 
-void ath_txq_schedule_all(struct ath_softc *sc)
-{
-	struct ath_txq *txq;
-	int i;
+out:
 
-	for (i = 0; i < IEEE80211_NUM_ACS; i++) {
-		txq = sc->tx.txq_map[i];
+	if (ret != -ENOENT)
+		ieee80211_schedule_txq(hw, queue);
 
-		spin_lock_bh(&txq->axq_lock);
-		ath_txq_schedule(sc, txq);
-		spin_unlock_bh(&txq->axq_lock);
-	}
+	ath_txq_unlock(sc, txq);
 }
 
 /***********/
@@ -2645,7 +2531,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
 
 		if (list_empty(&txq->axq_q)) {
 			txq->axq_link = NULL;
-			ath_txq_schedule(sc, txq);
 			break;
 		}
 		bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
@@ -2697,6 +2582,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
 		ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
 	}
 	ath_txq_unlock_complete(sc, txq);
+	ath_txq_schedule(sc);
 }
 
 void ath_tx_tasklet(struct ath_softc *sc)
@@ -2711,6 +2597,7 @@ void ath_tx_tasklet(struct ath_softc *sc)
 			ath_tx_processq(sc, &sc->tx.txq[i]);
 	}
 	rcu_read_unlock();
+	ath_txq_schedule(sc);
 }
 
 void ath_tx_edma_tasklet(struct ath_softc *sc)
@@ -2796,6 +2683,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
 		ath_txq_unlock_complete(sc, txq);
 	}
 	rcu_read_unlock();
+	ath_txq_schedule(sc);
 }
 
 /*****************/
@@ -2875,7 +2763,6 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
 		tid->baw_head  = tid->baw_tail = 0;
 		tid->active	   = false;
 		tid->clear_ps_filter = true;
-		tid->has_queued  = false;
 		__skb_queue_head_init(&tid->retry_q);
 		INIT_LIST_HEAD(&tid->list);
 		acno = TID_TO_WME_AC(tidno);
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index cc9073e45be9..f0373dd3d714 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -105,9 +105,12 @@
  * The driver is expected to initialize its private per-queue data for stations
  * and interfaces in the .add_interface and .sta_add ops.
  *
- * The driver can't access the queue directly. To dequeue a frame, it calls
- * ieee80211_tx_dequeue(). Whenever mac80211 adds a new frame to a queue, it
- * calls the .wake_tx_queue driver op.
+ * The driver can't access the queue directly. To obtain the next queue to pull
+ * frames from, the driver calls ieee80211_next_txq(). To dequeue a frame from a
+ * txq, it calls ieee80211_tx_dequeue(). Whenever mac80211 adds a new frame to a
+ * queue, it calls the .wake_tx_queue driver op. The driver is expected to
+ * re-schedule the txq using ieee80211_schedule_txq() if it is still active
+ * after the driver has finished pulling packets from it.
  *
  * For AP powersave TIM handling, the driver only needs to indicate if it has
  * buffered packets in the driver specific data structures by calling
@@ -3723,8 +3726,7 @@ struct ieee80211_ops {
 					 struct ieee80211_vif *vif,
 					 struct ieee80211_tdls_ch_sw_params *params);
 
-	void (*wake_tx_queue)(struct ieee80211_hw *hw,
-			      struct ieee80211_txq *txq);
+	void (*wake_tx_queue)(struct ieee80211_hw *hw);
 	void (*sync_rx_queues)(struct ieee80211_hw *hw);
 
 	int (*start_nan)(struct ieee80211_hw *hw,
@@ -5876,6 +5878,29 @@ void ieee80211_unreserve_tid(struct ieee80211_sta *sta, u8 tid);
 struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
 				     struct ieee80211_txq *txq);
 
+/**
+ * ieee80211_schedule_txq - add txq to scheduling loop
+ *
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
+ * @txq: pointer obtained from station or virtual interface
+ *
+ * Returns true if the txq was actually added to the scheduling,
+ * false otherwise.
+ */
+bool ieee80211_schedule_txq(struct ieee80211_hw *hw,
+			    struct ieee80211_txq *txq);
+
+/**
+ * ieee80211_next_txq - get next tx queue to pull packets from
+ *
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
+ *
+ * Returns the next txq if successful, %NULL if no queue is eligible. If a txq
+ * is returned, it will have been removed from the scheduler queue and needs to
+ * be re-scheduled with ieee80211_schedule_txq() to continue to be active.
+ */
+struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw);
+
 /**
  * ieee80211_txq_get_depth - get pending frame/byte count of given txq
  *
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index bef516ec47f9..569b5b5c6d70 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -226,9 +226,13 @@ ieee80211_agg_start_txq(struct sta_info *sta, int tid, bool enable)
 		clear_bit(IEEE80211_TXQ_AMPDU, &txqi->flags);
 
 	clear_bit(IEEE80211_TXQ_STOP, &txqi->flags);
+
+	if (!ieee80211_schedule_txq(&sta->sdata->local->hw, txq))
+		return;
+
 	local_bh_disable();
 	rcu_read_lock();
-	drv_wake_tx_queue(sta->sdata->local, txqi);
+	drv_wake_tx_queue(sta->sdata->local);
 	rcu_read_unlock();
 	local_bh_enable();
 }
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 09f77e4a8a79..e20a9e2acd53 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1157,16 +1157,10 @@ drv_tdls_recv_channel_switch(struct ieee80211_local *local,
 	trace_drv_return_void(local);
 }
 
-static inline void drv_wake_tx_queue(struct ieee80211_local *local,
-				     struct txq_info *txq)
+static inline void drv_wake_tx_queue(struct ieee80211_local *local)
 {
-	struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->txq.vif);
-
-	if (!check_sdata_in_driver(sdata))
-		return;
-
-	trace_drv_wake_tx_queue(local, sdata, txq);
-	local->ops->wake_tx_queue(&local->hw, &txq->txq);
+	trace_drv_wake_tx_queue(local);
+	local->ops->wake_tx_queue(&local->hw);
 }
 
 static inline int drv_start_nan(struct ieee80211_local *local,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 9675814f64db..48bf933435a8 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -832,6 +832,7 @@ struct txq_info {
 	struct codel_vars def_cvars;
 	struct codel_stats cstats;
 	struct sk_buff_head frags;
+	struct list_head schedule_order;
 	unsigned long flags;
 
 	/* keep last! */
@@ -1121,6 +1122,9 @@ struct ieee80211_local {
 	struct codel_vars *cvars;
 	struct codel_params cparams;
 
+	struct list_head active_txqs;
+	spinlock_t active_txq_lock;
+
 	const struct ieee80211_ops *ops;
 
 	/*
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 8aa1f5b6a051..9ad0556aa24b 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -616,6 +616,9 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
 	spin_lock_init(&local->rx_path_lock);
 	spin_lock_init(&local->queue_stop_reason_lock);
 
+	INIT_LIST_HEAD(&local->active_txqs);
+	spin_lock_init(&local->active_txq_lock);
+
 	INIT_LIST_HEAD(&local->chanctx_list);
 	mutex_init(&local->chanctx_mtx);
 
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 9673e157bf8f..5db76db6bfc8 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -1246,12 +1246,15 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
 		drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
 
 	if (sta->sta.txq[0]) {
+		bool wake = false;
 		for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
 			if (!txq_has_queue(sta->sta.txq[i]))
 				continue;
 
-			drv_wake_tx_queue(local, to_txq_info(sta->sta.txq[i]));
+			wake = wake || ieee80211_schedule_txq(&local->hw, sta->sta.txq[i]);
 		}
+		if (wake)
+			drv_wake_tx_queue(local);
 	}
 
 	skb_queue_head_init(&pending);
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 3d9ac17af407..531c0e7f2358 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -2550,33 +2550,20 @@ TRACE_EVENT(drv_tdls_recv_channel_switch,
 );
 
 TRACE_EVENT(drv_wake_tx_queue,
-	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata,
-		 struct txq_info *txq),
+	TP_PROTO(struct ieee80211_local *local),
 
-	TP_ARGS(local, sdata, txq),
+	TP_ARGS(local),
 
 	TP_STRUCT__entry(
 		LOCAL_ENTRY
-		VIF_ENTRY
-		STA_ENTRY
-		__field(u8, ac)
-		__field(u8, tid)
 	),
 
 	TP_fast_assign(
-		struct ieee80211_sta *sta = txq->txq.sta;
-
 		LOCAL_ASSIGN;
-		VIF_ASSIGN;
-		STA_ASSIGN;
-		__entry->ac = txq->txq.ac;
-		__entry->tid = txq->txq.tid;
 	),
-
 	TP_printk(
-		LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT " ac:%d tid:%d",
-		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->ac, __entry->tid
+		LOCAL_PR_FMT,
+		LOCAL_PR_ARG
 	)
 );
 
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 94826680cf2b..0ee6ea71d1c4 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1405,6 +1405,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);
 
 	txqi->txq.vif = &sdata->vif;
 
@@ -1428,6 +1429,7 @@ void ieee80211_txq_purge(struct ieee80211_local *local,
 
 	fq_tin_reset(fq, tin, fq_skb_free_func);
 	ieee80211_purge_tx_queue(&local->hw, &txqi->frags);
+	list_del_init(&txqi->schedule_order);
 }
 
 int ieee80211_txq_setup_flows(struct ieee80211_local *local)
@@ -1524,7 +1526,8 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local,
 	ieee80211_txq_enqueue(local, txqi, skb);
 	spin_unlock_bh(&fq->lock);
 
-	drv_wake_tx_queue(local, txqi);
+	if (ieee80211_schedule_txq(&local->hw, &txqi->txq))
+		drv_wake_tx_queue(local);
 
 	return true;
 }
@@ -3517,6 +3520,49 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
 }
 EXPORT_SYMBOL(ieee80211_tx_dequeue);
 
+bool ieee80211_schedule_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);
+	int ret = 0;
+
+	spin_lock_bh(&local->active_txq_lock);
+
+	if (list_empty(&txqi->schedule_order)) {
+		list_add_tail(&txqi->schedule_order, &local->active_txqs);
+		ret = 1;
+	}
+
+	spin_unlock_bh(&local->active_txq_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(ieee80211_schedule_txq);
+
+struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct txq_info *txqi = NULL;
+
+	spin_lock_bh(&local->active_txq_lock);
+
+	if (list_empty(&local->active_txqs))
+		goto out;
+
+	txqi = list_first_entry(&local->active_txqs, struct txq_info, schedule_order);
+	list_del_init(&txqi->schedule_order);
+
+out:
+	spin_unlock_bh(&local->active_txq_lock);
+
+	if (!txqi)
+		return NULL;
+
+	return &txqi->txq;
+}
+EXPORT_SYMBOL(ieee80211_next_txq);
+
 void __ieee80211_subif_start_xmit(struct sk_buff *skb,
 				  struct net_device *dev,
 				  u32 info_flags)
-- 
2.14.2

^ permalink raw reply related

* [PATCH 2/2] mac80211: Add airtime accounting and scheduling to TXQs
From: Toke Høiland-Jørgensen @ 2017-10-16 16:09 UTC (permalink / raw)
  To: make-wifi-fast, linux-wireless; +Cc: Toke Høiland-Jørgensen
In-Reply-To: <20171016160902.8970-1-toke@toke.dk>

This adds airtime accounting and scheduling to the mac80211 TXQ scheduler. A new
hardware flag, AIRTIME_ACCOUNTING, is added that drivers can set if they support
reporting airtime usage of transmissions. When this flag is set, mac80211 will
expect the actual airtime usage to be reported in the tx_time and rx_time fields
of the respective status structs.

When airtime information is present, mac80211 will schedule TXQs (through
ieee80211_next_txq()) in a way that enforces airtime fairness between active
stations. This scheduling works the same way as the ath9k in-driver airtime
fairness scheduling, which is then removed.

Only ath9k currently sets the AIRTIME_ACCOUNTING flag.

Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
---
Changes since the RFC:

- Don't try to calculate airtime usage in mac80211; instead, add a field to
  struct ieee80211_rx_status for the driver to fill in.
- Fold ath9k patch into this patch, and remove all the airtime bits from
  ath9k apart from the actual airtime accounting.
- Feature parity with the ath9k scheduler (in particular, the old/new
  station optimisation is retained).
- Add explicit hardware flag for the driver to signal that it supports
  airtime accounting and wants the scheduling.
- This has actually been tested... :)

 drivers/net/wireless/ath/ath9k/ath9k.h     |  7 +---
 drivers/net/wireless/ath/ath9k/debug.h     |  8 -----
 drivers/net/wireless/ath/ath9k/debug_sta.c | 54 ------------------------------
 drivers/net/wireless/ath/ath9k/init.c      |  4 +--
 drivers/net/wireless/ath/ath9k/recv.c      | 11 ++----
 drivers/net/wireless/ath/ath9k/xmit.c      | 21 ++++--------
 include/net/mac80211.h                     |  6 ++++
 net/mac80211/debugfs.c                     |  1 +
 net/mac80211/debugfs_sta.c                 | 29 ++++++++++++++++
 net/mac80211/ieee80211_i.h                 |  6 +++-
 net/mac80211/main.c                        |  3 +-
 net/mac80211/rx.c                          |  9 +++++
 net/mac80211/sta_info.c                    |  2 ++
 net/mac80211/sta_info.h                    |  7 ++++
 net/mac80211/status.c                      | 15 +++++++++
 net/mac80211/tx.c                          | 28 +++++++++++++---
 16 files changed, 112 insertions(+), 99 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index f6c53df78856..f6e8f9b1b984 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -112,8 +112,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
 #define ATH_TXFIFO_DEPTH           8
 #define ATH_TX_ERROR               0x01
 
-#define ATH_AIRTIME_QUANTUM        300 /* usec */
-
 /* Stop tx traffic 1ms before the GO goes away */
 #define ATH_P2P_PS_STOP_TIME       1000
 
@@ -215,6 +213,7 @@ struct ath_buf_state {
 	bool stale;
 	u16 seqno;
 	unsigned long bfs_paprd_timestamp;
+	u32 airtime;
 };
 
 struct ath_buf {
@@ -262,12 +261,9 @@ struct ath_node {
 
 	bool sleeping;
 	bool no_ps_filter;
-	s64 airtime_deficit[IEEE80211_NUM_ACS];
-	u32 airtime_rx_start;
 
 #ifdef CONFIG_ATH9K_STATION_STATISTICS
 	struct ath_rx_rate_stats rx_rate_stats;
-	struct ath_airtime_stats airtime_stats;
 #endif
 	u8 key_idx[4];
 
@@ -986,7 +982,6 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs);
 
 #define AIRTIME_USE_TX		BIT(0)
 #define AIRTIME_USE_RX		BIT(1)
-#define AIRTIME_USE_NEW_QUEUES	BIT(2)
 #define AIRTIME_ACTIVE(flags) (!!(flags & (AIRTIME_USE_TX|AIRTIME_USE_RX)))
 
 struct ath_softc {
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 249f8141cd00..559d9628f280 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -319,20 +319,12 @@ ath9k_debug_sync_cause(struct ath_softc *sc, u32 sync_cause)
 void ath_debug_rate_stats(struct ath_softc *sc,
 			  struct ath_rx_status *rs,
 			  struct sk_buff *skb);
-void ath_debug_airtime(struct ath_softc *sc,
-		       struct ath_node *an,
-		       u32 rx, u32 tx);
 #else
 static inline void ath_debug_rate_stats(struct ath_softc *sc,
 					struct ath_rx_status *rs,
 					struct sk_buff *skb)
 {
 }
-static inline void ath_debug_airtime(struct ath_softc *sc,
-			      struct ath_node *an,
-			      u32 rx, u32 tx)
-{
-}
 #endif /* CONFIG_ATH9K_STATION_STATISTICS */
 
 #endif /* DEBUG_H */
diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c b/drivers/net/wireless/ath/ath9k/debug_sta.c
index efc692ee67d4..89ba95287a8b 100644
--- a/drivers/net/wireless/ath/ath9k/debug_sta.c
+++ b/drivers/net/wireless/ath/ath9k/debug_sta.c
@@ -242,59 +242,6 @@ static const struct file_operations fops_node_recv = {
 	.llseek = default_llseek,
 };
 
-void ath_debug_airtime(struct ath_softc *sc,
-		struct ath_node *an,
-		u32 rx,
-		u32 tx)
-{
-	struct ath_airtime_stats *astats = &an->airtime_stats;
-
-	astats->rx_airtime += rx;
-	astats->tx_airtime += tx;
-}
-
-static ssize_t read_airtime(struct file *file, char __user *user_buf,
-			size_t count, loff_t *ppos)
-{
-	struct ath_node *an = file->private_data;
-	struct ath_airtime_stats *astats;
-	static const char *qname[4] = {
-		"VO", "VI", "BE", "BK"
-	};
-	u32 len = 0, size = 256;
-	char *buf;
-	size_t retval;
-	int i;
-
-	buf = kzalloc(size, GFP_KERNEL);
-	if (buf == NULL)
-		return -ENOMEM;
-
-	astats = &an->airtime_stats;
-
-	len += scnprintf(buf + len, size - len, "RX: %u us\n", astats->rx_airtime);
-	len += scnprintf(buf + len, size - len, "TX: %u us\n", astats->tx_airtime);
-	len += scnprintf(buf + len, size - len, "Deficit: ");
-	for (i = 0; i < 4; i++)
-		len += scnprintf(buf+len, size - len, "%s: %lld us ", qname[i], an->airtime_deficit[i]);
-	if (len < size)
-		buf[len++] = '\n';
-
-	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
-	kfree(buf);
-
-	return retval;
-}
-
-
-static const struct file_operations fops_airtime = {
-	.read = read_airtime,
-	.open = simple_open,
-	.owner = THIS_MODULE,
-	.llseek = default_llseek,
-};
-
-
 void ath9k_sta_add_debugfs(struct ieee80211_hw *hw,
 			   struct ieee80211_vif *vif,
 			   struct ieee80211_sta *sta,
@@ -304,5 +251,4 @@ void ath9k_sta_add_debugfs(struct ieee80211_hw *hw,
 
 	debugfs_create_file("node_aggr", S_IRUGO, dir, an, &fops_node_aggr);
 	debugfs_create_file("node_recv", S_IRUGO, dir, an, &fops_node_recv);
-	debugfs_create_file("airtime", S_IRUGO, dir, an, &fops_airtime);
 }
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index bb7936090b91..b4c6fc49b19e 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -620,8 +620,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
 
 	/* Will be cleared in ath9k_start() */
 	set_bit(ATH_OP_INVALID, &common->op_flags);
-	sc->airtime_flags = (AIRTIME_USE_TX | AIRTIME_USE_RX |
-			     AIRTIME_USE_NEW_QUEUES);
+	sc->airtime_flags = (AIRTIME_USE_TX | AIRTIME_USE_RX);
 
 	sc->sc_ah = ah;
 	sc->dfs_detector = dfs_pattern_detector_init(common, NL80211_DFS_UNSET);
@@ -873,6 +872,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
 	ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
 	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
 	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
+	ieee80211_hw_set(hw, AIRTIME_ACCOUNTING);
 
 	if (ath9k_ps_enable)
 		ieee80211_hw_set(hw, SUPPORTS_PS);
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 2197aee2bb72..e77e5c839abc 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -1054,14 +1054,9 @@ static void ath_rx_count_airtime(struct ath_softc *sc,
 						len, rxs->rate_idx, is_sp);
 	}
 
- 	if (!!(sc->airtime_flags & AIRTIME_USE_RX)) {
-		spin_lock_bh(&acq->lock);
-		an->airtime_deficit[acno] -= airtime;
-		if (an->airtime_deficit[acno] <= 0)
-			__ath_tx_queue_tid(sc, ATH_AN_2_TID(an, tidno));
-		spin_unlock_bh(&acq->lock);
-	}
-	ath_debug_airtime(sc, an, airtime, 0);
+ 	if (sc->airtime_flags & AIRTIME_USE_RX)
+		rxs->rx_time = min_t(u32, 0xffff, airtime);
+
 exit:
 	rcu_read_unlock();
 }
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 4256701500ff..86b1d21b237e 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -638,11 +638,9 @@ static bool bf_is_ampdu_not_probing(struct ath_buf *bf)
     return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
 }
 
-static void ath_tx_count_airtime(struct ath_softc *sc, struct ath_node *an,
-				 struct ath_atx_tid *tid, struct ath_buf *bf,
+static void ath_tx_count_airtime(struct ath_softc *sc, struct ath_buf *bf,
 				 struct ath_tx_status *ts)
 {
-	struct ath_txq *txq = tid->txq;
 	u32 airtime = 0;
 	int i;
 
@@ -652,15 +650,9 @@ static void ath_tx_count_airtime(struct ath_softc *sc, struct ath_node *an,
 		airtime += rate_dur * bf->rates[i].count;
 	}
 
-	if (sc->airtime_flags & AIRTIME_USE_TX) {
-		int q = txq->mac80211_qnum;
-		struct ath_acq *acq = &sc->cur_chan->acq[q];
+	if (sc->airtime_flags & AIRTIME_USE_TX)
+		bf->bf_state.airtime = airtime;
 
-		spin_lock_bh(&acq->lock);
-		an->airtime_deficit[q] -= airtime;
-		spin_unlock_bh(&acq->lock);
-	}
-	ath_debug_airtime(sc, an, 0, airtime);
 }
 
 static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
@@ -690,7 +682,7 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
 	if (sta) {
 		struct ath_node *an = (struct ath_node *)sta->drv_priv;
 		tid = ath_get_skb_tid(sc, an, bf->bf_mpdu);
-		ath_tx_count_airtime(sc, an, tid, bf, ts);
+		ath_tx_count_airtime(sc, bf, ts);
 		if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY))
 			tid->clear_ps_filter = true;
 	}
@@ -2425,6 +2417,8 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
 	if (ts->ts_status & ATH9K_TXERR_FILT)
 		tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
 
+	tx_info->status.tx_time = min_t(u32, 0xffff, bf->bf_state.airtime);
+
 	dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE);
 	bf->bf_buf_addr = 0;
 	if (sc->tx99_state)
@@ -2751,9 +2745,6 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
 	struct ath_atx_tid *tid;
 	int tidno, acno;
 
-	for (acno = 0; acno < IEEE80211_NUM_ACS; acno++)
-		an->airtime_deficit[acno] = ATH_AIRTIME_QUANTUM;
-
 	for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
 		tid = ath_node_to_tid(an, tidno);
 		tid->an        = an;
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index f0373dd3d714..2bedd361511b 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1202,6 +1202,7 @@ struct ieee80211_rx_status {
 	u32 device_timestamp;
 	u32 ampdu_reference;
 	u32 flag;
+	u16 rx_time;
 	u16 freq;
 	u8 enc_flags;
 	u8 encoding:2, bw:3;
@@ -2059,6 +2060,10 @@ struct ieee80211_txq {
  *	The stack will not do fragmentation.
  *	The callback for @set_frag_threshold should be set as well.
  *
+ * @IEEE80211_HW_AIRTIME_ACCOUNTING: Hardware supports accounting the airtime
+ *      usage of other stations and reports it in the @tx_time and/or @rx_time
+ *      fields of the TX/RX status structs.
+ *
  * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
  */
 enum ieee80211_hw_flags {
@@ -2101,6 +2106,7 @@ enum ieee80211_hw_flags {
 	IEEE80211_HW_TX_FRAG_LIST,
 	IEEE80211_HW_REPORTS_LOW_ACK,
 	IEEE80211_HW_SUPPORTS_TX_FRAG,
+	IEEE80211_HW_AIRTIME_ACCOUNTING,
 
 	/* keep last, obviously */
 	NUM_IEEE80211_HW_FLAGS
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 5fae001f286c..20e3aa0e8464 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -211,6 +211,7 @@ static const char *hw_flag_names[] = {
 	FLAG(TX_FRAG_LIST),
 	FLAG(REPORTS_LOW_ACK),
 	FLAG(SUPPORTS_TX_FRAG),
+	FLAG(AIRTIME_ACCOUNTING),
 #undef FLAG
 };
 
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index b15412c21ac9..57bc6b544f0e 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -188,6 +188,32 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf,
 }
 STA_OPS(aqm);
 
+static ssize_t sta_airtime_read(struct file *file, char __user *userbuf,
+				size_t count, loff_t *ppos)
+{
+	struct sta_info *sta = file->private_data;
+	size_t bufsz = 200;
+	char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf;
+	ssize_t rv;
+
+	if (!buf)
+		return -ENOMEM;
+
+	spin_lock_bh(&sta->lock);
+
+	p += scnprintf(p, bufsz+buf-p,
+		"RX: %llu us\nTX: %llu us\nDeficit: %lld us\n",
+		sta->airtime_stats.rx_airtime,
+		sta->airtime_stats.tx_airtime,
+		sta->airtime_deficit);
+
+	spin_unlock_bh(&sta->lock);
+	rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+	kfree(buf);
+	return rv;
+}
+STA_OPS(airtime);
+
 static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
 					size_t count, loff_t *ppos)
 {
@@ -542,6 +568,9 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
 	if (local->ops->wake_tx_queue)
 		DEBUGFS_ADD(aqm);
 
+	if (ieee80211_hw_check(&local->hw, AIRTIME_ACCOUNTING))
+		DEBUGFS_ADD(airtime);
+
 	if (sizeof(sta->driver_buffered_tids) == sizeof(u32))
 		debugfs_create_x32("driver_buffered_tids", 0400,
 				   sta->debugfs_dir,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 48bf933435a8..7f6fe5285813 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -90,6 +90,9 @@ extern const u8 ieee80211_ac_to_qos_mask[IEEE80211_NUM_ACS];
 
 #define IEEE80211_MAX_NAN_INSTANCE_ID 255
 
+/* How much to increase airtime deficit on each scheduling round */
+#define IEEE80211_AIRTIME_QUANTUM        1000 /* usec */
+
 struct ieee80211_fragment_entry {
 	struct sk_buff_head skb_list;
 	unsigned long first_frag_time;
@@ -1122,7 +1125,8 @@ struct ieee80211_local {
 	struct codel_vars *cvars;
 	struct codel_params cparams;
 
-	struct list_head active_txqs;
+	struct list_head active_txqs_new;
+	struct list_head active_txqs_old;
 	spinlock_t active_txq_lock;
 
 	const struct ieee80211_ops *ops;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 9ad0556aa24b..acf73c398d9b 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -616,7 +616,8 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
 	spin_lock_init(&local->rx_path_lock);
 	spin_lock_init(&local->queue_stop_reason_lock);
 
-	INIT_LIST_HEAD(&local->active_txqs);
+	INIT_LIST_HEAD(&local->active_txqs_new);
+	INIT_LIST_HEAD(&local->active_txqs_old);
 	spin_lock_init(&local->active_txq_lock);
 
 	INIT_LIST_HEAD(&local->chanctx_list);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 70e9d2ca8bbe..14cc1a5902a7 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1637,6 +1637,15 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
 	if (ieee80211_vif_is_mesh(&rx->sdata->vif))
 		ieee80211_mps_rx_h_sta_process(sta, hdr);
 
+	/* airtime accounting */
+	if (ieee80211_hw_check(&sta->local->hw, AIRTIME_ACCOUNTING) &&
+	    status->rx_time) {
+		spin_lock_bh(&sta->lock);
+		sta->airtime_stats.rx_airtime += status->rx_time;
+		sta->airtime_deficit -= status->rx_time;
+		spin_unlock_bh(&sta->lock);
+	}
+
 	/*
 	 * Drop (qos-)data::nullfunc frames silently, since they
 	 * are used only to control station power saving mode.
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 5db76db6bfc8..51fe010af20e 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -433,6 +433,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
 	sta->cparams.interval = MS2TIME(100);
 	sta->cparams.ecn = true;
 
+	sta->airtime_deficit = IEEE80211_AIRTIME_QUANTUM;
+
 	sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);
 
 	return sta;
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 5c54acd10562..5d1802f22550 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -550,6 +550,13 @@ struct sta_info {
 	} tx_stats;
 	u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
 
+	/* Airtime stats and deficit, protected by lock */
+	struct {
+		u64 rx_airtime;
+		u64 tx_airtime;
+	} airtime_stats;
+	s64 airtime_deficit;
+
 	/*
 	 * Aggregation information, locked with lock.
 	 */
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index da7427a41529..2f1111532be0 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -823,6 +823,13 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
 				ieee80211_lost_packet(sta, info);
 			}
 		}
+
+		if (info->status.tx_time) {
+			spin_lock_bh(&sta->lock);
+			sta->airtime_stats.tx_airtime += info->status.tx_time;
+			sta->airtime_deficit -= info->status.tx_time;
+			spin_unlock_bh(&sta->lock);
+		}
 	}
 
 	/* SNMP counters
@@ -947,6 +954,14 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
 			sta->status_stats.retry_failed++;
 		sta->status_stats.retry_count += retry_count;
 
+		if (ieee80211_hw_check(&local->hw, AIRTIME_ACCOUNTING) &&
+		    info->status.tx_time) {
+			spin_lock_bh(&sta->lock);
+			sta->airtime_stats.tx_airtime += info->status.tx_time;
+			sta->airtime_deficit -= info->status.tx_time;
+			spin_unlock_bh(&sta->lock);
+		}
+
 		if (acked) {
 			sta->status_stats.last_ack = jiffies;
 
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 0ee6ea71d1c4..937d48a1ba7a 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -3530,7 +3530,7 @@ bool ieee80211_schedule_txq(struct ieee80211_hw *hw,
 	spin_lock_bh(&local->active_txq_lock);
 
 	if (list_empty(&txqi->schedule_order)) {
-		list_add_tail(&txqi->schedule_order, &local->active_txqs);
+		list_add_tail(&txqi->schedule_order, &local->active_txqs_new);
 		ret = 1;
 	}
 
@@ -3544,13 +3544,33 @@ struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct txq_info *txqi = NULL;
+	struct list_head *head;
 
 	spin_lock_bh(&local->active_txq_lock);
 
-	if (list_empty(&local->active_txqs))
-		goto out;
+begin:
+	head = &local->active_txqs_new;
+	if (list_empty(head)) {
+		head = &local->active_txqs_old;
+		if (list_empty(head))
+			goto out;
+	}
+
+	txqi = list_first_entry(head, struct txq_info, schedule_order);
+
+	if (txqi->txq.sta) {
+		struct sta_info *sta = container_of(txqi->txq.sta, struct sta_info, sta);
+
+		spin_lock_bh(&sta->lock);
+		if (sta->airtime_deficit < 0) {
+			sta->airtime_deficit += IEEE80211_AIRTIME_QUANTUM;
+			list_move_tail(&txqi->schedule_order, &local->active_txqs_old);
+			spin_unlock_bh(&sta->lock);
+			goto begin;
+		}
+		spin_unlock_bh(&sta->lock);
+	}
 
-	txqi = list_first_entry(&local->active_txqs, struct txq_info, schedule_order);
 	list_del_init(&txqi->schedule_order);
 
 out:
-- 
2.14.2

^ permalink raw reply related

* [PATCH] netlink: fix netlink_ack() extack race
From: Johannes Berg @ 2017-10-16 15:09 UTC (permalink / raw)
  To: linux-wireless, netdev; +Cc: Johannes Berg

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

It seems that it's possible to toggle NETLINK_F_EXT_ACK
through setsockopt() while another thread/CPU is building
a message inside netlink_ack(), which could then trigger
the WARN_ON()s I added since if it goes from being turned
off to being turned on between allocating and filling the
message, the skb could end up being too small.

Avoid this whole situation by storing the value of this
flag in a separate variable and using that throughout the
function instead.

Fixes: 2d4bc93368f5 ("netlink: extended ACK reporting")
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/netlink/af_netlink.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 336d9c6dcad9..767c84e10e20 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -2307,6 +2307,7 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
 	size_t tlvlen = 0;
 	struct netlink_sock *nlk = nlk_sk(NETLINK_CB(in_skb).sk);
 	unsigned int flags = 0;
+	bool nlk_has_extack = nlk->flags & NETLINK_F_EXT_ACK;
 
 	/* Error messages get the original request appened, unless the user
 	 * requests to cap the error message, and get extra error data if
@@ -2317,7 +2318,7 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
 			payload += nlmsg_len(nlh);
 		else
 			flags |= NLM_F_CAPPED;
-		if (nlk->flags & NETLINK_F_EXT_ACK && extack) {
+		if (nlk_has_extack && extack) {
 			if (extack->_msg)
 				tlvlen += nla_total_size(strlen(extack->_msg) + 1);
 			if (extack->bad_attr)
@@ -2326,8 +2327,7 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
 	} else {
 		flags |= NLM_F_CAPPED;
 
-		if (nlk->flags & NETLINK_F_EXT_ACK &&
-		    extack && extack->cookie_len)
+		if (nlk_has_extack && extack && extack->cookie_len)
 			tlvlen += nla_total_size(extack->cookie_len);
 	}
 
@@ -2347,7 +2347,7 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
 	errmsg->error = err;
 	memcpy(&errmsg->msg, nlh, payload > sizeof(*errmsg) ? nlh->nlmsg_len : sizeof(*nlh));
 
-	if (nlk->flags & NETLINK_F_EXT_ACK && extack) {
+	if (nlk_has_extack && extack) {
 		if (err) {
 			if (extack->_msg)
 				WARN_ON(nla_put_string(skb, NLMSGERR_ATTR_MSG,
-- 
2.14.2

^ permalink raw reply related

* [PATCH] fq_impl: Properly enforce memory limit
From: Toke Høiland-Jørgensen @ 2017-10-16 15:05 UTC (permalink / raw)
  To: linux-wireless; +Cc: Toke Høiland-Jørgensen

The fq structure would fail to properly enforce the memory limit in the case
where the packet being enqueued was bigger than the packet being removed to
bring the memory usage down. So keep dropping packets until the memory usage is
back below the limit. Also, fix the statistics for memory limit violations.

Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
---
 include/net/fq_impl.h | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/include/net/fq_impl.h b/include/net/fq_impl.h
index 4e6131cd3f43..ac1a2317941e 100644
--- a/include/net/fq_impl.h
+++ b/include/net/fq_impl.h
@@ -146,6 +146,7 @@ static void fq_tin_enqueue(struct fq *fq,
 			   fq_flow_get_default_t get_default_func)
 {
 	struct fq_flow *flow;
+	bool oom;
 
 	lockdep_assert_held(&fq->lock);
 
@@ -167,8 +168,8 @@ static void fq_tin_enqueue(struct fq *fq,
 	}
 
 	__skb_queue_tail(&flow->queue, skb);
-
-	if (fq->backlog > fq->limit || fq->memory_usage > fq->memory_limit) {
+	oom = (fq->memory_usage > fq->memory_limit);
+	while (fq->backlog > fq->limit || oom) {
 		flow = list_first_entry_or_null(&fq->backlogs,
 						struct fq_flow,
 						backlogchain);
@@ -183,8 +184,10 @@ static void fq_tin_enqueue(struct fq *fq,
 
 		flow->tin->overlimit++;
 		fq->overlimit++;
-		if (fq->memory_usage > fq->memory_limit)
+		if (oom) {
 			fq->overmemory++;
+			oom = (fq->memory_usage > fq->memory_limit);
+		}
 	}
 }
 
-- 
2.14.2

^ permalink raw reply related

* [PATCH] netlink: use NETLINK_CB(in_skb).sk instead of looking it up
From: Johannes Berg @ 2017-10-16 14:57 UTC (permalink / raw)
  To: linux-wireless, netdev; +Cc: Eric W . Biederman, Johannes Berg

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

When netlink_ack() reports an allocation error to the sending
socket, there's no need to look up the sending socket since
it's available in the SKB's CB. Use that instead of going to
the trouble of looking it up.

Note that the pointer is only available since Eric Biederman's
commit 3fbc290540a1 ("netlink: Make the sending netlink socket availabe in NETLINK_CB")
which is far newer than the original lookup code (Oct 2003)
(though the field was called 'ssk' in that commit and only got
renamed to 'sk' later, I'd actually argue 'ssk' was better - or
perhaps it should've been 'source_sk' - since there are so many
different 'sk's involved.)

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/netlink/af_netlink.c | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index f34750691c5c..336d9c6dcad9 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -2336,16 +2336,8 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
 
 	skb = nlmsg_new(payload + tlvlen, GFP_KERNEL);
 	if (!skb) {
-		struct sock *sk;
-
-		sk = netlink_lookup(sock_net(in_skb->sk),
-				    in_skb->sk->sk_protocol,
-				    NETLINK_CB(in_skb).portid);
-		if (sk) {
-			sk->sk_err = ENOBUFS;
-			sk->sk_error_report(sk);
-			sock_put(sk);
-		}
+		NETLINK_CB(in_skb).sk->sk_err = ENOBUFS;
+		NETLINK_CB(in_skb).sk->sk_error_report(NETLINK_CB(in_skb).sk);
 		return;
 	}
 
-- 
2.14.2

^ permalink raw reply related

* pull-request: mac80211 2017-10-16
From: Johannes Berg @ 2017-10-16 13:46 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-wireless

Hi Dave,

Here's a fix, for a small part of the "KRACK" announced today
(krackattacks.com).

Please pull and let me know if there's any problem.

Thanks,
johannes



The following changes since commit c0576e3975084d4699b7bfef578613fb8e1144f6:

  net: call cgroup_sk_alloc() earlier in sk_clone_lock() (2017-10-10 20:24:29 -0700)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git tags/mac80211-for-davem-2017-10-16

for you to fetch changes up to fdf7cb4185b60c68e1a75e61691c4afdc15dea0e:

  mac80211: accept key reinstall without changing anything (2017-10-16 13:02:03 +0200)

----------------------------------------------------------------
Just a single fix, for a WoWLAN-related part of CVE-2017-13080.

----------------------------------------------------------------
Johannes Berg (1):
      mac80211: accept key reinstall without changing anything

 net/mac80211/key.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

^ permalink raw reply

* Re: Two rtlwifi drivers?
From: Kalle Valo @ 2017-10-16 13:22 UTC (permalink / raw)
  To: Pkshih
  Cc: Larry Finger, Greg Kroah-Hartman, Dan Carpenter,
	莊彥宣, Johannes Berg, Souptick Joarder,
	devel@driverdev.osuosl.org, linux-wireless@vger.kernel.org,
	kernel-janitors@vger.kernel.org
In-Reply-To: <5B2DA6FDDF928F4E855344EE0A5C39D10581FF70@RTITMBSV07.realtek.com.tw>

Hi PK,

you got good answers already so only short reply from me:

Pkshih <pkshih@realtek.com> writes:

> 3) Coming drivers -- rtl8723de and rtl8821ce
>    We're developing the two drivers, and rtl8723de and rtl8821ce will
>    be ready on 2017Q4 and 2018Q1 respectively. The drivers are based on
>    rtl8822be that in staging now, so the line of code will be fewer.
>    The new files will be a new IC folder and IC supported files of 
>    three modules that btcoexist, phydm and halmac. Could I submit
>    them to wirless tree when they're ready?

My recommendation is to avoid accumulating patches at all cost and start
submitting them as soon as you can. This way you get patches committed
much more smoother. So do not wait until _all_ patches are ready,
instead start submitting patches as soon as you have _some_ patches
ready. In other words, keep the delta between mainline and your
not-yet-submitted patches as small as possible.

And the patches don't need to be bug free as you can always fix bugs
later. Just mention in the commit logs that this is preparation for some
new feature and not fully tested yet. We do that all the time, for
example Intel's iwlwifi has support for hardware which have not reached
customers yet.

> On the way, I'll attend netdev workshop in Korea, so we can meet there
> if you attend too.

I'm also attending Netdev 2.2, looking forward to meeting you there.

-- 
Kalle Valo

^ permalink raw reply

* Re: Two rtlwifi drivers?
From: Oleksij Rempel @ 2017-10-16 13:11 UTC (permalink / raw)
  To: Kalle Valo
  Cc: Pkshih, Larry Finger, Greg Kroah-Hartman, Dan Carpenter,
	莊彥宣, Johannes Berg, Souptick Joarder,
	devel@driverdev.osuosl.org, linux-wireless@vger.kernel.org,
	kernel-janitors@vger.kernel.org
In-Reply-To: <87fuajmeak.fsf@kamboji.qca.qualcomm.com>


[-- Attachment #1.1: Type: text/plain, Size: 1433 bytes --]

Am 16.10.2017 um 15:07 schrieb Kalle Valo:
> Oleksij Rempel <linux@rempel-privat.de> writes:
> 
>>> 4) As Kalle mentioned, rtlwifi contains many magic numbers, and I 
>>>    plan to fix them after rtl8723de and rtl8821ce. Because the drivers
>>>    are developing, the changes will make us hard to integrate. However,
>>>    I don't have plan to process the magic numbers in the module phydm,
>>>    because the most of BB/RF registers contain many functions. And
>>>    it doesn't have a register name but a bit field name instead.
>>>    Our BB team guys say the use of enumeration or defined name will
>>>    be unreadable, and the name is meaningless for most people.
>>
>> Experience with ath9k driver showed, that development was kind of
>> balanced between two groups, QCA and Community (Other companies,
>> researches, education and so on.). Saying: "you will not understand it
>> any way" is nor really helpful :)
>> Please don't repeat bad experience of Broadcom.
> 
> I agree with Oleksij here, but I want to still point out that there are
> cases when using magic numbers are ok, for example look at
> ar5008_initvals.h from ath9k. So it depends on case by case.

Beside. It is probably offtopic. I assume this initvals related to BB.
Is it possible to force a 802.11n controller to work in 802.11b mode? I
can image, it should be possible by reconfiguring BB. Correct?
-- 
Regards,
Oleksij


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply

* Re: Two rtlwifi drivers?
From: Kalle Valo @ 2017-10-16 13:07 UTC (permalink / raw)
  To: Oleksij Rempel
  Cc: Pkshih, Larry Finger, Greg Kroah-Hartman, Dan Carpenter,
	莊彥宣, Johannes Berg, Souptick Joarder,
	devel@driverdev.osuosl.org, linux-wireless@vger.kernel.org,
	kernel-janitors@vger.kernel.org
In-Reply-To: <ed361ae7-864e-1179-c7da-3ff10f4c73e2@rempel-privat.de>

Oleksij Rempel <linux@rempel-privat.de> writes:

>> 4) As Kalle mentioned, rtlwifi contains many magic numbers, and I 
>>    plan to fix them after rtl8723de and rtl8821ce. Because the drivers
>>    are developing, the changes will make us hard to integrate. However,
>>    I don't have plan to process the magic numbers in the module phydm,
>>    because the most of BB/RF registers contain many functions. And
>>    it doesn't have a register name but a bit field name instead.
>>    Our BB team guys say the use of enumeration or defined name will
>>    be unreadable, and the name is meaningless for most people.
>
> Experience with ath9k driver showed, that development was kind of
> balanced between two groups, QCA and Community (Other companies,
> researches, education and so on.). Saying: "you will not understand it
> any way" is nor really helpful :)
> Please don't repeat bad experience of Broadcom.

I agree with Oleksij here, but I want to still point out that there are
cases when using magic numbers are ok, for example look at
ar5008_initvals.h from ath9k. So it depends on case by case.

-- 
Kalle Valo

^ permalink raw reply

* Re: Two rtlwifi drivers?
From: Kalle Valo @ 2017-10-16 13:03 UTC (permalink / raw)
  To: Dan Carpenter
  Cc: Pkshih, Larry Finger, Greg Kroah-Hartman,
	莊彥宣, Johannes Berg, Souptick Joarder,
	devel@driverdev.osuosl.org, linux-wireless@vger.kernel.org,
	kernel-janitors@vger.kernel.org
In-Reply-To: <20171016074516.4irgvbid6p5zwqjg@mwanda>

Dan Carpenter <dan.carpenter@oracle.com> writes:

> On Mon, Oct 16, 2017 at 02:41:38AM +0000, Pkshih wrote:
>> 2) The rtlwifi in staging
>>    In staging, the module phydm v13 contains bugs, so I want to upgrade
>>    to v21 (Realtek internal version number). This upgrade contains a
>>    big patch that the difference between v13 and v21, and there are 
>>    40+ patches to support this upgrade. I have three options, and
>>    I want to know which one is prefer.
>
> We can't discuss patches we haven't seend.  Please just send them right
> away without any delay to both lists, and we can decide from there.
>
> 40 patches is a medium size set, patch that we are used to dealing with
> every day.

I review every patch I commit and 40 patches is just pure pain to dig
through. So when submitting patches to me please keep the size more
reasonable, like 10-12 patches per set. I think Dave also has a similar
rule for net patches.

I wrote a FAQ entry about this:

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches#too_many_patches

-- 
Kalle Valo

^ permalink raw reply

* Re: [PATCH v3 1/2] dt-bindings: add device tree binding for Allwinner XR819 SDIO Wi-Fi
From: Kalle Valo @ 2017-10-16 12:58 UTC (permalink / raw)
  To: icenowy
  Cc: devicetree, Arend van Spriel, netdev, linux-wireless,
	linux-kernel, linux-sunxi, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, linux-arm-kernel
In-Reply-To: <dba5f095f9f25f0726ee3a2852e01b88@aosc.io>

icenowy@aosc.io writes:

>>>>> > > Like I asked already last time, AFAICS there is no upstream xr819
>>>>> > > wireless driver in drivers/net/wireless directory. Do we still
>>>> accept
>>>>> > > bindings like this for out-of-tree drivers?
>>>>> >
>>>>> > See esp8089.
>>>>> >
>>>>> > There's also no in-tree driver for it.
>>>>>
>>>>> The question is whether we should. The above might be a precedent,
>>>> but it
>>>>> may not necessarily be the way to go. The commit message for esp8089
>>>> seems
>>>>> to hint that there is intent to have an in-tree driver:
>>>>>
>>>>> """
>>>>>     Note that at this point there only is an out of tree driver for
>>>> this
>>>>>     hardware, there is no clear timeline / path for merging this.
>>>> Still
>>>>>     I believe it would be good to specify the binding for this in
>>>> tree
>>>>>     now, so that any future migration to an in tree driver will not
>>>> cause
>>>>>     compatiblity issues.
>>>>>
>>>>>     Cc: Icenowy Zheng <icenowy@aosc.xyz>
>>>>>     Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>>>>>     Signed-off-by: Rob Herring <robh@kernel.org>
>>>>> """
>>>>>
>>>>> Regardless the bindings are in principle independent of the kernel
>>>> and just
>>>>> describing hardware. I think there have been discussions to move the
>>>>> bindings to their own repository, but apparently it was decided
>>>> otherwise.
>>>>
>>>> Yeah, I guess especially how it could be merged with the cw1200
>>>> driver
>>>> would be very relevant to that commit log.
>>>
>>> The cw1200 driver seems to still have some legacy platform
>>> data. Maybe they should also be convert to DT.
>>> (Or maybe compatible = "allwinner,xr819" is enough, as
>>> xr819 is a specified variant of cw1200 family)
>>
>> Ah, so the upstream cw1200 driver supports xr819? Has anyone tested
>> that? Or does cw1200 more changes than just adding the DT support?
>
> The support of XR819 in CW1200 driver is far more difficult than I
> imagined -- the codedrop used in the mainlined CW1200 driver seems to
> be so old that it's before XR819 (which seems to be based on CW1160),
> and there's a large number of problems to adapt it to a modern CW1200
> variant.
>
> P.S. could you apply this device tree binding patch now?

As I haven't seen any consensus that applying bindings document for
out-of-tree drivers is ok so at least I'm not taking this. Though not
sure what DT maintainers are planning to do.

-- 
Kalle Valo

^ permalink raw reply

* [PATCH] bcma: use bcma_debug and pr_cont in MIPS driver
From: Rafał Miłecki @ 2017-10-16 12:54 UTC (permalink / raw)
  To: Kalle Valo, linux-wireless; +Cc: Hauke Mehrtens, Rafał Miłecki

From: Rafał Miłecki <rafal@milecki.pl>

Using bcma_debug gives a device-specific prefix for messages and pr_cont
is a common helper for continuing a line.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
 drivers/bcma/driver_mips.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c
index 89af807cf29c..5904ef1aa624 100644
--- a/drivers/bcma/driver_mips.c
+++ b/drivers/bcma/driver_mips.c
@@ -184,10 +184,11 @@ static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
 {
 	int i;
 	static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
-	printk(KERN_DEBUG KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
+
+	bcma_debug(dev->bus, "core 0x%04x, irq :", dev->id.id);
 	for (i = 0; i <= 6; i++)
-		printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
-	printk("\n");
+		pr_cont(" %s%s", irq_name[i], i == irq ? "*" : " ");
+	pr_cont("\n");
 }
 
 static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
-- 
2.11.0

^ permalink raw reply related

* Re: rc2-next-20170929: wireless down, won't come up
From: Stanislaw Gruszka @ 2017-10-16 12:34 UTC (permalink / raw)
  To: Pavel Machek; +Cc: linux-wireless, kernel list
In-Reply-To: <20171016122456.GA7351@amd>

On Mon, Oct 16, 2017 at 02:24:56PM +0200, Pavel Machek wrote:
> So far it happened once... so I don't know about reproducibility. And
> I'm not even sure if I'm using iwlegacy driver. Am I?

iwl3945 (and iwl4965) are iwlegacy drivers.

Regards
Stanislaw

^ permalink raw reply

* Re: rc2-next-20170929: wireless down, won't come up
From: Pavel Machek @ 2017-10-16 12:24 UTC (permalink / raw)
  To: Stanislaw Gruszka; +Cc: linux-wireless, kernel list
In-Reply-To: <20171016105154.GB3752@redhat.com>

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

On Mon 2017-10-16 12:51:55, Stanislaw Gruszka wrote:
> Hi
> 
> Site note: Intel folks do not support iwlegacy, I removed them from CC.
> 
> On Mon, Oct 16, 2017 at 12:27:45PM +0200, Pavel Machek wrote:
> > > In -next... after few days of usage with suspend and resume cycles,
> > > wifi failed on thinkpad x60. I have not seen this in years...
> <snip>
> > > Any ideas?
> 
> We do not have any recent iwlegacy changes except cosmetic
> ones, so this problem most likely is mac80211, pci or other
> subsystem issue
> 
> > Suspend+resume fixed the problem.
> 
> It is not reproducible? If so, I think it will not be 
> easy to identify the issue.

So far it happened once... so I don't know about reproducibility. And
I'm not even sure if I'm using iwlegacy driver. Am I?

									Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply

* Re: usb/net/rt2x00: warning in rt2800_eeprom_word_index
From: Dmitry Vyukov @ 2017-10-16 12:19 UTC (permalink / raw)
  To: Stanislaw Gruszka
  Cc: Andrey Konovalov, Helmut Schaa, Kalle Valo, linux-wireless,
	netdev, LKML, Kostya Serebryany, syzkaller
In-Reply-To: <20171016094024.GD2553@redhat.com>

On Mon, Oct 16, 2017 at 11:40 AM, Stanislaw Gruszka <sgruszka@redhat.com> wrote:
> Hi Dmitry
>
> On Sat, Oct 14, 2017 at 04:38:03PM +0200, Dmitry Vyukov wrote:
>> On Thu, Oct 12, 2017 at 9:25 AM, Stanislaw Gruszka <sgruszka@redhat.com> wrote:
>> > Hi
>> >
>> > On Mon, Oct 09, 2017 at 07:50:53PM +0200, Andrey Konovalov wrote:
>> >> I've got the following report while fuzzing the kernel with syzkaller.
>> >>
>> >> On commit 8a5776a5f49812d29fe4b2d0a2d71675c3facf3f (4.14-rc4).
>> >>
>> >> I'm not sure whether this is a bug in the driver, or just a way to
>> >> report misbehaving device. In the latter case this shouldn't be a
>> >> WARN() call, since WARN() means bug in the kernel.
>> >
>> > This is about wrong EEPROM, which reported 3 tx streams on
>> > non 3 antenna device. I think WARN() is justified and thanks
>> > to the call trace I was actually able to to understand what
>> > happened.
>> >
>> > In general I do not think WARN() only means a kernel bug, it
>> > can be F/W or H/W bug too.
>>
>> Hi Stanislaw,
>>
>> Printing messages is fine. Printing stacks is fine. Just please make
>> them distinguishable from kernel bugs and don't kill the whole
>> possibility of automated Linux kernel testing. That's an important
>> capability.
>
> We do not distinguish between bugs and other problems when WARN() is
> used in (wireless) drivers, what I think is correct, taking comment from
> include/asm-generic/bug.h :
>
> /*
>  * WARN(), WARN_ON(), WARN_ON_ONCE, and so on can be used to report
>  * significant issues that need prompt attention if they should ever
>  * appear at runtime.  Use the versions with printk format strings
>  * to provide better diagnostics.
>  */
>
> Historically we have BUG() to mark the bugs, but usage if it is not
> recommended as it can kill the system, so for anything that can
> be recovered in runtime - WARN() is recommended.
>
> Perhaps we can introduce another helper like PROBLEM() for marking
> situations when something is wrong, but it is not a bug. However I'm
> not even sure at what extent it can be used, since for many cases
> if not the most, driver author can not tell apriori if the problem
> is a bug in the driver or HW/FW misbehaviour (or maybe particular
> issue can happen because of both).

I will write a separate email to LKML.

Thanks

^ permalink raw reply

* Re: usb/net/rt2x00: warning in rt2800_eeprom_word_index
From: Dmitry Vyukov @ 2017-10-16 12:16 UTC (permalink / raw)
  To: Kalle Valo
  Cc: Stanislaw Gruszka, Andrey Konovalov, Helmut Schaa, linux-wireless,
	netdev, LKML, Kostya Serebryany, syzkaller
In-Reply-To: <8760bfo09s.fsf@kamboji.qca.qualcomm.com>

On Mon, Oct 16, 2017 at 12:27 PM, Kalle Valo <kvalo@codeaurora.org> wrote:
> Dmitry Vyukov <dvyukov@google.com> writes:
>
>> On Thu, Oct 12, 2017 at 9:25 AM, Stanislaw Gruszka <sgruszka@redhat.com> wrote:
>>> Hi
>>>
>>> On Mon, Oct 09, 2017 at 07:50:53PM +0200, Andrey Konovalov wrote:
>>>> I've got the following report while fuzzing the kernel with syzkaller.
>>>>
>>>> On commit 8a5776a5f49812d29fe4b2d0a2d71675c3facf3f (4.14-rc4).
>>>>
>>>> I'm not sure whether this is a bug in the driver, or just a way to
>>>> report misbehaving device. In the latter case this shouldn't be a
>>>> WARN() call, since WARN() means bug in the kernel.
>>>
>>> This is about wrong EEPROM, which reported 3 tx streams on
>>> non 3 antenna device. I think WARN() is justified and thanks
>>> to the call trace I was actually able to to understand what
>>> happened.
>>>
>>> In general I do not think WARN() only means a kernel bug, it
>>> can be F/W or H/W bug too.
>>
>> Hi Stanislaw,
>>
>> Printing messages is fine. Printing stacks is fine. Just please make
>> them distinguishable from kernel bugs and don't kill the whole
>> possibility of automated Linux kernel testing. That's an important
>> capability.
>
> Not really following you. Are you saying that using WARN() prevents
> automated Linux kernel testing?


Absence of a way to understand when there is something wrong with
kernel (something to notify kernel developers about) is the problem.

^ permalink raw reply

* Re: rc2-next-20170929: wireless down, won't come up
From: Stanislaw Gruszka @ 2017-10-16 10:51 UTC (permalink / raw)
  To: Pavel Machek; +Cc: linux-wireless, kernel list
In-Reply-To: <20171016102745.GA22525@amd>

Hi

Site note: Intel folks do not support iwlegacy, I removed them from CC.

On Mon, Oct 16, 2017 at 12:27:45PM +0200, Pavel Machek wrote:
> > In -next... after few days of usage with suspend and resume cycles,
> > wifi failed on thinkpad x60. I have not seen this in years...
<snip>
> > Any ideas?

We do not have any recent iwlegacy changes except cosmetic
ones, so this problem most likely is mac80211, pci or other
subsystem issue

> Suspend+resume fixed the problem.

It is not reproducible? If so, I think it will not be 
easy to identify the issue.

Thanks
Stanislaw

^ permalink raw reply

* Re: usb/net/rt2x00: warning in rt2800_eeprom_word_index
From: Kalle Valo @ 2017-10-16 10:27 UTC (permalink / raw)
  To: Dmitry Vyukov
  Cc: Stanislaw Gruszka, Andrey Konovalov, Helmut Schaa, linux-wireless,
	netdev, LKML, Kostya Serebryany, syzkaller
In-Reply-To: <CACT4Y+YLM-u7bMfRB=eu_pz1M9iDrY-Qmnho7Hw_Lh3M=LSeMQ@mail.gmail.com>

Dmitry Vyukov <dvyukov@google.com> writes:

> On Thu, Oct 12, 2017 at 9:25 AM, Stanislaw Gruszka <sgruszka@redhat.com> wrote:
>> Hi
>>
>> On Mon, Oct 09, 2017 at 07:50:53PM +0200, Andrey Konovalov wrote:
>>> I've got the following report while fuzzing the kernel with syzkaller.
>>>
>>> On commit 8a5776a5f49812d29fe4b2d0a2d71675c3facf3f (4.14-rc4).
>>>
>>> I'm not sure whether this is a bug in the driver, or just a way to
>>> report misbehaving device. In the latter case this shouldn't be a
>>> WARN() call, since WARN() means bug in the kernel.
>>
>> This is about wrong EEPROM, which reported 3 tx streams on
>> non 3 antenna device. I think WARN() is justified and thanks
>> to the call trace I was actually able to to understand what
>> happened.
>>
>> In general I do not think WARN() only means a kernel bug, it
>> can be F/W or H/W bug too.
>
> Hi Stanislaw,
>
> Printing messages is fine. Printing stacks is fine. Just please make
> them distinguishable from kernel bugs and don't kill the whole
> possibility of automated Linux kernel testing. That's an important
> capability.

Not really following you. Are you saying that using WARN() prevents
automated Linux kernel testing?

-- 
Kalle Valo

^ permalink raw reply

* Re: rc2-next-20170929: wireless down, won't come up
From: Pavel Machek @ 2017-10-16 10:27 UTC (permalink / raw)
  To: sgruszka, linux-wireless, kernel list, johannes.berg,
	emmanuel.grumbach, luciano.coelho, linuxwifi
In-Reply-To: <20171016091830.GA21812@amd>

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

Hi!

> In -next... after few days of usage with suspend and resume cycles,
> wifi failed on thinkpad x60. I have not seen this in years...
> 
> [28140.944044] CE: hpet increased min_delta_ns to 20115 nsec
> [28174.048418] iwl3945 0000:03:00.0: Error sending C_RATE_SCALE: time
> out after 500ms.
> [28174.048430] iwl3945 0000:03:00.0: Error setting HW rate table:
> FFFFFF92
> [28174.186576] iwl3945 0000:03:00.0: Error: Response NULL in
> 'C_ADD_STA'
> [28174.186593] iwl3945 0000:03:00.0: Adding station 00:00:00:00:00:01
> failed.
> [28174.206312] iwl3945 0000:03:00.0: Error: Response NULL in
> 'C_ADD_STA'
> [28174.206326] iwl3945 0000:03:00.0: Adding station ff:ff:ff:ff:ff:ff
> failed.
> [30306.599241] wlan0: deauthenticating from 00:00:00:00:00:01 by local
> choice (Reason: 3=DEAUTH_LEAVING)
> [30306.624302] iwl3945 0000:03:00.0: Error removing station
> 00:00:00:00:00:01
> [30309.055257] wlan0: authenticate with 00:00:00:00:00:01
> [30309.055631] wlan0: send auth to 00:00:00:00:00:01 (try 1/3)
> [30309.256142] wlan0: send auth to 00:00:00:00:00:01 (try 2/3)
> [30309.460114] wlan0: send auth to 00:00:00:00:00:01 (try 3/3)
> [30309.664117] wlan0: authentication with 00:00:00:00:00:01 timed out
> 
> (Yes, my AP has funny hw address; but its other hw address fails, too).
> 
> Any ideas?

Suspend+resume fixed the problem.
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply


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