Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH v2 04/16] mac80211: split PS buffers into ACs
From: Johannes Berg @ 2011-09-29 14:04 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless
In-Reply-To: <20110929140425.390322480@sipsolutions.net>

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

For uAPSD support we'll need to have per-AC PS
buffers. As this is a major undertaking, split
the buffers before really adding support for
uAPSD. This already makes some reference to the
uapsd_queues variable, but for now that will
never be non-zero.

Since book-keeping is complicated, also change
the logic for keeping a maximum of frames only
and allow 64 frames per AC (up from 128 for a
station).

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 include/net/mac80211.h     |    1 
 net/mac80211/debugfs_sta.c |   10 +-
 net/mac80211/sta_info.c    |  204 +++++++++++++++++++++++++++++++++------------
 net/mac80211/sta_info.h    |   24 ++---
 net/mac80211/status.c      |   17 +++
 net/mac80211/tx.c          |   42 +++++----
 6 files changed, 214 insertions(+), 84 deletions(-)

--- a/net/mac80211/sta_info.c	2011-09-29 16:01:18.000000000 +0200
+++ b/net/mac80211/sta_info.c	2011-09-29 16:03:09.000000000 +0200
@@ -309,8 +309,10 @@ struct sta_info *sta_info_alloc(struct i
 		 */
 		sta->timer_to_tid[i] = i;
 	}
-	skb_queue_head_init(&sta->ps_tx_buf);
-	skb_queue_head_init(&sta->tx_filtered);
+	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]);
+	}
 
 	for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
 		sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX);
@@ -641,12 +643,32 @@ static inline void __bss_tim_clear(struc
 	bss->tim[aid / 8] &= ~(1 << (aid % 8));
 }
 
+static unsigned long ieee80211_tids_for_ac(int ac)
+{
+	/* If we ever support TIDs > 7, this obviously needs to be adjusted */
+	switch (ac) {
+	case IEEE80211_AC_VO:
+		return BIT(6) | BIT(7);
+	case IEEE80211_AC_VI:
+		return BIT(4) | BIT(5);
+	case IEEE80211_AC_BE:
+		return BIT(0) | BIT(3);
+	case IEEE80211_AC_BK:
+		return BIT(1) | BIT(2);
+	default:
+		WARN_ON(1);
+		return 0;
+	}
+}
+
 void sta_info_recalc_tim(struct sta_info *sta)
 {
 	struct ieee80211_local *local = sta->local;
 	struct ieee80211_if_ap *bss = sta->sdata->bss;
 	unsigned long flags;
-	bool have_data = false;
+	bool indicate_tim = false;
+	u8 ignore_for_tim = sta->sta.uapsd_queues;
+	int ac;
 
 	if (WARN_ON_ONCE(!sta->sdata->bss))
 		return;
@@ -658,21 +680,43 @@ void sta_info_recalc_tim(struct sta_info
 	if (sta->dead)
 		goto done;
 
-	have_data = test_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF) ||
-		    !skb_queue_empty(&sta->tx_filtered) ||
-		    !skb_queue_empty(&sta->ps_tx_buf);
+	/*
+	 * If all ACs are delivery-enabled then we should build
+	 * the TIM bit for all ACs anyway; if only some are then
+	 * we ignore those and build the TIM bit using only the
+	 * non-enabled ones.
+	 */
+	if (ignore_for_tim == BIT(IEEE80211_NUM_ACS) - 1)
+		ignore_for_tim = 0;
+
+	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+		unsigned long tids;
+
+		if (ignore_for_tim & BIT(ac))
+			continue;
+
+		indicate_tim |= !skb_queue_empty(&sta->tx_filtered[ac]) ||
+				!skb_queue_empty(&sta->ps_tx_buf[ac]);
+		if (indicate_tim)
+			break;
+
+		tids = ieee80211_tids_for_ac(ac);
+
+		indicate_tim |=
+			sta->driver_buffered_tids & tids;
+	}
 
  done:
 	spin_lock_irqsave(&local->sta_lock, flags);
 
-	if (have_data)
+	if (indicate_tim)
 		__bss_tim_set(bss, sta->sta.aid);
 	else
 		__bss_tim_clear(bss, sta->sta.aid);
 
 	if (local->ops->set_tim) {
 		local->tim_in_locked_section = true;
-		drv_set_tim(local, &sta->sta, have_data);
+		drv_set_tim(local, &sta->sta, indicate_tim);
 		local->tim_in_locked_section = false;
 	}
 
@@ -699,16 +743,12 @@ static bool sta_info_buffer_expired(stru
 }
 
 
-static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
-					     struct sta_info *sta)
+static bool sta_info_cleanup_expire_buffered_ac(struct ieee80211_local *local,
+						struct sta_info *sta, int ac)
 {
 	unsigned long flags;
 	struct sk_buff *skb;
 
-	/* This is only necessary for stations on BSS interfaces */
-	if (!sta->sdata->bss)
-		return false;
-
 	/*
 	 * First check for frames that should expire on the filtered
 	 * queue. Frames here were rejected by the driver and are on
@@ -717,13 +757,13 @@ static bool sta_info_cleanup_expire_buff
 	 * total_ps_buffered counter.
 	 */
 	for (;;) {
-		spin_lock_irqsave(&sta->tx_filtered.lock, flags);
-		skb = skb_peek(&sta->tx_filtered);
+		spin_lock_irqsave(&sta->tx_filtered[ac].lock, flags);
+		skb = skb_peek(&sta->tx_filtered[ac]);
 		if (sta_info_buffer_expired(sta, skb))
-			skb = __skb_dequeue(&sta->tx_filtered);
+			skb = __skb_dequeue(&sta->tx_filtered[ac]);
 		else
 			skb = NULL;
-		spin_unlock_irqrestore(&sta->tx_filtered.lock, flags);
+		spin_unlock_irqrestore(&sta->tx_filtered[ac].lock, flags);
 
 		/*
 		 * Frames are queued in order, so if this one
@@ -743,13 +783,13 @@ static bool sta_info_cleanup_expire_buff
 	 * buffered frames.
 	 */
 	for (;;) {
-		spin_lock_irqsave(&sta->ps_tx_buf.lock, flags);
-		skb = skb_peek(&sta->ps_tx_buf);
+		spin_lock_irqsave(&sta->ps_tx_buf[ac].lock, flags);
+		skb = skb_peek(&sta->ps_tx_buf[ac]);
 		if (sta_info_buffer_expired(sta, skb))
-			skb = __skb_dequeue(&sta->ps_tx_buf);
+			skb = __skb_dequeue(&sta->ps_tx_buf[ac]);
 		else
 			skb = NULL;
-		spin_unlock_irqrestore(&sta->ps_tx_buf.lock, flags);
+		spin_unlock_irqrestore(&sta->ps_tx_buf[ac].lock, flags);
 
 		/*
 		 * frames are queued in order, so if this one
@@ -779,8 +819,25 @@ static bool sta_info_cleanup_expire_buff
 	 * used to check whether the cleanup timer still needs to run,
 	 * if there are no frames we don't need to rearm the timer.
 	 */
-	return !(skb_queue_empty(&sta->ps_tx_buf) &&
-		 skb_queue_empty(&sta->tx_filtered));
+	return !(skb_queue_empty(&sta->ps_tx_buf[ac]) &&
+		 skb_queue_empty(&sta->tx_filtered[ac]));
+}
+
+static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
+					     struct sta_info *sta)
+{
+	bool have_buffered = false;
+	int ac;
+
+	/* This is only necessary for stations on BSS interfaces */
+	if (!sta->sdata->bss)
+		return false;
+
+	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+		have_buffered |=
+			sta_info_cleanup_expire_buffered_ac(local, sta, ac);
+
+	return have_buffered;
 }
 
 static int __must_check __sta_info_destroy(struct sta_info *sta)
@@ -788,7 +845,7 @@ static int __must_check __sta_info_destr
 	struct ieee80211_local *local;
 	struct ieee80211_sub_if_data *sdata;
 	unsigned long flags;
-	int ret, i;
+	int ret, i, ac;
 
 	might_sleep();
 
@@ -856,9 +913,11 @@ static int __must_check __sta_info_destr
 	 */
 	synchronize_rcu();
 
-	local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf);
-	__skb_queue_purge(&sta->ps_tx_buf);
-	__skb_queue_purge(&sta->tx_filtered);
+	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+		local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]);
+		__skb_queue_purge(&sta->ps_tx_buf[ac]);
+		__skb_queue_purge(&sta->tx_filtered[ac]);
+	}
 
 #ifdef CONFIG_MAC80211_MESH
 	if (ieee80211_vif_is_mesh(&sdata->vif))
@@ -1055,17 +1114,33 @@ void ieee80211_sta_ps_deliver_wakeup(str
 {
 	struct ieee80211_sub_if_data *sdata = sta->sdata;
 	struct ieee80211_local *local = sdata->local;
-	int sent, buffered;
+	struct sk_buff_head pending;
+	int filtered = 0, buffered = 0, ac;
+
+	BUILD_BUG_ON(BITS_TO_LONGS(STA_TID_NUM) > 1);
+	sta->driver_buffered_tids = 0;
 
-	clear_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
 	if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
 		drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
 
+	skb_queue_head_init(&pending);
+
 	/* Send all buffered frames to the station */
-	sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered);
-	buffered = ieee80211_add_pending_skbs_fn(local, &sta->ps_tx_buf,
-						 clear_sta_ps_flags, sta);
-	sent += buffered;
+	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+		int count = skb_queue_len(&pending), tmp;
+
+		skb_queue_splice_tail_init(&sta->tx_filtered[ac], &pending);
+		tmp = skb_queue_len(&pending);
+		filtered += tmp - count;
+		count = tmp;
+
+		skb_queue_splice_tail_init(&sta->ps_tx_buf[ac], &pending);
+		tmp = skb_queue_len(&pending);
+		buffered += tmp - count;
+	}
+
+	ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta);
+
 	local->total_ps_buffered -= buffered;
 
 	sta_info_recalc_tim(sta);
@@ -1073,7 +1148,7 @@ void ieee80211_sta_ps_deliver_wakeup(str
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 	printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames "
 	       "since STA not sleeping anymore\n", sdata->name,
-	       sta->sta.addr, sta->sta.aid, sent - buffered, buffered);
+	       sta->sta.addr, sta->sta.aid, filtered, buffered);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 }
 
@@ -1081,17 +1156,43 @@ void ieee80211_sta_ps_deliver_poll_respo
 {
 	struct ieee80211_sub_if_data *sdata = sta->sdata;
 	struct ieee80211_local *local = sdata->local;
-	struct sk_buff *skb;
-	int no_pending_pkts;
+	struct sk_buff *skb = NULL;
+	bool more_data = false;
+	int ac;
+	u8 ignore_for_response = sta->sta.uapsd_queues;
 
-	skb = skb_dequeue(&sta->tx_filtered);
-	if (!skb) {
-		skb = skb_dequeue(&sta->ps_tx_buf);
-		if (skb)
-			local->total_ps_buffered--;
+	/*
+	 * If all ACs are delivery-enabled then we should reply
+	 * from any of them, if only some are enabled we reply
+	 * only from the non-enabled ones.
+	 */
+	if (ignore_for_response == BIT(IEEE80211_NUM_ACS) - 1)
+		ignore_for_response = 0;
+
+	/*
+	 * Get response frame and more data bit for it.
+	 */
+	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+		if (ignore_for_response & BIT(ac))
+			continue;
+
+		if (!skb) {
+			skb = skb_dequeue(&sta->tx_filtered[ac]);
+			if (!skb) {
+				skb = skb_dequeue(&sta->ps_tx_buf[ac]);
+				if (skb)
+					local->total_ps_buffered--;
+			}
+		}
+
+		/* FIXME: take into account driver-buffered frames */
+
+		if (!skb_queue_empty(&sta->tx_filtered[ac]) ||
+		    !skb_queue_empty(&sta->ps_tx_buf[ac])) {
+			more_data = true;
+			break;
+		}
 	}
-	no_pending_pkts = skb_queue_empty(&sta->tx_filtered) &&
-		skb_queue_empty(&sta->ps_tx_buf);
 
 	if (skb) {
 		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -1105,14 +1206,13 @@ void ieee80211_sta_ps_deliver_poll_respo
 		info->flags |= IEEE80211_TX_CTL_PSPOLL_RESPONSE;
 
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-		printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n",
-		       sta->sta.addr, sta->sta.aid,
-		       skb_queue_len(&sta->ps_tx_buf));
+		printk(KERN_DEBUG "STA %pM aid %d: PS Poll\n",
+		       sta->sta.addr, sta->sta.aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 
 		/* Use MoreData flag to indicate whether there are more
 		 * buffered frames for this STA */
-		if (no_pending_pkts)
+		if (!more_data)
 			hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
 		else
 			hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
@@ -1154,10 +1254,14 @@ void ieee80211_sta_set_buffered(struct i
 {
 	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
 
-	if (!buffered)
+	if (WARN_ON(tid >= STA_TID_NUM))
 		return;
 
-	set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
+	if (buffered)
+		set_bit(tid, &sta->driver_buffered_tids);
+	else
+		clear_bit(tid, &sta->driver_buffered_tids);
+
 	sta_info_recalc_tim(sta);
 }
 EXPORT_SYMBOL(ieee80211_sta_set_buffered);
--- a/net/mac80211/sta_info.h	2011-09-29 16:01:19.000000000 +0200
+++ b/net/mac80211/sta_info.h	2011-09-29 16:02:04.000000000 +0200
@@ -43,8 +43,6 @@
  *	be in the queues
  * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping
  *	station in power-save mode, reply when the driver unblocks.
- * @WLAN_STA_PS_DRIVER_BUF: Station has frames pending in driver internal
- *	buffers. Automatically cleared on station wake-up.
  * @WLAN_STA_TDLS_PEER: Station is a TDLS peer.
  * @WLAN_STA_TDLS_PEER_AUTH: This TDLS peer is authorized to send direct
  *	packets. This means the link is enabled.
@@ -63,7 +61,6 @@ enum ieee80211_sta_info_flags {
 	WLAN_STA_BLOCK_BA	= 1<<11,
 	WLAN_STA_PS_DRIVER	= 1<<12,
 	WLAN_STA_PSPOLL		= 1<<13,
-	WLAN_STA_PS_DRIVER_BUF	= 1<<14,
 	WLAN_STA_TDLS_PEER	= 1<<15,
 	WLAN_STA_TDLS_PEER_AUTH	= 1<<16,
 };
@@ -212,11 +209,13 @@ struct sta_ampdu_mlme {
  * @drv_unblock_wk: used for driver PS unblocking
  * @listen_interval: listen interval of this station, when we're acting as AP
  * @flags: STA flags, see &enum ieee80211_sta_info_flags
- * @ps_tx_buf: buffer of frames to transmit to this station
- *	when it leaves power saving state
- * @tx_filtered: buffer of frames we already tried to transmit
- *	but were filtered by hardware due to STA having entered
- *	power saving state
+ * @ps_tx_buf: buffers (per AC) of frames to transmit to this station
+ *	when it leaves power saving state or polls
+ * @tx_filtered: buffers (per AC) of frames we already tried to
+ *	transmit but were filtered by hardware due to STA having
+ *	entered power saving state, these are also delivered to
+ *	the station when it leaves powersave or polls for frames
+ * @driver_buffered_tids: bitmap of TIDs the driver has data buffered on
  * @rx_packets: Number of MSDUs received from this STA
  * @rx_bytes: Number of bytes received from this STA
  * @wep_weak_iv_count: number of weak WEP IVs received from this station
@@ -286,8 +285,9 @@ struct sta_info {
 	 * STA powersave frame queues, no more than the internal
 	 * locking required.
 	 */
-	struct sk_buff_head ps_tx_buf;
-	struct sk_buff_head tx_filtered;
+	struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS];
+	struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS];
+	unsigned long driver_buffered_tids;
 
 	/* Updated from RX path only, no locking requirements */
 	unsigned long rx_packets, rx_bytes;
@@ -434,8 +434,8 @@ rcu_dereference_protected_tid_tx(struct
 #define STA_HASH(sta) (sta[5])
 
 
-/* Maximum number of frames to buffer per power saving station */
-#define STA_MAX_TX_BUFFER 128
+/* Maximum number of frames to buffer per power saving station per AC */
+#define STA_MAX_TX_BUFFER	64
 
 /* Minimum buffered frame expiry time. If STA uses listen interval that is
  * smaller than this value, the minimum value here is used instead. */
--- a/include/net/mac80211.h	2011-09-29 16:01:18.000000000 +0200
+++ b/include/net/mac80211.h	2011-09-29 16:02:04.000000000 +0200
@@ -109,6 +109,7 @@ enum ieee80211_ac_numbers {
 	IEEE80211_AC_BE		= 2,
 	IEEE80211_AC_BK		= 3,
 };
+#define IEEE80211_NUM_ACS	4
 
 /**
  * struct ieee80211_tx_queue_params - transmit queue configuration
--- a/net/mac80211/status.c	2011-09-29 16:01:18.000000000 +0200
+++ b/net/mac80211/status.c	2011-09-29 16:02:04.000000000 +0200
@@ -14,6 +14,7 @@
 #include "rate.h"
 #include "mesh.h"
 #include "led.h"
+#include "wme.h"
 
 
 void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
@@ -43,6 +44,8 @@ static void ieee80211_handle_filtered_fr
 					    struct sk_buff *skb)
 {
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_hdr *hdr = (void *)skb->data;
+	int ac;
 
 	/*
 	 * This skb 'survived' a round-trip through the driver, and
@@ -62,6 +65,14 @@ static void ieee80211_handle_filtered_fr
 
 	sta->tx_filtered_count++;
 
+	if (ieee80211_is_data_qos(hdr->frame_control)) {
+		int tid = *ieee80211_get_qos_ctl(hdr) &
+					IEEE80211_QOS_CTL_TID_MASK;
+		ac = ieee802_1d_to_ac[tid & 7];
+	} else {
+		ac = IEEE80211_AC_BE;
+	}
+
 	/*
 	 * Clear the TX filter mask for this STA when sending the next
 	 * packet. If the STA went to power save mode, this will happen
@@ -104,8 +115,8 @@ static void ieee80211_handle_filtered_fr
 	 *	unknown.
 	 */
 	if (test_sta_flags(sta, WLAN_STA_PS_STA) &&
-	    skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
-		skb_queue_tail(&sta->tx_filtered, skb);
+	    skb_queue_len(&sta->tx_filtered[ac]) < STA_MAX_TX_BUFFER) {
+		skb_queue_tail(&sta->tx_filtered[ac], skb);
 		sta_info_recalc_tim(sta);
 
 		if (!timer_pending(&local->sta_cleanup))
@@ -127,7 +138,7 @@ static void ieee80211_handle_filtered_fr
 	if (net_ratelimit())
 		wiphy_debug(local->hw.wiphy,
 			    "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n",
-			    skb_queue_len(&sta->tx_filtered),
+			    skb_queue_len(&sta->tx_filtered[ac]),
 			    !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies);
 #endif
 	dev_kfree_skb(skb);
--- a/net/mac80211/debugfs_sta.c	2011-09-29 16:01:19.000000000 +0200
+++ b/net/mac80211/debugfs_sta.c	2011-09-29 16:02:04.000000000 +0200
@@ -78,8 +78,14 @@ static ssize_t sta_num_ps_buf_frames_rea
 					  size_t count, loff_t *ppos)
 {
 	struct sta_info *sta = file->private_data;
-	return mac80211_format_buffer(userbuf, count, ppos, "%u\n",
-				      skb_queue_len(&sta->ps_tx_buf));
+	char buf[17*IEEE80211_NUM_ACS], *p = buf;
+	int ac;
+
+	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+		p += scnprintf(p, sizeof(buf)+buf-p, "AC%d: %d\n", ac,
+			       skb_queue_len(&sta->ps_tx_buf[ac]) +
+			       skb_queue_len(&sta->tx_filtered[ac]));
+	return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
 }
 STA_OPS(num_ps_buf_frames);
 
--- a/net/mac80211/tx.c	2011-09-29 16:01:18.000000000 +0200
+++ b/net/mac80211/tx.c	2011-09-29 16:02:04.000000000 +0200
@@ -343,13 +343,22 @@ static void purge_old_ps_buffers(struct
 		total += skb_queue_len(&ap->ps_bc_buf);
 	}
 
+	/*
+	 * Drop one frame from each station from the lowest-priority
+	 * AC that has frames at all.
+	 */
 	list_for_each_entry_rcu(sta, &local->sta_list, list) {
-		skb = skb_dequeue(&sta->ps_tx_buf);
-		if (skb) {
-			purged++;
-			dev_kfree_skb(skb);
+		int ac;
+
+		for (ac = IEEE80211_AC_BK; ac >= IEEE80211_AC_VO; ac--) {
+			skb = skb_dequeue(&sta->ps_tx_buf[ac]);
+			total += skb_queue_len(&sta->ps_tx_buf[ac]);
+			if (skb) {
+				purged++;
+				dev_kfree_skb(skb);
+				break;
+			}
 		}
-		total += skb_queue_len(&sta->ps_tx_buf);
 	}
 
 	rcu_read_unlock();
@@ -448,22 +457,21 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
 
 	if (unlikely((staflags & (WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) &&
 		     !(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE))) {
+		int ac = skb_get_queue_mapping(tx->skb);
+
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-		printk(KERN_DEBUG "STA %pM aid %d: PS buffer (entries "
-		       "before %d)\n",
-		       sta->sta.addr, sta->sta.aid,
-		       skb_queue_len(&sta->ps_tx_buf));
+		printk(KERN_DEBUG "STA %pM aid %d: PS buffer for AC %d\n",
+		       sta->sta.addr, sta->sta.aid, ac);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 		if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
 			purge_old_ps_buffers(tx->local);
-		if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) {
-			struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf);
+		if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) {
+			struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]);
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-			if (net_ratelimit()) {
-				printk(KERN_DEBUG "%s: STA %pM TX "
-				       "buffer full - dropping oldest frame\n",
-				       tx->sdata->name, sta->sta.addr);
-			}
+			if (net_ratelimit())
+				printk(KERN_DEBUG "%s: STA %pM TX buffer for "
+				       "AC %d full - dropping oldest frame\n",
+				       tx->sdata->name, sta->sta.addr, ac);
 #endif
 			dev_kfree_skb(old);
 		} else
@@ -472,7 +480,7 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
 		info->control.jiffies = jiffies;
 		info->control.vif = &tx->sdata->vif;
 		info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
-		skb_queue_tail(&sta->ps_tx_buf, tx->skb);
+		skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb);
 
 		if (!timer_pending(&local->sta_cleanup))
 			mod_timer(&local->sta_cleanup,



^ permalink raw reply

* [PATCH v2 03/16] mac80211: also expire filtered frames
From: Johannes Berg @ 2011-09-29 14:04 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless
In-Reply-To: <20110929140425.390322480@sipsolutions.net>

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

mac80211 will expire normal PS-buffered frames, but
if the device rejected some frames for a sleeping
station, these won't be on the ps_tx_buf queue but
on the tx_filtered queue instead; this is done to
avoid reordering.

However, mac80211 will not expire frames from the
filtered queue, let's fix that.

Also add a more comments to what all this expiry is
doing and how it works.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/mac80211/sta_info.c |   57 +++++++++++++++++++++++++++++++++++++++++++-----
 net/mac80211/status.c   |    5 ++++
 2 files changed, 57 insertions(+), 5 deletions(-)

--- a/net/mac80211/sta_info.c	2011-09-29 15:52:41.000000000 +0200
+++ b/net/mac80211/sta_info.c	2011-09-29 15:52:55.000000000 +0200
@@ -709,6 +709,39 @@ static bool sta_info_cleanup_expire_buff
 	if (!sta->sdata->bss)
 		return false;
 
+	/*
+	 * First check for frames that should expire on the filtered
+	 * queue. Frames here were rejected by the driver and are on
+	 * a separate queue to avoid reordering with normal PS-buffered
+	 * frames. They also aren't accounted for right now in the
+	 * total_ps_buffered counter.
+	 */
+	for (;;) {
+		spin_lock_irqsave(&sta->tx_filtered.lock, flags);
+		skb = skb_peek(&sta->tx_filtered);
+		if (sta_info_buffer_expired(sta, skb))
+			skb = __skb_dequeue(&sta->tx_filtered);
+		else
+			skb = NULL;
+		spin_unlock_irqrestore(&sta->tx_filtered.lock, flags);
+
+		/*
+		 * Frames are queued in order, so if this one
+		 * hasn't expired yet we can stop testing. If
+		 * we actually reached the end of the queue we
+		 * also need to stop, of course.
+		 */
+		if (!skb)
+			break;
+		dev_kfree_skb(skb);
+	}
+
+	/*
+	 * Now also check the normal PS-buffered queue, this will
+	 * only find something if the filtered queue was emptied
+	 * since the filtered frames are all before the normal PS
+	 * buffered frames.
+	 */
 	for (;;) {
 		spin_lock_irqsave(&sta->ps_tx_buf.lock, flags);
 		skb = skb_peek(&sta->ps_tx_buf);
@@ -718,6 +751,11 @@ static bool sta_info_cleanup_expire_buff
 			skb = NULL;
 		spin_unlock_irqrestore(&sta->ps_tx_buf.lock, flags);
 
+		/*
+		 * frames are queued in order, so if this one
+		 * hasn't expired yet (or we reached the end of
+		 * the queue) we can stop testing
+		 */
 		if (!skb)
 			break;
 
@@ -727,13 +765,22 @@ static bool sta_info_cleanup_expire_buff
 		       sta->sta.addr);
 #endif
 		dev_kfree_skb(skb);
-
-		/* if the queue is now empty recalc TIM bit */
-		if (skb_queue_empty(&sta->ps_tx_buf))
-			sta_info_recalc_tim(sta);
 	}
 
-	return !skb_queue_empty(&sta->ps_tx_buf);
+	/*
+	 * Finally, recalculate the TIM bit for this station -- it might
+	 * now be clear because the station was too slow to retrieve its
+	 * frames.
+	 */
+	sta_info_recalc_tim(sta);
+
+	/*
+	 * Return whether there are any frames still buffered, this is
+	 * used to check whether the cleanup timer still needs to run,
+	 * if there are no frames we don't need to rearm the timer.
+	 */
+	return !(skb_queue_empty(&sta->ps_tx_buf) &&
+		 skb_queue_empty(&sta->tx_filtered));
 }
 
 static int __must_check __sta_info_destroy(struct sta_info *sta)
--- a/net/mac80211/status.c	2011-09-29 15:51:45.000000000 +0200
+++ b/net/mac80211/status.c	2011-09-29 15:52:55.000000000 +0200
@@ -107,6 +107,11 @@ static void ieee80211_handle_filtered_fr
 	    skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
 		skb_queue_tail(&sta->tx_filtered, skb);
 		sta_info_recalc_tim(sta);
+
+		if (!timer_pending(&local->sta_cleanup))
+			mod_timer(&local->sta_cleanup,
+				  round_jiffies(jiffies +
+						STA_INFO_CLEANUP_INTERVAL));
 		return;
 	}
 



^ permalink raw reply

* [PATCH v2 02/16] mac80211: unify TIM bit handling
From: Johannes Berg @ 2011-09-29 14:04 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless
In-Reply-To: <20110929140425.390322480@sipsolutions.net>

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

Currently, the TIM bit for a given station is set
and cleared all over the place. Since the logic to
set/clear it will become much more complex when we
add uAPSD support, as a first step let's collect
the entire logic in one place. This requires a few
small adjustments to other places.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/mac80211/sta_info.c |  101 ++++++++++++++++++++----------------------------
 net/mac80211/sta_info.h |    3 -
 net/mac80211/status.c   |    1 
 net/mac80211/tx.c       |   15 ++-----
 4 files changed, 51 insertions(+), 69 deletions(-)

--- a/net/mac80211/sta_info.h	2011-09-29 15:57:18.000000000 +0200
+++ b/net/mac80211/sta_info.h	2011-09-29 15:57:29.000000000 +0200
@@ -528,8 +528,7 @@ int sta_info_destroy_addr(struct ieee802
 int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata,
 			      const u8 *addr);
 
-void sta_info_set_tim_bit(struct sta_info *sta);
-void sta_info_clear_tim_bit(struct sta_info *sta);
+void sta_info_recalc_tim(struct sta_info *sta);
 
 void sta_info_init(struct ieee80211_local *local);
 void sta_info_stop(struct ieee80211_local *local);
--- a/net/mac80211/tx.c	2011-09-29 15:57:18.000000000 +0200
+++ b/net/mac80211/tx.c	2011-09-29 15:57:29.000000000 +0200
@@ -469,15 +469,6 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
 		} else
 			tx->local->total_ps_buffered++;
 
-		/*
-		 * Queue frame to be sent after STA wakes up/polls,
-		 * but don't set the TIM bit if the driver is blocking
-		 * wakeup or poll response transmissions anyway.
-		 */
-		if (skb_queue_empty(&sta->ps_tx_buf) &&
-		    !(staflags & WLAN_STA_PS_DRIVER))
-			sta_info_set_tim_bit(sta);
-
 		info->control.jiffies = jiffies;
 		info->control.vif = &tx->sdata->vif;
 		info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
@@ -488,6 +479,12 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
 				  round_jiffies(jiffies +
 						STA_INFO_CLEANUP_INTERVAL));
 
+		/*
+		 * We queued up some frames, so the TIM bit might
+		 * need to be set, recalculate it.
+		 */
+		sta_info_recalc_tim(sta);
+
 		return TX_QUEUED;
 	}
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
--- a/net/mac80211/sta_info.c	2011-09-29 15:57:18.000000000 +0200
+++ b/net/mac80211/sta_info.c	2011-09-29 15:58:07.000000000 +0200
@@ -641,54 +641,42 @@ static inline void __bss_tim_clear(struc
 	bss->tim[aid / 8] &= ~(1 << (aid % 8));
 }
 
-static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss,
-				   struct sta_info *sta)
-{
-	BUG_ON(!bss);
-
-	__bss_tim_set(bss, sta->sta.aid);
-
-	if (sta->local->ops->set_tim) {
-		sta->local->tim_in_locked_section = true;
-		drv_set_tim(sta->local, &sta->sta, true);
-		sta->local->tim_in_locked_section = false;
-	}
-}
-
-void sta_info_set_tim_bit(struct sta_info *sta)
+void sta_info_recalc_tim(struct sta_info *sta)
 {
+	struct ieee80211_local *local = sta->local;
+	struct ieee80211_if_ap *bss = sta->sdata->bss;
 	unsigned long flags;
+	bool have_data = false;
 
-	BUG_ON(!sta->sdata->bss);
-
-	spin_lock_irqsave(&sta->local->sta_lock, flags);
-	__sta_info_set_tim_bit(sta->sdata->bss, sta);
-	spin_unlock_irqrestore(&sta->local->sta_lock, flags);
-}
+	if (WARN_ON_ONCE(!sta->sdata->bss))
+		return;
 
-static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss,
-				     struct sta_info *sta)
-{
-	BUG_ON(!bss);
+	/* No need to do anything if the driver does all */
+	if (local->hw.flags & IEEE80211_HW_AP_LINK_PS)
+		return;
 
-	__bss_tim_clear(bss, sta->sta.aid);
+	if (sta->dead)
+		goto done;
 
-	if (sta->local->ops->set_tim) {
-		sta->local->tim_in_locked_section = true;
-		drv_set_tim(sta->local, &sta->sta, false);
-		sta->local->tim_in_locked_section = false;
-	}
-}
+	have_data = test_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF) ||
+		    !skb_queue_empty(&sta->tx_filtered) ||
+		    !skb_queue_empty(&sta->ps_tx_buf);
 
-void sta_info_clear_tim_bit(struct sta_info *sta)
-{
-	unsigned long flags;
+ done:
+	spin_lock_irqsave(&local->sta_lock, flags);
 
-	BUG_ON(!sta->sdata->bss);
+	if (have_data)
+		__bss_tim_set(bss, sta->sta.aid);
+	else
+		__bss_tim_clear(bss, sta->sta.aid);
+
+	if (local->ops->set_tim) {
+		local->tim_in_locked_section = true;
+		drv_set_tim(local, &sta->sta, have_data);
+		local->tim_in_locked_section = false;
+	}
 
-	spin_lock_irqsave(&sta->local->sta_lock, flags);
-	__sta_info_clear_tim_bit(sta->sdata->bss, sta);
-	spin_unlock_irqrestore(&sta->local->sta_lock, flags);
+	spin_unlock_irqrestore(&local->sta_lock, flags);
 }
 
 static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb)
@@ -717,6 +705,10 @@ static bool sta_info_cleanup_expire_buff
 	unsigned long flags;
 	struct sk_buff *skb;
 
+	/* This is only necessary for stations on BSS interfaces */
+	if (!sta->sdata->bss)
+		return false;
+
 	for (;;) {
 		spin_lock_irqsave(&sta->ps_tx_buf.lock, flags);
 		skb = skb_peek(&sta->ps_tx_buf);
@@ -736,9 +728,9 @@ static bool sta_info_cleanup_expire_buff
 #endif
 		dev_kfree_skb(skb);
 
-		if (skb_queue_empty(&sta->ps_tx_buf) &&
-		    !test_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF))
-			sta_info_clear_tim_bit(sta);
+		/* if the queue is now empty recalc TIM bit */
+		if (skb_queue_empty(&sta->ps_tx_buf))
+			sta_info_recalc_tim(sta);
 	}
 
 	return !skb_queue_empty(&sta->ps_tx_buf);
@@ -748,7 +740,6 @@ static int __must_check __sta_info_destr
 {
 	struct ieee80211_local *local;
 	struct ieee80211_sub_if_data *sdata;
-	struct sk_buff *skb;
 	unsigned long flags;
 	int ret, i;
 
@@ -792,7 +783,7 @@ static int __must_check __sta_info_destr
 		BUG_ON(!sdata->bss);
 
 		atomic_dec(&sdata->bss->num_sta_ps);
-		sta_info_clear_tim_bit(sta);
+		sta_info_recalc_tim(sta);
 	}
 
 	local->num_sta--;
@@ -818,6 +809,10 @@ static int __must_check __sta_info_destr
 	 */
 	synchronize_rcu();
 
+	local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf);
+	__skb_queue_purge(&sta->ps_tx_buf);
+	__skb_queue_purge(&sta->tx_filtered);
+
 #ifdef CONFIG_MAC80211_MESH
 	if (ieee80211_vif_is_mesh(&sdata->vif))
 		mesh_accept_plinks_update(sdata);
@@ -840,14 +835,6 @@ static int __must_check __sta_info_destr
 	}
 #endif
 
-	while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
-		local->total_ps_buffered--;
-		dev_kfree_skb_any(skb);
-	}
-
-	while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL)
-		dev_kfree_skb_any(skb);
-
 	__sta_info_free(local, sta);
 
 	return 0;
@@ -1027,9 +1014,6 @@ void ieee80211_sta_ps_deliver_wakeup(str
 	if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
 		drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
 
-	if (!skb_queue_empty(&sta->ps_tx_buf))
-		sta_info_clear_tim_bit(sta);
-
 	/* Send all buffered frames to the station */
 	sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered);
 	buffered = ieee80211_add_pending_skbs_fn(local, &sta->ps_tx_buf,
@@ -1037,6 +1021,8 @@ void ieee80211_sta_ps_deliver_wakeup(str
 	sent += buffered;
 	local->total_ps_buffered -= buffered;
 
+	sta_info_recalc_tim(sta);
+
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 	printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames "
 	       "since STA not sleeping anymore\n", sdata->name,
@@ -1086,8 +1072,7 @@ void ieee80211_sta_ps_deliver_poll_respo
 
 		ieee80211_add_pending_skb(local, skb);
 
-		if (no_pending_pkts)
-			sta_info_clear_tim_bit(sta);
+		sta_info_recalc_tim(sta);
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 	} else {
 		/*
@@ -1126,6 +1111,6 @@ void ieee80211_sta_set_buffered(struct i
 		return;
 
 	set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
-	sta_info_set_tim_bit(sta);
+	sta_info_recalc_tim(sta);
 }
 EXPORT_SYMBOL(ieee80211_sta_set_buffered);
--- a/net/mac80211/status.c	2011-09-29 15:57:18.000000000 +0200
+++ b/net/mac80211/status.c	2011-09-29 15:58:07.000000000 +0200
@@ -106,6 +106,7 @@ static void ieee80211_handle_filtered_fr
 	if (test_sta_flags(sta, WLAN_STA_PS_STA) &&
 	    skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
 		skb_queue_tail(&sta->tx_filtered, skb);
+		sta_info_recalc_tim(sta);
 		return;
 	}
 



^ permalink raw reply

* [PATCH v2 01/16] mac80211: let drivers inform it about per TID buffered frames
From: Johannes Berg @ 2011-09-29 14:04 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless
In-Reply-To: <20110929140425.390322480@sipsolutions.net>

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

For uAPSD implementation, it is necessary to know on
which ACs frames are buffered. mac80211 obviously
knows about the frames it has buffered itself, but
with aggregation many drivers buffer frames. Thus,
mac80211 needs to be informed about this.

For now, since we don't have APSD in any form, this
will unconditionally set the TIM bit for the station
but later with uAPSD only some ACs might cause the
TIM bit to be set.

ath9k is the only driver using this API and I only
modify it in the most basic way, it won't be able
to implement uAPSD with this yet. But it can't do
that anyway since there's no way to selectively
release frames to the peer yet.

Since drivers will buffer frames per TID, let them
inform mac80211 on a per TID basis, mac80211 will
then sort out the AC mapping itself.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 drivers/net/wireless/ath/ath9k/ath9k.h |    3 ++-
 drivers/net/wireless/ath/ath9k/main.c  |    3 +--
 drivers/net/wireless/ath/ath9k/xmit.c  |   14 +++++++-------
 include/net/mac80211.h                 |   30 ++++++++++++++++++++++++------
 net/mac80211/sta_info.c                |    8 ++++++--
 5 files changed, 40 insertions(+), 18 deletions(-)

--- a/include/net/mac80211.h	2011-09-28 19:09:57.000000000 +0200
+++ b/include/net/mac80211.h	2011-09-28 19:10:10.000000000 +0200
@@ -2361,17 +2361,35 @@ static inline int ieee80211_sta_ps_trans
 #define IEEE80211_TX_STATUS_HEADROOM	13
 
 /**
- * ieee80211_sta_set_tim - set the TIM bit for a sleeping station
+ * ieee80211_sta_set_buffered - inform mac80211 about driver-buffered frames
  * @sta: &struct ieee80211_sta pointer for the sleeping station
+ * @tid: the TID that has buffered frames
+ * @buffered: indicates whether or not frames are buffered for this TID
  *
  * If a driver buffers frames for a powersave station instead of passing
- * them back to mac80211 for retransmission, the station needs to be told
- * to wake up using the TIM bitmap in the beacon.
+ * them back to mac80211 for retransmission, the station may still need
+ * to be told that there are buffered frames via the TIM bit.
  *
- * This function sets the station's TIM bit - it will be cleared when the
- * station wakes up.
+ * This function informs mac80211 whether or not there are frames that are
+ * buffered in the driver for a given TID; mac80211 can then use this data
+ * to set the TIM bit (NOTE: This may call back into the driver's set_tim
+ * call! Beware of the locking!)
+ *
+ * If all frames are released to the station (due to PS-poll or uAPSD)
+ * then the driver needs to inform mac80211 that there no longer are
+ * frames buffered. However, when the station wakes up mac80211 assumes
+ * that all buffered frames will be transmitted and clears this data,
+ * drivers need to make sure they inform mac80211 about all buffered
+ * frames on the sleep transition (sta_notify() with %STA_NOTIFY_SLEEP).
+ *
+ * Note that technically mac80211 only needs to know this per AC, not per
+ * TID, but since driver buffering will inevitably happen per TID (since
+ * it is related to aggregation) it is easier to make mac80211 map the
+ * TID to the AC as required instead of keeping track in all drivers that
+ * use this API.
  */
-void ieee80211_sta_set_tim(struct ieee80211_sta *sta);
+void ieee80211_sta_set_buffered(struct ieee80211_sta *sta,
+				u8 tid, bool buffered);
 
 /**
  * ieee80211_tx_status - transmit status callback
--- a/net/mac80211/sta_info.c	2011-09-28 17:12:05.000000000 +0200
+++ b/net/mac80211/sta_info.c	2011-09-28 19:10:10.000000000 +0200
@@ -1117,11 +1117,15 @@ void ieee80211_sta_block_awake(struct ie
 }
 EXPORT_SYMBOL(ieee80211_sta_block_awake);
 
-void ieee80211_sta_set_tim(struct ieee80211_sta *pubsta)
+void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta,
+				u8 tid, bool buffered)
 {
 	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
 
+	if (!buffered)
+		return;
+
 	set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
 	sta_info_set_tim_bit(sta);
 }
-EXPORT_SYMBOL(ieee80211_sta_set_tim);
+EXPORT_SYMBOL(ieee80211_sta_set_buffered);
--- a/drivers/net/wireless/ath/ath9k/ath9k.h	2011-09-28 17:12:05.000000000 +0200
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h	2011-09-28 19:10:10.000000000 +0200
@@ -340,7 +340,8 @@ void ath_tx_aggr_stop(struct ath_softc *
 void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
 
 void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
-bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an);
+void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
+		       struct ath_node *an);
 
 /********/
 /* VIFs */
--- a/drivers/net/wireless/ath/ath9k/main.c	2011-09-28 17:12:05.000000000 +0200
+++ b/drivers/net/wireless/ath/ath9k/main.c	2011-09-28 19:10:10.000000000 +0200
@@ -1833,8 +1833,7 @@ static void ath9k_sta_notify(struct ieee
 	switch (cmd) {
 	case STA_NOTIFY_SLEEP:
 		an->sleeping = true;
-		if (ath_tx_aggr_sleep(sc, an))
-			ieee80211_sta_set_tim(sta);
+		ath_tx_aggr_sleep(sta, sc, an);
 		break;
 	case STA_NOTIFY_AWAKE:
 		an->sleeping = false;
--- a/drivers/net/wireless/ath/ath9k/xmit.c	2011-09-28 17:12:05.000000000 +0200
+++ b/drivers/net/wireless/ath/ath9k/xmit.c	2011-09-28 19:10:10.000000000 +0200
@@ -542,7 +542,7 @@ static void ath_tx_complete_aggr(struct
 	/* prepend un-acked frames to the beginning of the pending frame queue */
 	if (!skb_queue_empty(&bf_pending)) {
 		if (an->sleeping)
-			ieee80211_sta_set_tim(sta);
+			ieee80211_sta_set_buffered(sta, tid->tidno, true);
 
 		spin_lock_bh(&txq->axq_lock);
 		if (clear_filter)
@@ -1153,12 +1153,13 @@ void ath_tx_aggr_stop(struct ath_softc *
 	ath_tx_flush_tid(sc, txtid);
 }
 
-bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
+void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
+		       struct ath_node *an)
 {
 	struct ath_atx_tid *tid;
 	struct ath_atx_ac *ac;
 	struct ath_txq *txq;
-	bool buffered = false;
+	bool buffered;
 	int tidno;
 
 	for (tidno = 0, tid = &an->tid[tidno];
@@ -1172,8 +1173,7 @@ bool ath_tx_aggr_sleep(struct ath_softc
 
 		spin_lock_bh(&txq->axq_lock);
 
-		if (!skb_queue_empty(&tid->buf_q))
-			buffered = true;
+		buffered = !skb_queue_empty(&tid->buf_q);
 
 		tid->sched = false;
 		list_del(&tid->list);
@@ -1184,9 +1184,9 @@ bool ath_tx_aggr_sleep(struct ath_softc
 		}
 
 		spin_unlock_bh(&txq->axq_lock);
-	}
 
-	return buffered;
+		ieee80211_sta_set_buffered(sta, tidno, buffered);
+	}
 }
 
 void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)



^ permalink raw reply

* [PATCH v2 00/16] mac80211 uAPSD support
From: Johannes Berg @ 2011-09-29 14:04 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless

Sorry for the resend!

This fixes a stupid bug that made resume crash.

johannes


^ permalink raw reply

* Re: [PATCH 2/2] ath9k: Choose highest rate of MRR based on IEEE80211_TX_CTL_USE_MINRATE
From: Rajkumar Manoharan @ 2011-09-29 13:37 UTC (permalink / raw)
  To: Felix Fietkau; +Cc: linville, linux-wireless
In-Reply-To: <4E846D4F.1070900@openwrt.org>

On Thu, Sep 29, 2011 at 03:06:23PM +0200, Felix Fietkau wrote:
> On 2011-09-29 2:14 PM, Rajkumar Manoharan wrote:
> >On Thu, Sep 29, 2011 at 01:32:03PM +0200, Felix Fietkau wrote:
> >> On 2011-09-29 1:24 PM, Rajkumar Manoharan wrote:
> >> >Select appropriate rate as highest rate of rate series, if the frame
> >> >was asked to be sent at minimum rate. For example nullfunc frames
> >> >either can be sent at HT rates on normal case or at non-HT rates if
> >> >it is used for connection monitoring.
> >> >
> >> >Signed-off-by: Rajkumar Manoharan<rmanohar@qca.qualcomm.com>
> >> >---
> >> >   drivers/net/wireless/ath/ath9k/rc.c |    4 ++--
> >> >   1 files changed, 2 insertions(+), 2 deletions(-)
> >> >
> >> Shouldn't the check for IEEE80211_TX_CTL_USE_MINRATE be in
> >> rate_control_send_low(), so that it does not have to be repeated in
> >> every single rate control module?
> >>
> >But I donno what could be the side effect of changing rate_control_send_low
> >as it is used by all drivers. And also if the rate control provide the
> >minrate, it can be used to update the PER upon tx status. isnt it?
> It always updates the PER upon tx status, even if
> rate_control_send_low was used. It should work the same way for
> every driver, so I think putting this in the ath9k rc is the wrong
> place, and it would be weird if a flag with such a generic name as
> IEEE80211_TX_CTL_USE_MINRATE would be used by some rate control
> modules and ignored by others.
>
That true. Till now rate_control_send_low never be used for data frame.
So just to be causious, I dicided to process tx_ctl at rate control side.
If it wont break any rate control algo other than ath9k, then I send my
earlier rfc patch. Thanks for your input.

--
Rajkumar

^ permalink raw reply

* Re: [PATCH 2/2] ath9k: Choose highest rate of MRR based on IEEE80211_TX_CTL_USE_MINRATE
From: Felix Fietkau @ 2011-09-29 13:06 UTC (permalink / raw)
  To: Rajkumar Manoharan; +Cc: linville, linux-wireless
In-Reply-To: <20110929121426.GA20802@vmraj-lnx.users.atheros.com>

On 2011-09-29 2:14 PM, Rajkumar Manoharan wrote:
> On Thu, Sep 29, 2011 at 01:32:03PM +0200, Felix Fietkau wrote:
>>  On 2011-09-29 1:24 PM, Rajkumar Manoharan wrote:
>>  >Select appropriate rate as highest rate of rate series, if the frame
>>  >was asked to be sent at minimum rate. For example nullfunc frames
>>  >either can be sent at HT rates on normal case or at non-HT rates if
>>  >it is used for connection monitoring.
>>  >
>>  >Signed-off-by: Rajkumar Manoharan<rmanohar@qca.qualcomm.com>
>>  >---
>>  >   drivers/net/wireless/ath/ath9k/rc.c |    4 ++--
>>  >   1 files changed, 2 insertions(+), 2 deletions(-)
>>  >
>>  Shouldn't the check for IEEE80211_TX_CTL_USE_MINRATE be in
>>  rate_control_send_low(), so that it does not have to be repeated in
>>  every single rate control module?
>>
> But I donno what could be the side effect of changing rate_control_send_low
> as it is used by all drivers. And also if the rate control provide the
> minrate, it can be used to update the PER upon tx status. isnt it?
It always updates the PER upon tx status, even if rate_control_send_low 
was used. It should work the same way for every driver, so I think 
putting this in the ath9k rc is the wrong place, and it would be weird 
if a flag with such a generic name as IEEE80211_TX_CTL_USE_MINRATE would 
be used by some rate control modules and ignored by others.

- Felix

^ permalink raw reply

* Re: Regulatory revamp status
From: Zefir Kurtisi @ 2011-09-29 12:46 UTC (permalink / raw)
  To: Adrian Chadd
  Cc: Luis R. Rodriguez, linux-wireless, Boris Presman, Assaf Azulay,
	Michael Green, David Quan, Kevin Hayes, Arun Venkataraman
In-Reply-To: <CAJ-VmonqEs4mODDa2=fTj8zWHwRM7-G5e=BWNUyGdy65+kYvfg@mail.gmail.com>

On 09/29/2011 01:45 PM, Adrian Chadd wrote:
> On 29 September 2011 16:37, Zefir Kurtisi <zefir.kurtisi@neratec.com> wrote:
>> Thanks for the update.
>>
>> To me it looks not reasonable to mix in between the two approaches: either we assume countrycodes use the same DFS region for all channels, or each channel/band needs to have its own. Otherwise I feel that a DFS region bitmap would give a semi-flexible compromise that might end up being insufficient to represent some fancy countrycodes.
> 
> There's some funny stuff in there.
> 
> For example, some of the DFS bands have different CAC/NOL timing. :-)
> 
> 
> 
> Adrian

Really? Where would be 'there' countrycode-wise?

That would definitely break today's CRDA capabilities :-\


Zefir

^ permalink raw reply

* Re: [PATCH 2/2] ath9k: Choose highest rate of MRR based on IEEE80211_TX_CTL_USE_MINRATE
From: Rajkumar Manoharan @ 2011-09-29 12:14 UTC (permalink / raw)
  To: Felix Fietkau; +Cc: linville, linux-wireless
In-Reply-To: <4E845733.1000203@openwrt.org>

On Thu, Sep 29, 2011 at 01:32:03PM +0200, Felix Fietkau wrote:
> On 2011-09-29 1:24 PM, Rajkumar Manoharan wrote:
> >Select appropriate rate as highest rate of rate series, if the frame
> >was asked to be sent at minimum rate. For example nullfunc frames
> >either can be sent at HT rates on normal case or at non-HT rates if
> >it is used for connection monitoring.
> >
> >Signed-off-by: Rajkumar Manoharan<rmanohar@qca.qualcomm.com>
> >---
> >  drivers/net/wireless/ath/ath9k/rc.c |    4 ++--
> >  1 files changed, 2 insertions(+), 2 deletions(-)
> >
> Shouldn't the check for IEEE80211_TX_CTL_USE_MINRATE be in
> rate_control_send_low(), so that it does not have to be repeated in
> every single rate control module?
>
But I donno what could be the side effect of changing rate_control_send_low
as it is used by all drivers. And also if the rate control provide the
minrate, it can be used to update the PER upon tx status. isnt it?

--
Rajkumar

^ permalink raw reply

* [PATCH v3] net:rfkill: add a gpio setup function into GPIO rfkill
From: Sangwook Lee @ 2011-09-29 11:57 UTC (permalink / raw)
  To: johannes, rklein; +Cc: linux-kernel, linux-wireless, patches, Sangwook Lee

Add a gpio setup function which gives a chance to set up
platform specific configuration such as pin multiplexing,
input/output direction at the runtime or booting time.

Signed-off-by: Sangwook Lee <sangwook.lee@linaro.org>
---
v3:
  add a gpio clean-up function into GPIO rfkill
v2:
- fixed the return type after checking gpio_runtime_setup

 include/linux/rfkill-gpio.h |    4 ++++
 net/rfkill/rfkill-gpio.c    |   11 +++++++++++
 2 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/include/linux/rfkill-gpio.h b/include/linux/rfkill-gpio.h
index a175d05..4d09f6e 100644
--- a/include/linux/rfkill-gpio.h
+++ b/include/linux/rfkill-gpio.h
@@ -30,6 +30,8 @@
  * @reset_gpio:		GPIO which is used for reseting rfkill switch
  * @shutdown_gpio:	GPIO which is used for shutdown of rfkill switch
  * @power_clk_name:	[optional] name of clk to turn off while blocked
+ * @gpio_runtime_close:	clean up platform specific gpio configuration
+ * @gpio_runtime_setup:	set up platform specific gpio configuration
  */
 
 struct rfkill_gpio_platform_data {
@@ -38,6 +40,8 @@ struct rfkill_gpio_platform_data {
 	int			shutdown_gpio;
 	const char		*power_clk_name;
 	enum rfkill_type	type;
+	void	(*gpio_runtime_close)(struct platform_device *);
+	int	(*gpio_runtime_setup)(struct platform_device *);
 };
 
 #endif /* __RFKILL_GPIO_H */
diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c
index 256c5dd..128677d 100644
--- a/net/rfkill/rfkill-gpio.c
+++ b/net/rfkill/rfkill-gpio.c
@@ -101,6 +101,14 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
 	if (!rfkill)
 		return -ENOMEM;
 
+	if (pdata->gpio_runtime_setup) {
+		ret = pdata->gpio_runtime_setup(pdev);
+		if (ret) {
+			pr_warn("%s: can't set up gpio\n", __func__);
+			return ret;
+		}
+	}
+
 	rfkill->pdata = pdata;
 
 	len = strlen(pdata->name);
@@ -182,7 +190,10 @@ fail_alloc:
 static int rfkill_gpio_remove(struct platform_device *pdev)
 {
 	struct rfkill_gpio_data *rfkill = platform_get_drvdata(pdev);
+	struct rfkill_gpio_platform_data *pdata = pdev->dev.platform_data;
 
+	if (pdata->gpio_runtime_close)
+		pdata->gpio_runtime_close(pdev);
 	rfkill_unregister(rfkill->rfkill_dev);
 	rfkill_destroy(rfkill->rfkill_dev);
 	if (gpio_is_valid(rfkill->pdata->shutdown_gpio))
-- 
1.7.4.1


^ permalink raw reply related

* Re: Regulatory revamp status
From: Adrian Chadd @ 2011-09-29 11:45 UTC (permalink / raw)
  To: Zefir Kurtisi
  Cc: Luis R. Rodriguez, linux-wireless, Boris Presman, Assaf Azulay,
	Michael Green, David Quan, Kevin Hayes, Arun Venkataraman
In-Reply-To: <1125417094.1836.1317285426615.JavaMail.root@idefix>

On 29 September 2011 16:37, Zefir Kurtisi <zefir.kurtisi@neratec.com> wrote:
> Thanks for the update.
>
> To me it looks not reasonable to mix in between the two approaches: either we assume countrycodes use the same DFS region for all channels, or each channel/band needs to have its own. Otherwise I feel that a DFS region bitmap would give a semi-flexible compromise that might end up being insufficient to represent some fancy countrycodes.

There's some funny stuff in there.

For example, some of the DFS bands have different CAC/NOL timing. :-)



Adrian

^ permalink raw reply

* [PATCHv2] mac80211: Allow noack flag overwrite for injected frames
From: Helmut Schaa @ 2011-09-29 11:42 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, johannes, Helmut Schaa
In-Reply-To: <1317288432-26380-1-git-send-email-helmut.schaa@googlemail.com>

Allow injected unicast frames to be sent without having to wait
for an ACK.

Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
---
 include/net/ieee80211_radiotap.h |    1 +
 net/mac80211/tx.c                |   15 +++++++++++++--
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h
index b0be5fb..7e2c4d4 100644
--- a/include/net/ieee80211_radiotap.h
+++ b/include/net/ieee80211_radiotap.h
@@ -251,6 +251,7 @@ enum ieee80211_radiotap_type {
 						 * retries */
 #define IEEE80211_RADIOTAP_F_TX_CTS	0x0002	/* used cts 'protection' */
 #define IEEE80211_RADIOTAP_F_TX_RTS	0x0004	/* used rts/cts handshake */
+#define IEEE80211_RADIOTAP_F_TX_NOACK	0x0008	/* don't expect an ack */
 
 
 /* For IEEE80211_RADIOTAP_MCS */
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 0107263..c1bad18 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1047,6 +1047,7 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
 						   NULL);
+	u16 txflags;
 
 	info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
 	tx->flags &= ~IEEE80211_TX_FRAGMENTED;
@@ -1095,6 +1096,13 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
 				tx->flags |= IEEE80211_TX_FRAGMENTED;
 			break;
 
+		case IEEE80211_RADIOTAP_TX_FLAGS:
+			txflags = le16_to_cpu(get_unaligned((__le16*)
+						iterator.this_arg));
+			if (txflags & IEEE80211_RADIOTAP_F_TX_NOACK)
+				info->flags |= IEEE80211_TX_CTL_NO_ACK;
+			break;
+
 		/*
 		 * Please update the file
 		 * Documentation/networking/mac80211-injection.txt
@@ -1257,8 +1265,11 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
 		tx->flags |= IEEE80211_TX_UNICAST;
 		if (unlikely(local->wifi_wme_noack_test))
 			info->flags |= IEEE80211_TX_CTL_NO_ACK;
-		else
-			info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
+		/*
+		 * Flags are initialized to 0. Hence, no need to
+		 * explicitly unset IEEE80211_TX_CTL_NO_ACK since
+		 * it might already be set for injected frames.
+		 */
 	}
 
 	if (tx->flags & IEEE80211_TX_FRAGMENTED) {
-- 
1.7.3.4


^ permalink raw reply related

* Re: [PATCH 2/2] ath9k: Choose highest rate of MRR based on IEEE80211_TX_CTL_USE_MINRATE
From: Felix Fietkau @ 2011-09-29 11:32 UTC (permalink / raw)
  To: Rajkumar Manoharan; +Cc: linville, linux-wireless
In-Reply-To: <1317295446-20749-1-git-send-email-rmanohar@qca.qualcomm.com>

On 2011-09-29 1:24 PM, Rajkumar Manoharan wrote:
> Select appropriate rate as highest rate of rate series, if the frame
> was asked to be sent at minimum rate. For example nullfunc frames
> either can be sent at HT rates on normal case or at non-HT rates if
> it is used for connection monitoring.
>
> Signed-off-by: Rajkumar Manoharan<rmanohar@qca.qualcomm.com>
> ---
>   drivers/net/wireless/ath/ath9k/rc.c |    4 ++--
>   1 files changed, 2 insertions(+), 2 deletions(-)
>
Shouldn't the check for IEEE80211_TX_CTL_USE_MINRATE be in 
rate_control_send_low(), so that it does not have to be repeated in 
every single rate control module?

- Felix

^ permalink raw reply

* [PATCH 2/2] ath9k: Choose highest rate of MRR based on IEEE80211_TX_CTL_USE_MINRATE
From: Rajkumar Manoharan @ 2011-09-29 11:24 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Rajkumar Manoharan

Select appropriate rate as highest rate of rate series, if the frame
was asked to be sent at minimum rate. For example nullfunc frames
either can be sent at HT rates on normal case or at non-HT rates if
it is used for connection monitoring.

Signed-off-by: Rajkumar Manoharan <rmanohar@qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath9k/rc.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index 8448281..3509f14 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -789,8 +789,8 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 	try_per_rate = 4;
 
 	rate_table = ath_rc_priv->rate_table;
-	rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table,
-				     &is_probe, false);
+	rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe,
+			     !!(tx_info->flags & IEEE80211_TX_CTL_USE_MINRATE));
 	high_rix = rix;
 
 	/*
-- 
1.7.6.4


^ permalink raw reply related

* [PATCH 1/2] mac80211: Ask rate control to send probing frames at lower rate
From: Rajkumar Manoharan @ 2011-09-29 11:23 UTC (permalink / raw)
  To: johannes; +Cc: linville, linux-wireless, Rajkumar Manoharan

Recently mac80211 was changed to use nullfunc instead of probe
request for connection monitoring for tx ack status reporting
hardwares. Sometimes in congested network, STA got disconnected
quickly after the association. It was observered that the rate
control was not adopted to environment due to minimal transmission.

As the nullfunc are used for monitoring purpose, these frames should
not be sacrificed for rate control updation. So better to ask to
rate control to send the monitoring null func frames at minimum rate
that could help to retain the connection.

Signed-off-by: Rajkumar Manoharan <rmanohar@qca.qualcomm.com>
---
 include/net/mac80211.h |    4 ++++
 net/mac80211/mlme.c    |    5 +++++
 2 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 1e83afa..62faf6c 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -366,6 +366,9 @@ struct ieee80211_bss_conf {
  * @IEEE80211_TX_CTL_NO_CCK_RATE: This frame will be sent at non CCK rate.
  *	This flag is actually used for management frame especially for P2P
  *	frames not being sent at CCK rate in 2GHz band.
+ * @IEEE80211_TX_CTL_USE_MINRATE: This frame will be sent at lowest rate.
+ *	This flag is used to send nullfunc frame at minimum rate where
+ *	the nullfunc is used for connection monitoring.
  *
  * Note: If you have to add new flags to the enumeration, then don't
  *	 forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary.
@@ -397,6 +400,7 @@ enum mac80211_tx_control_flags {
 	IEEE80211_TX_CTL_TX_OFFCHAN		= BIT(25),
 	IEEE80211_TX_INTFL_TKIP_MIC_FAILURE	= BIT(26),
 	IEEE80211_TX_CTL_NO_CCK_RATE		= BIT(27),
+	IEEE80211_TX_CTL_USE_MINRATE		= BIT(28),
 };
 
 #define IEEE80211_TX_CTL_STBC_SHIFT		23
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index cd37a4e..d87a88e 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -348,6 +348,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
 {
 	struct sk_buff *skb;
 	struct ieee80211_hdr_3addr *nullfunc;
+	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
 	skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif);
 	if (!skb)
@@ -358,6 +359,10 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
 		nullfunc->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
 
 	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+	if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
+			    IEEE80211_STA_CONNECTION_POLL))
+		IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE;
+
 	ieee80211_tx_skb(sdata, skb);
 }
 
-- 
1.7.6.4


^ permalink raw reply related

* Re: [PATCH] mac80211: Allow NO_ACK flag overwrite for injected frames
From: Helmut Schaa @ 2011-09-29 10:50 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, linville
In-Reply-To: <1317291672.3974.3.camel@jlt3.sipsolutions.net>

On Thu, Sep 29, 2011 at 12:21 PM, Johannes Berg
<johannes@sipsolutions.net> wrote:
>> >> @@ -1257,7 +1265,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
>> >>               tx->flags |= IEEE80211_TX_UNICAST;
>> >>               if (unlikely(local->wifi_wme_noack_test))
>> >>                       info->flags |= IEEE80211_TX_CTL_NO_ACK;
>> >> -             else
>> >> +             else if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
>> >>                       info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
>> >
>> > ??
>>
>> Don't remove the IEEE80211_TX_CTL_NO_ACK flag when it was set via radiotap.
>
> Well, ok, but the logic is:
>
> if (flag not set)
>        unset flag
>
> which is kinda useless, right?

Haha, right!

Since the tx info is always initialized to 0 the code was useless before
as well :) but now it is even more useless ...

I guess it was good for documentary purposes. Hence, I'll replace it with
a comment instead ...

Helmut

^ permalink raw reply

* Re: [PATCH] wireless: at76c50x: fix multithread access to hex2str
From: Andy Shevchenko @ 2011-09-29 10:46 UTC (permalink / raw)
  To: Pavel Roskin; +Cc: linux-wireless, John W. Linville
In-Reply-To: <20110928171909.6889916c@mj>

On Wed, 2011-09-28 at 17:19 -0400, Pavel Roskin wrote: 
> On Wed, 28 Sep 2011 16:17:31 +0300
> Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:
> 
> > The original hex2str uses finite array of buffers to keep output
> > data. It's a wrong approach, because we can't say at compile time how
> > many threads will be used.
> > 
> > This patch introduces one buffer and global mutex to access this
> > function. All calls of it are wrapped by locking this mutex. It saves
> > some memory as a side effect.
> > 
> > Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> > Cc: "John W. Linville" <linville@tuxdriver.com>
> 
> The reason for having 4 buffers is to allow using hex2str() more than
> once in the same printk() statement.
And even in this case it has a weird limitation. Why 4? Why not 5 or 20?

> As you can see, hex2str() is never used in one statement more than once.
Yeah, that's why it works in both cases.

> Your solution would make
> it impossible to use hex2str() twice in the same printk(), as the
> buffer would be reused.  Actually, wrong data would be printed with no
> warning!  Such code doesn't exist in the driver, but it could be added
> by somebody looking for a problem.  And that would hamper debugging
> instead of helping it.
You know, there is no statement, how to use the function for the 3rd
party developer. We have the mailing list not only for bots. I'm glad to
hear some explanations which I didn't catch from the code itself.

> I think we can live with a debug function printing wrong data if it's
> called by 5 callers at once.
I disagree with such attitude.

> And if you want a perfectly correct fix, I suggest that you use
> buffers allocated by the callers on the stack.  That's less intrusive
> than mutexes, and it would allow using more than one hex2str() in one
> statement as long as the buffers are different.
> Or maybe hex2str() should be replaced with calls to print_hex_dump_bytes()?
I thought about it. Actually I must write RFC prefix to the patch, my
bad.

> Or maybe you could develop an extension for printk() format that would
> dump strings of the given length?  Something like %pM, but with an
> extra argument (and make sure it would not trigger a gcc warning).
> This way, everybody would benefit.
I don't think it would be a noticeable benefit. On the other hand
vsnprintf() is hugely overloaded by many "extensions" to the C99
variant.

> Please rethink whether it's helpful to send such "fixes" for old and
> little maintained drivers.
Last copyright is 2010, TODO list actually suggests to remove hex2str at
all.


-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

^ permalink raw reply

* Re: ath9k: irq storm after suspend/resume
From: Adrian Chadd @ 2011-09-29 10:33 UTC (permalink / raw)
  To: Mohammed Shafi; +Cc: Clemens Buchacher, linux-wireless, beta992
In-Reply-To: <CAD2nsn3ZwUJsFRLyjKenO6Pm3+jr9gfmAMRDQPStEcC1hN_mkw@mail.gmail.com>

Hm,

Has someone figured out which ISR bits are being triggered?

If not, I can likely whip up a patch which adds some relevant
printk's. I think it's worth establishing:

* is it a sync/async interrupt;
* is it a fatal interrupt (eg something like a PCI bus error or
transaction timeout) or is it a normal ISR bit that keeps firing;
* .. and which one is firing.


Adrian

^ permalink raw reply

* Re: [PATCH] mac80211: Allow NO_ACK flag overwrite for injected frames
From: Johannes Berg @ 2011-09-29 10:21 UTC (permalink / raw)
  To: Helmut Schaa; +Cc: linux-wireless, linville
In-Reply-To: <CAGXE3d87utQhKifrA8bco14rv9zn3-uZEsDiisg8wkDfipeBMQ@mail.gmail.com>

On Thu, 2011-09-29 at 12:02 +0200, Helmut Schaa wrote:

> > Makes sense, but I wonder if we really should continue using
> > radiotap :-) Maybe mgmt-tx in nl80211 would be appropriate.

An nl80211 flag, and the right modifications in hostapd to use mgmt-tx
and the flag. But I guess that's just another thing on the growing list
of things to do to move hostapd to not use monitor interfaces ...

> Hmm, not sure how much work that would be ...
> 
> >> @@ -1257,7 +1265,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
> >>               tx->flags |= IEEE80211_TX_UNICAST;
> >>               if (unlikely(local->wifi_wme_noack_test))
> >>                       info->flags |= IEEE80211_TX_CTL_NO_ACK;
> >> -             else
> >> +             else if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
> >>                       info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
> >
> > ??
> 
> Don't remove the IEEE80211_TX_CTL_NO_ACK flag when it was set via radiotap.

Well, ok, but the logic is:

if (flag not set)
	unset flag

which is kinda useless, right?

johannes


^ permalink raw reply

* Re: [PATCH] mac80211: Allow NO_ACK flag overwrite for injected frames
From: Helmut Schaa @ 2011-09-29 10:02 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, linville
In-Reply-To: <1317290375.3974.1.camel@jlt3.sipsolutions.net>

On Thu, Sep 29, 2011 at 11:59 AM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> On Thu, 2011-09-29 at 11:27 +0200, Helmut Schaa wrote:
>> Allow injected unicast frames to be sent without having to wait
>> for an ACK.
>>
>> Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
>> ---
>>
>> Just in case you're interested in what's the intended purpose of this:
>>
>> Some clients are staying on scanned channels for a very short period of
>> time. hostapd sends out probe responses for each configured BSSID. Under
>> some circumstances I can see that the client already left the channel
>> while some probe responses are still sent out and thus retried. This
>> consumes quite some airtime. Commercial wireless APs (Aruba for example)
>> seem to disable retries for probe responses to mitigate such issues.
>
> Makes sense, but I wonder if we really should continue using
> radiotap :-) Maybe mgmt-tx in nl80211 would be appropriate.

Hmm, not sure how much work that would be ...

>> @@ -1257,7 +1265,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
>>               tx->flags |= IEEE80211_TX_UNICAST;
>>               if (unlikely(local->wifi_wme_noack_test))
>>                       info->flags |= IEEE80211_TX_CTL_NO_ACK;
>> -             else
>> +             else if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
>>                       info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
>
> ??

Don't remove the IEEE80211_TX_CTL_NO_ACK flag when it was set via radiotap.

Helmut

^ permalink raw reply

* Re: [PATCH] mac80211: Allow NO_ACK flag overwrite for injected frames
From: Johannes Berg @ 2011-09-29  9:59 UTC (permalink / raw)
  To: Helmut Schaa; +Cc: linux-wireless, linville
In-Reply-To: <1317288432-26380-1-git-send-email-helmut.schaa@googlemail.com>

On Thu, 2011-09-29 at 11:27 +0200, Helmut Schaa wrote:
> Allow injected unicast frames to be sent without having to wait
> for an ACK.
> 
> Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
> ---
> 
> Just in case you're interested in what's the intended purpose of this:
> 
> Some clients are staying on scanned channels for a very short period of
> time. hostapd sends out probe responses for each configured BSSID. Under
> some circumstances I can see that the client already left the channel
> while some probe responses are still sent out and thus retried. This 
> consumes quite some airtime. Commercial wireless APs (Aruba for example)
> seem to disable retries for probe responses to mitigate such issues.

Makes sense, but I wonder if we really should continue using
radiotap :-) Maybe mgmt-tx in nl80211 would be appropriate.

> @@ -1257,7 +1265,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
>  		tx->flags |= IEEE80211_TX_UNICAST;
>  		if (unlikely(local->wifi_wme_noack_test))
>  			info->flags |= IEEE80211_TX_CTL_NO_ACK;
> -		else
> +		else if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
>  			info->flags &= ~IEEE80211_TX_CTL_NO_ACK;

??

johannes


^ permalink raw reply

* [PATCH] mac80211: Allow NO_ACK flag overwrite for injected frames
From: Helmut Schaa @ 2011-09-29  9:27 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, johannes, Helmut Schaa

Allow injected unicast frames to be sent without having to wait
for an ACK.

Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
---

Just in case you're interested in what's the intended purpose of this:

Some clients are staying on scanned channels for a very short period of
time. hostapd sends out probe responses for each configured BSSID. Under
some circumstances I can see that the client already left the channel
while some probe responses are still sent out and thus retried. This 
consumes quite some airtime. Commercial wireless APs (Aruba for example)
seem to disable retries for probe responses to mitigate such issues.

 include/net/ieee80211_radiotap.h |    1 +
 net/mac80211/tx.c                |   10 +++++++++-
 2 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h
index b0be5fb..7e2c4d4 100644
--- a/include/net/ieee80211_radiotap.h
+++ b/include/net/ieee80211_radiotap.h
@@ -251,6 +251,7 @@ enum ieee80211_radiotap_type {
 						 * retries */
 #define IEEE80211_RADIOTAP_F_TX_CTS	0x0002	/* used cts 'protection' */
 #define IEEE80211_RADIOTAP_F_TX_RTS	0x0004	/* used rts/cts handshake */
+#define IEEE80211_RADIOTAP_F_TX_NOACK	0x0008	/* don't expect an ack */
 
 
 /* For IEEE80211_RADIOTAP_MCS */
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 0107263..8b55465 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1047,6 +1047,7 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
 						   NULL);
+	u16 txflags;
 
 	info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
 	tx->flags &= ~IEEE80211_TX_FRAGMENTED;
@@ -1095,6 +1096,13 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
 				tx->flags |= IEEE80211_TX_FRAGMENTED;
 			break;
 
+		case IEEE80211_RADIOTAP_TX_FLAGS:
+			txflags = le16_to_cpu(get_unaligned((__le16*)
+						iterator.this_arg));
+			if (txflags & IEEE80211_RADIOTAP_F_TX_NOACK)
+				info->flags |= IEEE80211_TX_CTL_NO_ACK;
+			break;
+
 		/*
 		 * Please update the file
 		 * Documentation/networking/mac80211-injection.txt
@@ -1257,7 +1265,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
 		tx->flags |= IEEE80211_TX_UNICAST;
 		if (unlikely(local->wifi_wme_noack_test))
 			info->flags |= IEEE80211_TX_CTL_NO_ACK;
-		else
+		else if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
 			info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
 	}
 
-- 
1.7.3.4


^ permalink raw reply related

* Re: Regulatory revamp status
From: Zefir Kurtisi @ 2011-09-29  8:37 UTC (permalink / raw)
  To: Luis R. Rodriguez
  Cc: linux-wireless, Boris Presman, Assaf Azulay, Michael Green,
	David Quan, Kevin Hayes, Arun Venkataraman
In-Reply-To: <CAB=NE6U6qmYbvHPTWGTqOdXtuxbKYbUzZXNiE6POOX9QZNRWAg@mail.gmail.com>

Thanks for the update.

To me it looks not reasonable to mix in between the two approaches: either we assume countrycodes use the same DFS region for all channels, or each channel/band needs to have its own. Otherwise I feel that a DFS region bitmap would give a semi-flexible compromise that might end up being insufficient to represent some fancy countrycodes.


Zefir

----- Original Message -----
> From: "Luis R. Rodriguez" <rodrigue@qca.qualcomm.com>
> To: "Zefir Kurtisi" <zefir.kurtisi@neratec.com>, "Michael Green" <green@qca.qualcomm.com>, "David Quan"
> <dquan@qca.qualcomm.com>, "Kevin Hayes" <hayes@qca.qualcomm.com>, "Arun Venkataraman" <arunvenk@qca.qualcomm.com>
> Cc: "linux-wireless" <linux-wireless@vger.kernel.org>, "Boris Presman" <boris.presman@ti.com>, "Assaf Azulay"
> <assaf@ti.com>
> Sent: Wednesday, 28 September, 2011 9:52:15 PM
> Subject: Re: Regulatory revamp status
> On Wed, Sep 28, 2011 at 8:45 AM, Zefir Kurtisi
> <zefir.kurtisi@neratec.com> wrote:
> > Hello Luis,
> >
> > I am referring to your announcement for a regulatory revamp at the
> > LinuxWireless
> > summit in Vancouver and the patches to add DFS information to CRDA
> > you
> > proposed quite some time ago in [1].
> >
> > For the integration of DFS that is currently being worked out by TI,
> > we will need to have
> > the DFS regulatory domain for the selected countrycode available --
> > that basically was
> > implemented with the named patch set.
> 
> Yup, there was one pending item on that and it was to determine
> whether or not a country can have different DFS regions for different
> frequency bands. If this is true this also implies that a country can
> have multiple DFS regions. I have found one country in our internal
> regulatory updates which maps Bulgaria to different DFS regions and
> have asked our regulatory folks about this. This seems odd to me and
> I'd prefer to stick to one DFS region entirely for one country, but if
> in the future we forsee DFS regions to be band specific this may
> complicate things and we should address this now. Can you tell me if
> at TI you have no multiple DFS regions for one country ? Do you guys
> have Bulgaria mapping to one DFS region?
> 
> > Could you please give some info on the status of the regulatory
> > revamp and particularly if
> > the proposed DFS information will be part of it?
> 
> You should consider DFS integration into wireless-regdb as independent
> of the regulatory revamp given that we have 16 bits we can use to
> extend wireless-regdb for any future capabilities without having to
> restructure the format of the file to require a different version of
> crda. So DFS can be added as-is today. Updates below on the regulatory
> revamp though and DFS.
> 
> I'm chugging along the regulatory revamp slowly given the questions
> that come up with it require consulting with several different people.
> The latest piece I reviewed was TPC and for that it seems we already
> take into account the 3 dB difference into account into
> wireless-regdb, however this can be further optimized if TPC is
> implemented -- but implementing TPC is device specific in that the TPC
> reports and how you use them can vary depending on the device. When
> you send TPC report requests will also vary. In short I've latest
> determined to stick to what we have today and assume we'll always be
> reducing the 3 dB in power built-in already into the wireless-regdb
> power for each country where needed. This assumes no proper TPC
> implementation. It would still be nice to know when a band requires
> TPC though to enable vendors to implement TPC and reduce power not by
> 3 dB but by whatever metrics they come up with. Given that 3 dB seems
> to be the only required change we likely could stick to that as the
> assumed max value and just require a TPC flag, and if the band has
> this flag allow the driver / stack / etc to add 3 dB more to power if
> it implements TPC. The only problem with this is we'd assume alway a
> static 3 dB. Another possibility is to use a u8 value here to
> represent the deducted tx power, instead of a bit value for a flag.
> 
> Technically speaking we can support both DFS and TPC in the current
> file format for wireless-regdb, we have 16 bits left, we could leave
> u8 for DFS region as a bitmask (left to determine about the multiple
> DFS regions) and u8 for the tx power adaptation for TPC. Thoughts?
> 
> > One detail that came up in the discussion to
> > your patches was whether DFS regulatory domains are constant for a
> > countrycode or might
> > differ between bands. Has this been clarified meanwhile?
> 
> Not yet! I've asked for input a while ago and today as well. What do
> you guys think?
> 
> Luis

^ permalink raw reply

* Re: ath9k: irq storm after suspend/resume
From: Mohammed Shafi @ 2011-09-29  8:18 UTC (permalink / raw)
  To: Clemens Buchacher; +Cc: linux-wireless, beta992
In-Reply-To: <20110927214245.GA1416@ecki>

On Wed, Sep 28, 2011 at 3:12 AM, Clemens Buchacher <drizzd@aon.at> wrote:
> Hello Mohammed,
>
> On Mon, Sep 26, 2011 at 02:54:18PM +0530, Mohammed Shafi wrote:
>>
>> is the issue still seen? any improvement with the attached patch..
>
> I still have the issue. No change with current wl-testing plus your
> patch.

Clemens thanks for taking time  and test it, I wll see if i can find
something else.

>
> Below dmesg output of:
>
>  modprobe ath9k debug=0x0000fffb
>  echo mem >/sys/power/state
>  # resume
>
> Clemens
>
> ---
> [   27.575562] ath9k 0000:02:00.0: PCI INT A -> GSI 17 (level, low) -> IRQ 17
> [   27.577970] ath9k 0000:02:00.0: setting latency timer to 64
> [   27.581405] ath: UNDEFINED -> AWAKE
> [   27.581469] ath: serialize_regmode is 0
> [   27.626195] ath: Eeprom VER: 14, REV: 13
> [   27.626199] ath: Initialize ANI
> [   27.626203] ath: Enable MIB counters
> [   27.626240] ath: Setup TX queue: 9
> [   27.626243] ath: Set queue properties for: 9
> [   27.626248] ath: Setup TX queue: 8
> [   27.626251] ath: Set queue properties for: 8
> [   27.626255] ath: Set queue properties for: 8
> [   27.626259] ath: Reset TX queue: 8
> [   27.626286] ath: tx ok 0x0 err 0x0 desc 0x100 eol 0x100 urn 0x0
> [   27.626290] ath: Setup TX queue: 0
> [   27.626293] ath: Set queue properties for: 0
> [   27.626297] ath: Setup TX queue: 1
> [   27.626300] ath: Set queue properties for: 1
> [   27.626304] ath: Setup TX queue: 2
> [   27.626307] ath: Set queue properties for: 2
> [   27.626310] ath: Setup TX queue: 3
> [   27.626313] ath: Set queue properties for: 3
> [   27.627816] ath: TX streams 1, RX streams: 1
> [   27.627819] ath: EEPROM regdomain: 0x60
> [   27.627822] ath: EEPROM indicates we should expect a direct regpair map
> [   27.627828] ath: Country alpha2 being used: 00
> [   27.627830] ath: Regpair used: 0x60
> [   27.627838] ath: tx DMA: 512 buffers 1 desc/buf
> [   27.627857] ath: tx DMA map: ffff88006f250000 (54600) -> 6f250000 (54600)
> [   27.627891] ath: beacon DMA: 4 buffers 1 desc/buf
> [   27.627897] ath: beacon DMA map: ffff88007198d000 (416) -> 7198d000 (416)
> [   27.627902] ath: cachelsz 64 rxbufsize 1926
> [   27.627906] ath: rx DMA: 512 buffers 1 desc/buf
> [   27.627924] ath: rx DMA map: ffff88006f2b0000 (54600) -> 6f2b0000 (54600)
> [   27.629650] ieee80211 phy1: Selected rate control algorithm 'ath9k_rate_control'
> [   27.630460] Registered led device: ath9k-phy1
> [   27.630475] ieee80211 phy1: Atheros AR9285 Rev:2 mem=0xffffc90021ba0000, irq=17
> [   43.855411] PM: Syncing filesystems ... done.
> [   43.948410] PM: Preparing system for mem sleep
> [   43.949937] Freezing user space processes ... (elapsed 0.01 seconds) done.
> [   43.963254] Freezing remaining freezable tasks ... (elapsed 0.01 seconds) done.
> [   43.976527] PM: Entering mem sleep
> [   43.976595] Suspending console(s) (use no_console_suspend to debug)
> [   43.977193] sd 0:0:0:0: [sda] Synchronizing SCSI cache
> [   43.989161] jmb38x_ms 0000:06:00.3: PCI INT B disabled
> [   43.989194] sdhci-pci 0000:06:00.0: PCI INT B disabled
> [   43.989232] ath: AWAKE -> FULL-SLEEP
> [   43.998370] sd 0:0:0:0: [sda] Stopping disk
> [   44.196369] snd_hda_intel 0000:00:1b.0: PCI INT A disabled
> [   44.608701] PM: suspend of devices complete after 633.019 msecs
> [   44.609142] jme 0000:06:00.5: PME# enabled
> [   44.609152] jme 0000:06:00.5: wake-up capability enabled by ACPI
> [   44.648588] PM: late suspend of devices complete after 39.960 msecs
> [   44.648748] ACPI: Preparing to enter system sleep state S3
> [   44.951903] PM: Saving platform NVS memory
> [   44.952780] Disabling non-boot CPUs ...
> [   44.955081] CPU 1 is now offline
> [   45.057696] CPU 2 is now offline
> [   45.160822] CPU 3 is now offline
> [   45.161227] Extended CMOS year: 2000
> [   45.161461] ACPI: Low-level resume complete
> [   45.161521] PM: Restoring platform NVS memory
> [   45.161951] Extended CMOS year: 2000
> [   45.161974] Enabling non-boot CPUs ...
> [   45.162070] Booting Node 0 Processor 1 APIC 0x4
> [   45.162071] smpboot cpu 1: start_ip = 96000
> [   45.173166] Calibrating delay loop (skipped) already calibrated this CPU
> [   45.193433] NMI watchdog enabled, takes one hw-pmu counter.
> [   45.193554] CPU1 is up
> [   45.193622] Booting Node 0 Processor 2 APIC 0x1
> [   45.193623] smpboot cpu 2: start_ip = 96000
> [   45.194742] Switched to NOHz mode on CPU #1
> [   45.204719] Calibrating delay loop (skipped) already calibrated this CPU
> [   45.225042] NMI watchdog enabled, takes one hw-pmu counter.
> [   45.225176] CPU2 is up
> [   45.225257] Booting Node 0 Processor 3 APIC 0x5
> [   45.225259] smpboot cpu 3: start_ip = 96000
> [   45.228010] Switched to NOHz mode on CPU #2
> [   45.236352] Calibrating delay loop (skipped) already calibrated this CPU
> [   45.256763] NMI watchdog enabled, takes one hw-pmu counter.
> [   45.256925] CPU3 is up
> [   45.258831] Switched to NOHz mode on CPU #3
> [   45.259072] ACPI: Waking up from system sleep state S3
> [   45.580717] intel ips 0000:00:1f.6: MCP limit exceeded: Avg temp 20253, limit 9000
> [   45.658244] i915 0000:00:02.0: restoring config space at offset 0xf (was 0x100, writing 0x10b)
> [   45.658253] i915 0000:00:02.0: restoring config space at offset 0x1 (was 0x900007, writing 0x900407)
> [   45.658277] mei 0000:00:16.0: restoring config space at offset 0xf (was 0x100, writing 0x10b)
> [   45.658296] mei 0000:00:16.0: restoring config space at offset 0x4 (was 0x4, writing 0xd540a004)
> [   45.658304] mei 0000:00:16.0: restoring config space at offset 0x1 (was 0x180000, writing 0x180006)
> [   45.658332] pci 0000:00:1a.0: restoring config space at offset 0xf (was 0x100, writing 0x10b)
> [   45.658350] pci 0000:00:1a.0: restoring config space at offset 0x4 (was 0x0, writing 0xd5408000)
> [   45.658358] pci 0000:00:1a.0: restoring config space at offset 0x1 (was 0x2900000, writing 0x2900006)
> [   45.658391] snd_hda_intel 0000:00:1b.0: restoring config space at offset 0xf (was 0x100, writing 0x105)
> [   45.658410] snd_hda_intel 0000:00:1b.0: restoring config space at offset 0x4 (was 0x4, writing 0xd5400004)
> [   45.658415] snd_hda_intel 0000:00:1b.0: restoring config space at offset 0x3 (was 0x0, writing 0x10)
> [   45.658421] snd_hda_intel 0000:00:1b.0: restoring config space at offset 0x1 (was 0x100004, writing 0x100002)
> [   45.658455] pcieport 0000:00:1c.0: restoring config space at offset 0xf (was 0x100, writing 0x10010b)
> [   45.658467] pcieport 0000:00:1c.0: restoring config space at offset 0x9 (was 0x1fff1, writing 0x7c717c61)
> [   45.658479] pcieport 0000:00:1c.0: restoring config space at offset 0x3 (was 0x810000, writing 0x810010)
> [   45.658485] pcieport 0000:00:1c.0: restoring config space at offset 0x1 (was 0x100000, writing 0x100407)
> [   45.658538] pcieport 0000:00:1c.1: restoring config space at offset 0xf (was 0x200, writing 0x100203)
> [   45.658550] pcieport 0000:00:1c.1: restoring config space at offset 0x9 (was 0x1fff1, writing 0x7c517c41)
> [   45.658561] pcieport 0000:00:1c.1: restoring config space at offset 0x3 (was 0x810000, writing 0x810010)
> [   45.658568] pcieport 0000:00:1c.1: restoring config space at offset 0x1 (was 0x100000, writing 0x100407)
> [   45.658620] pcieport 0000:00:1c.2: restoring config space at offset 0xf (was 0x300, writing 0x100304)
> [   45.658632] pcieport 0000:00:1c.2: restoring config space at offset 0x9 (was 0x1fff1, writing 0x7c317c21)
> [   45.658643] pcieport 0000:00:1c.2: restoring config space at offset 0x3 (was 0x810000, writing 0x810010)
> [   45.658650] pcieport 0000:00:1c.2: restoring config space at offset 0x1 (was 0x100000, writing 0x100407)
> [   45.658703] pcieport 0000:00:1c.5: restoring config space at offset 0xf (was 0x200, writing 0x100203)
> [   45.658714] pcieport 0000:00:1c.5: restoring config space at offset 0x9 (was 0x1fff1, writing 0x7c117c01)
> [   45.658726] pcieport 0000:00:1c.5: restoring config space at offset 0x3 (was 0x810000, writing 0x810010)
> [   45.658732] pcieport 0000:00:1c.5: restoring config space at offset 0x1 (was 0x100000, writing 0x100407)
> [   45.658780] pci 0000:00:1d.0: restoring config space at offset 0xf (was 0x100, writing 0x10a)
> [   45.658799] pci 0000:00:1d.0: restoring config space at offset 0x4 (was 0x0, writing 0xd5407000)
> [   45.658807] pci 0000:00:1d.0: restoring config space at offset 0x1 (was 0x2900000, writing 0x2900006)
> [   45.658831] pci 0000:00:1e.0: restoring config space at offset 0xf (was 0x0, writing 0x100000)
> [   45.658930] ahci 0000:00:1f.2: restoring config space at offset 0x1 (was 0x2b00007, writing 0x2b00407)
> [   45.659017] intel ips 0000:00:1f.6: restoring config space at offset 0x1 (was 0x100400, writing 0x100406)
> [   45.659057] ath9k 0000:02:00.0: restoring config space at offset 0xf (was 0x1ff, writing 0x103)
> [   45.659077] ath9k 0000:02:00.0: restoring config space at offset 0x4 (was 0x4, writing 0xd2c00004)
> [   45.659082] ath9k 0000:02:00.0: restoring config space at offset 0x3 (was 0x0, writing 0x10)
> [   45.659088] ath9k 0000:02:00.0: restoring config space at offset 0x1 (was 0x100000, writing 0x100007)
> [   45.659129] sdhci-pci 0000:06:00.0: restoring config space at offset 0xf (was 0x2ff, writing 0x204)
> [   45.659157] sdhci-pci 0000:06:00.0: restoring config space at offset 0x4 (was 0x0, writing 0xd0407000)
> [   45.659163] sdhci-pci 0000:06:00.0: restoring config space at offset 0x3 (was 0x800000, writing 0x800010)
> [   45.659172] sdhci-pci 0000:06:00.0: restoring config space at offset 0x1 (was 0x100000, writing 0x100007)
> [   45.659218] pci 0000:06:00.2: restoring config space at offset 0xf (was 0x2ff, writing 0x204)
> [   45.659246] pci 0000:06:00.2: restoring config space at offset 0x4 (was 0x0, writing 0xd0406000)
> [   45.659253] pci 0000:06:00.2: restoring config space at offset 0x3 (was 0x800000, writing 0x800010)
> [   45.659262] pci 0000:06:00.2: restoring config space at offset 0x1 (was 0x100000, writing 0x100003)
> [   45.659308] jmb38x_ms 0000:06:00.3: restoring config space at offset 0xf (was 0x2ff, writing 0x204)
> [   45.659336] jmb38x_ms 0000:06:00.3: restoring config space at offset 0x4 (was 0x0, writing 0xd0405000)
> [   45.659342] jmb38x_ms 0000:06:00.3: restoring config space at offset 0x3 (was 0x800000, writing 0x800010)
> [   45.659351] jmb38x_ms 0000:06:00.3: restoring config space at offset 0x1 (was 0x100000, writing 0x100007)
> [   45.659397] pci 0000:06:00.4: restoring config space at offset 0xf (was 0x2ff, writing 0x204)
> [   45.659425] pci 0000:06:00.4: restoring config space at offset 0x4 (was 0x0, writing 0xd0404000)
> [   45.659431] pci 0000:06:00.4: restoring config space at offset 0x3 (was 0x800000, writing 0x800010)
> [   45.659441] pci 0000:06:00.4: restoring config space at offset 0x1 (was 0x100000, writing 0x100007)
> [   45.659487] jme 0000:06:00.5: restoring config space at offset 0xf (was 0x100, writing 0x103)
> [   45.659508] jme 0000:06:00.5: restoring config space at offset 0x7 (was 0x1, writing 0xa001)
> [   45.659520] jme 0000:06:00.5: restoring config space at offset 0x4 (was 0x0, writing 0xd0400000)
> [   45.659526] jme 0000:06:00.5: restoring config space at offset 0x3 (was 0x800000, writing 0x800010)
> [   45.659535] jme 0000:06:00.5: restoring config space at offset 0x1 (was 0x100000, writing 0x100007)
> [   45.659759] PM: early resume of devices complete after 1.603 msecs
> [   45.659979] i915 0000:00:02.0: setting latency timer to 64
> [   45.659996] snd_hda_intel 0000:00:1b.0: PCI INT A -> GSI 22 (level, low) -> IRQ 22
> [   45.660003] snd_hda_intel 0000:00:1b.0: setting latency timer to 64
> [   45.660050] snd_hda_intel 0000:00:1b.0: irq 45 for MSI/MSI-X
> [   45.660126] pci 0000:00:1e.0: setting latency timer to 64
> [   45.660144] ahci 0000:00:1f.2: setting latency timer to 64
> [   45.660211] ath: FULL-SLEEP -> AWAKE
> [   45.663932] sdhci-pci 0000:06:00.0: PCI INT B -> GSI 18 (level, low) -> IRQ 18
> [   45.663974] sdhci-pci 0000:06:00.0: setting latency timer to 64
> [   45.664037] jmb38x_ms 0000:06:00.3: PCI INT B -> GSI 18 (level, low) -> IRQ 18
> [   45.664051] jmb38x_ms 0000:06:00.3: setting latency timer to 64
> [   45.664113] jme 0000:06:00.5: wake-up capability disabled by ACPI
> [   45.664124] jme 0000:06:00.5: PME# disabled
> [   45.664503] ath: disable IER
> [   45.664521] ath: Disable MIB counters
> [   45.664560] ath: disable IER
> [   45.664575] ath: 0x30 => 0x30
> [   45.664576] ath: new IMR 0x30
> [   45.664672] sd 0:0:0:0: [sda] Starting disk
> [   45.667161] ath: Getting spur idx:0 is2Ghz:1 val:8000
> [   45.668810] ath: Reset TX queue: 0
> [   45.668813] ath: tx ok 0x0 err 0x0 desc 0x101 eol 0x101 urn 0x0
> [   45.668815] ath: Reset TX queue: 1
> [   45.668817] ath: tx ok 0x0 err 0x0 desc 0x103 eol 0x103 urn 0x0
> [   45.668819] ath: Reset TX queue: 2
> [   45.668821] ath: tx ok 0x0 err 0x0 desc 0x107 eol 0x107 urn 0x0
> [   45.668823] ath: Reset TX queue: 3
> [   45.668825] ath: tx ok 0x0 err 0x0 desc 0x10f eol 0x10f urn 0x0
> [   45.668827] ath: Reset TXQ, inactive queue: 4
> [   45.668828] ath: Reset TXQ, inactive queue: 5
> [   45.668830] ath: Reset TXQ, inactive queue: 6
> [   45.668831] ath: Reset TXQ, inactive queue: 7
> [   45.668832] ath: Reset TX queue: 8
> [   45.668842] ath: tx ok 0x0 err 0x0 desc 0x10f eol 0x10f urn 0x0
> [   45.668844] ath: Reset TX queue: 9
> [   45.668854] ath: tx ok 0x0 err 0x0 desc 0x10f eol 0x10f urn 0x0
> [   45.668861] ath: ah->misc_mode 0x4
> [   45.670264] ath: Running PA Calibration
> [   45.670963] ath: enabling ADC Gain Calibration.
> [   45.670964] ath: enabling ADC DC Calibration.
> [   45.670965] ath: enabling IQ Calibration.
> [   45.670969] ath: starting ADC Gain Calibration
> [   45.671139] ath: AWAKE -> FULL-SLEEP
> [   45.679552] Extended CMOS year: 2000
> [   45.983193] ata2: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
> [   45.985133] ata2.00: ACPI cmd ef/10:06:00:00:00:a0 (SET FEATURES) succeeded
> [   45.985136] ata2.00: ACPI cmd ef/10:03:00:00:00:a0 (SET FEATURES) filtered out
> [   45.988885] ata2.00: ACPI cmd ef/10:06:00:00:00:a0 (SET FEATURES) succeeded
> [   45.988889] ata2.00: ACPI cmd ef/10:03:00:00:00:a0 (SET FEATURES) filtered out
> [   45.989852] ata6: SATA link down (SStatus 0 SControl 300)
> [   45.990375] ata2.00: configured for UDMA/100
> [   46.120272] irq 17: nobody cared (try booting with the "irqpoll" option)
> [   46.120275] Pid: 0, comm: swapper Tainted: G         C  3.1.0-rc7-wl-ARCH3.1.0-rc7-ath9k-debug #2
> [   46.120277] Call Trace:
> [   46.120280]  <IRQ>  [<ffffffff810c68bd>] __report_bad_irq+0x3d/0xe0
> [   46.120290]  [<ffffffff810c6cfd>] note_interrupt+0x14d/0x210
> [   46.120293]  [<ffffffff810c4c39>] handle_irq_event_percpu+0xc9/0x2a0
> [   46.120296]  [<ffffffff810c4e58>] handle_irq_event+0x48/0x70
> [   46.120299]  [<ffffffff810c763a>] handle_fasteoi_irq+0x5a/0xe0
> [   46.120303]  [<ffffffff81016982>] handle_irq+0x22/0x40
> [   46.120308]  [<ffffffff813ec09a>] do_IRQ+0x5a/0xe0
> [   46.120312]  [<ffffffff813e8cee>] common_interrupt+0x6e/0x6e
> [   46.120313]  <EOI>  [<ffffffff8131234a>] ? poll_idle+0x3a/0x80
> [   46.120319]  [<ffffffff81312323>] ? poll_idle+0x13/0x80
> [   46.120321]  [<ffffffff813126f6>] cpuidle_idle_call+0xc6/0x350
> [   46.120324]  [<ffffffff81013229>] cpu_idle+0xc9/0x120
> [   46.120328]  [<ffffffff813c64e7>] rest_init+0x9b/0xa4
> [   46.120330]  [<ffffffff8174dc15>] start_kernel+0x3bf/0x3cc
> [   46.120333]  [<ffffffff8174d347>] x86_64_start_reservations+0x132/0x136
> [   46.120336]  [<ffffffff8174d140>] ? early_idt_handlers+0x140/0x140
> [   46.120338]  [<ffffffff8174d44d>] x86_64_start_kernel+0x102/0x111
> [   46.120340] handlers:
> [   46.120344] [<ffffffffa053c020>] ath_isr
> [   46.120345] Disabling IRQ #17
> [   48.371839] ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
> [   48.479286] ata1.00: ACPI cmd f5/00:00:00:00:00:a0 (SECURITY FREEZE LOCK) filtered out
> [   48.479457] ata1.00: ACPI cmd ef/10:06:00:00:00:a0 (SET FEATURES) succeeded
> [   48.479463] ata1.00: ACPI cmd ef/10:03:00:00:00:a0 (SET FEATURES) filtered out
> [   48.516626] ata1.00: ACPI cmd f5/00:00:00:00:00:a0 (SECURITY FREEZE LOCK) filtered out
> [   48.516804] ata1.00: ACPI cmd ef/10:06:00:00:00:a0 (SET FEATURES) succeeded
> [   48.516809] ata1.00: ACPI cmd ef/10:03:00:00:00:a0 (SET FEATURES) filtered out
> [   48.518731] ata1.00: configured for UDMA/133
> [   48.526624] ath: FULL-SLEEP -> AWAKE
> [   48.530116] ath: ah->misc_mode 0x4
> [   48.530142] ath: AWAKE -> FULL-SLEEP
> [   48.530172] PM: resume of devices complete after 2875.994 msecs
> [   48.530607] PM: Finishing wakeup.
> [   48.530608] Restarting tasks ... done.
> [   48.533504] video LNXVIDEO:02: Restoring backlight state
>



-- 
shafi

^ permalink raw reply

* Re: [RFC] ath9k_hw: set is_pciexpress true for AR9480
From: mohammed @ 2011-09-29  5:17 UTC (permalink / raw)
  To: Felix Fietkau
  Cc: linux-wireless, John W. Linville, Jouni Malinen, Rodriguez Luis,
	Balasubramanian senthilkumar, Vasanthakumar Thiagarajan,
	Rajkumar Manoharan, Vivek Natarajan, ath9k-devel
In-Reply-To: <4E83AC73.3090502@openwrt.org>

Hi Felix,

On Thursday 29 September 2011 04:53 AM, Felix Fietkau wrote:
> On 2011-09-28 2:07 PM, Mohammed Shafi Shajakhan wrote:
>> From: Mohammed Shafi Shajakhan<mohammed@qca.qualcomm.com>
>>
>> the AR_SREV register does not seems to indicate it properly though the
>> other information like macVersion etc can be obtained properly
> How about using AR_SREV_9300_20_OR_LATER(ah) instead to make sure that
> this works properly for future chips as well?

this seems to be a problem specifically for AR9480 and this problem does 
not seems to be observed in AR9485. but its needed as if is_pciexpress 
is false ASPM won't be initialized

>
> - Felix


^ 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