Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: regression: soft lockup with ath9k on master-2010-04-14
From: Kalle Valo @ 2010-04-19  7:19 UTC (permalink / raw)
  To: Johannes Berg; +Cc: John W. Linville, linux-wireless
In-Reply-To: <1271659397.3873.9.camel@jlt3.sipsolutions.net>

Johannes Berg <johannes@sipsolutions.net> writes:

> However that shouldn't be the problem. Or rather, that could be the
> reason you're seeing the problem on this patch, rather than the 098a
> one.
>
> Try the patch below?

Sorry, no luck. Still my laptop freezes.

-- 
Kalle Valo

^ permalink raw reply

* [PATCH] mac80211: Prevent running sta_cleanup timer unnecessarily
From: Juuso Oikarinen @ 2010-04-19  7:12 UTC (permalink / raw)
  To: linville; +Cc: janne.ylalehto, linux-wireless

The sta_cleanup timer is used to periodically expire buffered frames from the
tx buf. The timer is executing periodically, regardless of the need for it.
This is wasting resources.

Fix this simply by not restarting the sta_cleanup timer if the tx buffer was
empty. Restart the timer when there is some more tx-traffic.

Cc: Janne Ylälehto <janne.ylalehto@nokia.com>
Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
---
 net/mac80211/sta_info.c |   13 ++++++++++---
 net/mac80211/tx.c       |    7 +++++++
 2 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index ff0eb94..3de7a22 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -575,7 +575,7 @@ static int sta_info_buffer_expired(struct sta_info *sta,
 }
 
 
-static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
+static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
 					     struct sta_info *sta)
 {
 	unsigned long flags;
@@ -583,7 +583,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
 	struct ieee80211_sub_if_data *sdata;
 
 	if (skb_queue_empty(&sta->ps_tx_buf))
-		return;
+		return false;
 
 	for (;;) {
 		spin_lock_irqsave(&sta->ps_tx_buf.lock, flags);
@@ -608,6 +608,8 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
 		if (skb_queue_empty(&sta->ps_tx_buf))
 			sta_info_clear_tim_bit(sta);
 	}
+
+	return true;
 }
 
 static int __must_check __sta_info_destroy(struct sta_info *sta)
@@ -755,15 +757,20 @@ static void sta_info_cleanup(unsigned long data)
 {
 	struct ieee80211_local *local = (struct ieee80211_local *) data;
 	struct sta_info *sta;
+	bool timer_needed = false;
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(sta, &local->sta_list, list)
-		sta_info_cleanup_expire_buffered(local, sta);
+		if (sta_info_cleanup_expire_buffered(local, sta))
+			timer_needed = true;
 	rcu_read_unlock();
 
 	if (local->quiescing)
 		return;
 
+	if (!timer_needed)
+		return;
+
 	local->sta_cleanup.expires =
 		round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
 	add_timer(&local->sta_cleanup);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 2cb7726..e2aa972 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -429,6 +429,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
 	struct sta_info *sta = tx->sta;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
+	struct ieee80211_local *local = tx->local;
 	u32 staflags;
 
 	if (unlikely(!sta ||
@@ -476,6 +477,12 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
 		info->control.vif = &tx->sdata->vif;
 		info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
 		skb_queue_tail(&sta->ps_tx_buf, tx->skb);
+
+		if (!timer_pending(&local->sta_cleanup))
+			mod_timer(&local->sta_cleanup,
+				  round_jiffies(jiffies +
+						STA_INFO_CLEANUP_INTERVAL));
+
 		return TX_QUEUED;
 	}
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 3/3] orinoco: have sparse check endian issues
From: David Kilroy @ 2010-04-19  7:16 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, David Kilroy
In-Reply-To: <1271661383-27839-1-git-send-email-kilroyd@googlemail.com>

Orinoco should be endian clean, so enable the checking.

Signed-off-by: David Kilroy <kilroyd@googlemail.com>
---
 drivers/net/wireless/orinoco/Makefile |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/orinoco/Makefile b/drivers/net/wireless/orinoco/Makefile
index 9abd632..e645269 100644
--- a/drivers/net/wireless/orinoco/Makefile
+++ b/drivers/net/wireless/orinoco/Makefile
@@ -11,3 +11,6 @@ obj-$(CONFIG_PCI_HERMES)	+= orinoco_pci.o
 obj-$(CONFIG_TMD_HERMES)	+= orinoco_tmd.o
 obj-$(CONFIG_NORTEL_HERMES)	+= orinoco_nortel.o
 obj-$(CONFIG_PCMCIA_SPECTRUM)	+= spectrum_cs.o
+
+# Orinoco should be endian clean.
+ccflags-y += -D__CHECK_ENDIAN__
-- 
1.6.4.4


^ permalink raw reply related

* [PATCH 2/3] orinoco: use cfg80211_find_ie
From: David Kilroy @ 2010-04-19  7:16 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, David Kilroy
In-Reply-To: <1271661383-27839-1-git-send-email-kilroyd@googlemail.com>

Instead of using a local function.

Signed-off-by: David Kilroy <kilroyd@googlemail.com>
---
 drivers/net/wireless/orinoco/main.h |   12 ------------
 drivers/net/wireless/orinoco/scan.c |    4 ++--
 2 files changed, 2 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/orinoco/main.h b/drivers/net/wireless/orinoco/main.h
index 21ab36c..4dadf98 100644
--- a/drivers/net/wireless/orinoco/main.h
+++ b/drivers/net/wireless/orinoco/main.h
@@ -33,18 +33,6 @@ int orinoco_commit(struct orinoco_private *priv);
 void orinoco_reset(struct work_struct *work);
 
 /* Information element helpers - find a home for these... */
-static inline u8 *orinoco_get_ie(u8 *data, size_t len,
-				 enum ieee80211_eid eid)
-{
-	u8 *p = data;
-	while ((p + 2) < (data + len)) {
-		if (p[0] == eid)
-			return p;
-		p += p[1] + 2;
-	}
-	return NULL;
-}
-
 #define WPA_OUI_TYPE	"\x00\x50\xF2\x01"
 #define WPA_SELECTOR_LEN 4
 static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len)
diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c
index 330d42d..4300d9d 100644
--- a/drivers/net/wireless/orinoco/scan.c
+++ b/drivers/net/wireless/orinoco/scan.c
@@ -127,7 +127,7 @@ void orinoco_add_extscan_result(struct orinoco_private *priv,
 {
 	struct wiphy *wiphy = priv_to_wiphy(priv);
 	struct ieee80211_channel *channel;
-	u8 *ie;
+	const u8 *ie;
 	u64 timestamp;
 	s32 signal;
 	u16 capability;
@@ -136,7 +136,7 @@ void orinoco_add_extscan_result(struct orinoco_private *priv,
 	int chan, freq;
 
 	ie_len = len - sizeof(*bss);
-	ie = orinoco_get_ie(bss->data, ie_len, WLAN_EID_DS_PARAMS);
+	ie = cfg80211_find_ie(WLAN_EID_DS_PARAMS, bss->data, ie_len);
 	chan = ie ? ie[2] : 0;
 	freq = ieee80211_dsss_chan_to_freq(chan);
 	channel = ieee80211_get_channel(wiphy, freq);
-- 
1.6.4.4


^ permalink raw reply related

* [PATCH 1/3] orinoco: implement set_wiphy_params
From: David Kilroy @ 2010-04-19  7:16 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, David Kilroy

... to set fragmentation and RTS thresholds. Also report RTS retry
settings during wiphy init.

Note that the existing semantics for enabling microwave robustness are
preserved on firmwares that have it.

Signed-off-by: David Kilroy <kilroyd@googlemail.com>
---
 drivers/net/wireless/orinoco/cfg.c     |   88 +++++++++++++++-
 drivers/net/wireless/orinoco/hw.c      |   26 +++++
 drivers/net/wireless/orinoco/orinoco.h |    2 +
 drivers/net/wireless/orinoco/wext.c    |  183 +-------------------------------
 4 files changed, 120 insertions(+), 179 deletions(-)

diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c
index 27f2d33..90dd4d0 100644
--- a/drivers/net/wireless/orinoco/cfg.c
+++ b/drivers/net/wireless/orinoco/cfg.c
@@ -88,7 +88,9 @@ int orinoco_wiphy_register(struct wiphy *wiphy)
 
 	wiphy->rts_threshold = priv->rts_thresh;
 	if (!priv->has_mwo)
-		wiphy->frag_threshold = priv->frag_thresh;
+		wiphy->frag_threshold = priv->frag_thresh + 1;
+	wiphy->retry_short = priv->short_retry_limit;
+	wiphy->retry_long = priv->long_retry_limit;
 
 	return wiphy_register(wiphy);
 }
@@ -196,8 +198,92 @@ static int orinoco_set_channel(struct wiphy *wiphy,
 	return err;
 }
 
+static int orinoco_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+	struct orinoco_private *priv = wiphy_priv(wiphy);
+	int frag_value = -1;
+	int rts_value = -1;
+	int err = 0;
+
+	if (changed & WIPHY_PARAM_RETRY_SHORT) {
+		/* Setting short retry not supported */
+		err = -EINVAL;
+	}
+
+	if (changed & WIPHY_PARAM_RETRY_LONG) {
+		/* Setting long retry not supported */
+		err = -EINVAL;
+	}
+
+	if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
+		/* Set fragmentation */
+		if (priv->has_mwo) {
+			if (wiphy->frag_threshold < 0)
+				frag_value = 0;
+			else {
+				printk(KERN_WARNING "%s: Fixed fragmentation "
+				       "is not supported on this firmware. "
+				       "Using MWO robust instead.\n",
+				       priv->ndev->name);
+				frag_value = 1;
+			}
+		} else {
+			if (wiphy->frag_threshold < 0)
+				frag_value = 2346;
+			else if ((wiphy->frag_threshold < 257) ||
+				 (wiphy->frag_threshold > 2347))
+				err = -EINVAL;
+			else
+				/* cfg80211 value is 257-2347 (odd only)
+				 * orinoco rid has range 256-2346 (even only) */
+				frag_value = wiphy->frag_threshold & ~0x1;
+		}
+	}
+
+	if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
+		/* Set RTS.
+		 *
+		 * Prism documentation suggests default of 2432,
+		 * and a range of 0-3000.
+		 *
+		 * Current implementation uses 2347 as the default and
+		 * the upper limit.
+		 */
+
+		if (wiphy->rts_threshold < 0)
+			rts_value = 2347;
+		else if (wiphy->rts_threshold > 2347)
+			err = -EINVAL;
+		else
+			rts_value = wiphy->rts_threshold;
+	}
+
+	if (!err) {
+		unsigned long flags;
+
+		if (orinoco_lock(priv, &flags) != 0)
+			return -EBUSY;
+
+		if (frag_value >= 0) {
+			if (priv->has_mwo)
+				priv->mwo_robust = frag_value;
+			else
+				priv->frag_thresh = frag_value;
+		}
+		if (rts_value >= 0)
+			priv->rts_thresh = rts_value;
+
+		err = orinoco_commit(priv);
+
+		orinoco_unlock(priv, &flags);
+	}
+
+	return err;
+}
+
 const struct cfg80211_ops orinoco_cfg_ops = {
 	.change_virtual_intf = orinoco_change_vif,
 	.set_channel = orinoco_set_channel,
 	.scan = orinoco_scan,
+	.set_wiphy_params = orinoco_set_wiphy_params,
 };
diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c
index 883b8f8..24ea4b4 100644
--- a/drivers/net/wireless/orinoco/hw.c
+++ b/drivers/net/wireless/orinoco/hw.c
@@ -374,6 +374,32 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
 		err = hermes_read_wordrec(hw, USER_BAP,
 					  HERMES_RID_CNFPREAMBLE_SYMBOL,
 					  &priv->preamble);
+		if (err) {
+			dev_err(dev, "Failed to read preamble setup\n");
+			goto out;
+		}
+	}
+
+	/* Retry settings */
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT,
+				  &priv->short_retry_limit);
+	if (err) {
+		dev_err(dev, "Failed to read short retry limit\n");
+		goto out;
+	}
+
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT,
+				  &priv->long_retry_limit);
+	if (err) {
+		dev_err(dev, "Failed to read long retry limit\n");
+		goto out;
+	}
+
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME,
+				  &priv->retry_lifetime);
+	if (err) {
+		dev_err(dev, "Failed to read max retry lifetime\n");
+		goto out;
 	}
 
 out:
diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h
index 665ef56..ff6b7b1 100644
--- a/drivers/net/wireless/orinoco/orinoco.h
+++ b/drivers/net/wireless/orinoco/orinoco.h
@@ -131,6 +131,8 @@ struct orinoco_private {
 	u16 ap_density, rts_thresh;
 	u16 pm_on, pm_mcast, pm_period, pm_timeout;
 	u16 preamble;
+	u16 short_retry_limit, long_retry_limit;
+	u16 retry_lifetime;
 #ifdef WIRELESS_SPY
 	struct iw_spy_data spy_data; /* iwspy support */
 	struct iw_public_data	wireless_data;
diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c
index 57b850e..a1006bf 100644
--- a/drivers/net/wireless/orinoco/wext.c
+++ b/drivers/net/wireless/orinoco/wext.c
@@ -538,125 +538,6 @@ static int orinoco_ioctl_setsens(struct net_device *dev,
 	return -EINPROGRESS;		/* Call commit handler */
 }
 
-static int orinoco_ioctl_setrts(struct net_device *dev,
-				struct iw_request_info *info,
-				struct iw_param *rrq,
-				char *extra)
-{
-	struct orinoco_private *priv = ndev_priv(dev);
-	int val = rrq->value;
-	unsigned long flags;
-
-	if (rrq->disabled)
-		val = 2347;
-
-	if ((val < 0) || (val > 2347))
-		return -EINVAL;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	priv->rts_thresh = val;
-	orinoco_unlock(priv, &flags);
-
-	return -EINPROGRESS;		/* Call commit handler */
-}
-
-static int orinoco_ioctl_getrts(struct net_device *dev,
-				struct iw_request_info *info,
-				struct iw_param *rrq,
-				char *extra)
-{
-	struct orinoco_private *priv = ndev_priv(dev);
-
-	rrq->value = priv->rts_thresh;
-	rrq->disabled = (rrq->value == 2347);
-	rrq->fixed = 1;
-
-	return 0;
-}
-
-static int orinoco_ioctl_setfrag(struct net_device *dev,
-				 struct iw_request_info *info,
-				 struct iw_param *frq,
-				 char *extra)
-{
-	struct orinoco_private *priv = ndev_priv(dev);
-	int err = -EINPROGRESS;		/* Call commit handler */
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	if (priv->has_mwo) {
-		if (frq->disabled)
-			priv->mwo_robust = 0;
-		else {
-			if (frq->fixed)
-				printk(KERN_WARNING "%s: Fixed fragmentation "
-				       "is not supported on this firmware. "
-				       "Using MWO robust instead.\n",
-				       dev->name);
-			priv->mwo_robust = 1;
-		}
-	} else {
-		if (frq->disabled)
-			priv->frag_thresh = 2346;
-		else {
-			if ((frq->value < 256) || (frq->value > 2346))
-				err = -EINVAL;
-			else
-				/* must be even */
-				priv->frag_thresh = frq->value & ~0x1;
-		}
-	}
-
-	orinoco_unlock(priv, &flags);
-
-	return err;
-}
-
-static int orinoco_ioctl_getfrag(struct net_device *dev,
-				 struct iw_request_info *info,
-				 struct iw_param *frq,
-				 char *extra)
-{
-	struct orinoco_private *priv = ndev_priv(dev);
-	hermes_t *hw = &priv->hw;
-	int err;
-	u16 val;
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	if (priv->has_mwo) {
-		err = hermes_read_wordrec(hw, USER_BAP,
-					  HERMES_RID_CNFMWOROBUST_AGERE,
-					  &val);
-		if (err)
-			val = 0;
-
-		frq->value = val ? 2347 : 0;
-		frq->disabled = !val;
-		frq->fixed = 0;
-	} else {
-		err = hermes_read_wordrec(hw, USER_BAP,
-					  HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
-					  &val);
-		if (err)
-			val = 0;
-
-		frq->value = val;
-		frq->disabled = (val >= 2346);
-		frq->fixed = 1;
-	}
-
-	orinoco_unlock(priv, &flags);
-
-	return err;
-}
-
 static int orinoco_ioctl_setrate(struct net_device *dev,
 				 struct iw_request_info *info,
 				 struct iw_param *rrq,
@@ -1201,60 +1082,6 @@ static int orinoco_ioctl_set_mlme(struct net_device *dev,
 	return ret;
 }
 
-static int orinoco_ioctl_getretry(struct net_device *dev,
-				  struct iw_request_info *info,
-				  struct iw_param *rrq,
-				  char *extra)
-{
-	struct orinoco_private *priv = ndev_priv(dev);
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	u16 short_limit, long_limit, lifetime;
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT,
-				  &short_limit);
-	if (err)
-		goto out;
-
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT,
-				  &long_limit);
-	if (err)
-		goto out;
-
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME,
-				  &lifetime);
-	if (err)
-		goto out;
-
-	rrq->disabled = 0;		/* Can't be disabled */
-
-	/* Note : by default, display the retry number */
-	if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
-		rrq->flags = IW_RETRY_LIFETIME;
-		rrq->value = lifetime * 1000;	/* ??? */
-	} else {
-		/* By default, display the min number */
-		if ((rrq->flags & IW_RETRY_LONG)) {
-			rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
-			rrq->value = long_limit;
-		} else {
-			rrq->flags = IW_RETRY_LIMIT;
-			rrq->value = short_limit;
-			if (short_limit != long_limit)
-				rrq->flags |= IW_RETRY_SHORT;
-		}
-	}
-
- out:
-	orinoco_unlock(priv, &flags);
-
-	return err;
-}
-
 static int orinoco_ioctl_reset(struct net_device *dev,
 			       struct iw_request_info *info,
 			       void *wrqu,
@@ -1528,11 +1355,11 @@ static const iw_handler	orinoco_handler[] = {
 	IW_HANDLER(SIOCGIWESSID,	(iw_handler)orinoco_ioctl_getessid),
 	IW_HANDLER(SIOCSIWRATE,		(iw_handler)orinoco_ioctl_setrate),
 	IW_HANDLER(SIOCGIWRATE,		(iw_handler)orinoco_ioctl_getrate),
-	IW_HANDLER(SIOCSIWRTS,		(iw_handler)orinoco_ioctl_setrts),
-	IW_HANDLER(SIOCGIWRTS,		(iw_handler)orinoco_ioctl_getrts),
-	IW_HANDLER(SIOCSIWFRAG,		(iw_handler)orinoco_ioctl_setfrag),
-	IW_HANDLER(SIOCGIWFRAG,		(iw_handler)orinoco_ioctl_getfrag),
-	IW_HANDLER(SIOCGIWRETRY,	(iw_handler)orinoco_ioctl_getretry),
+	IW_HANDLER(SIOCSIWRTS,		(iw_handler)cfg80211_wext_siwrts),
+	IW_HANDLER(SIOCGIWRTS,		(iw_handler)cfg80211_wext_giwrts),
+	IW_HANDLER(SIOCSIWFRAG,		(iw_handler)cfg80211_wext_siwfrag),
+	IW_HANDLER(SIOCGIWFRAG,		(iw_handler)cfg80211_wext_giwfrag),
+	IW_HANDLER(SIOCGIWRETRY,	(iw_handler)cfg80211_wext_giwretry),
 	IW_HANDLER(SIOCSIWENCODE,	(iw_handler)orinoco_ioctl_setiwencode),
 	IW_HANDLER(SIOCGIWENCODE,	(iw_handler)orinoco_ioctl_getiwencode),
 	IW_HANDLER(SIOCSIWPOWER,	(iw_handler)orinoco_ioctl_setpower),
-- 
1.6.4.4


^ permalink raw reply related

* Re: regression: soft lockup with ath9k on master-2010-04-14
From: Johannes Berg @ 2010-04-19  6:43 UTC (permalink / raw)
  To: Kalle Valo; +Cc: John W. Linville, linux-wireless
In-Reply-To: <871veclztk.fsf@purkki.valot.fi>

On Mon, 2010-04-19 at 09:29 +0300, Kalle Valo wrote:

> > It might be useful to do a bisect.  If you choose to do that, you
> > might want to use wireless-next-2.6 instead, since that doesn't have
> > the occasional pulls from Linus that make bisecting wireless-testing
> > more painful.
> 
> Thanks for the tip, it helped a lot. My new laptop is really slow to
> compile kernels :/
> 
> I bisected it finally and found the culprit:
> 
> 66b0470aeef10a3b0f9a6a1c60d908b5a06c62ae is the first bad commit
> commit 66b0470aeef10a3b0f9a6a1c60d908b5a06c62ae
> Author: Johannes Berg <johannes@sipsolutions.net>
> Date:   Tue Apr 6 11:18:45 2010 +0200
> 
>     mac80211: remove ieee80211_sta_stop_rx_ba_session

[...]

> I took a quick peek of the patches but I wasn't able to immediately
> say what was wrong. This just made me suspicious:
> 
> -       ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
> -                                        (u16)*ptid, WLAN_BACK_TIMER,
> -                                        WLAN_REASON_QSTA_TIMEOUT);
> +       __ieee80211_stop_rx_ba_session(sta, *ptid,
> -                                        WLAN_BACK_RECIPIENT,
> +                                      WLAN_REASON_QSTA_TIMEOUT);
> 
> WLAN_BACK_TIMER was changed to WLAN_BACK_RECIPIENT, but I don't know
> if it was in purpose or not. Johannes, any ideas?

That was on purpose but belongs into
098a607091426e79178b9a6c318d993fea131791 not this patch ... :(

However that shouldn't be the problem. Or rather, that could be the
reason you're seeing the problem on this patch, rather than the 098a
one.

Try the patch below?

johannes

--- wireless-testing.orig/net/mac80211/agg-rx.c	2010-04-19 08:40:17.000000000 +0200
+++ wireless-testing/net/mac80211/agg-rx.c	2010-04-19 08:40:27.000000000 +0200
@@ -47,11 +47,6 @@ void __ieee80211_stop_rx_ba_session(stru
 		printk(KERN_DEBUG "HW problem - can not stop rx "
 				"aggregation for tid %d\n", tid);
 
-	/* check if this is a self generated aggregation halt */
-	if (initiator == WLAN_BACK_RECIPIENT)
-		ieee80211_send_delba(sta->sdata, sta->sta.addr,
-				     tid, 0, reason);
-
 	/* free the reordering buffer */
 	for (i = 0; i < tid_rx->buf_size; i++) {
 		if (tid_rx->reorder_buf[i]) {
@@ -69,6 +64,11 @@ void __ieee80211_stop_rx_ba_session(stru
 
 	spin_unlock_bh(&sta->lock);
 
+	/* check if this is a self generated aggregation halt */
+	if (initiator == WLAN_BACK_RECIPIENT)
+		ieee80211_send_delba(sta->sdata, sta->sta.addr,
+				     tid, 0, reason);
+
 	del_timer_sync(&tid_rx->session_timer);
 	kfree(tid_rx);
 }



^ permalink raw reply

* Re: regression: soft lockup with ath9k on master-2010-04-14
From: Kalle Valo @ 2010-04-19  6:29 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless, johannes
In-Reply-To: <20100415195812.GC3020@tuxdriver.com>

"John W. Linville" <linville@tuxdriver.com> writes:

> On Thu, Apr 15, 2010 at 10:44:52PM +0300, Kalle Valo wrote:
>> Hello,
>> 
>> I just updated my laptop to latest wireless-testing and it everytime
>> soft lockups few seconds after association.
>> 
>> I haven't updated wireless-testing for few days, so I can't say when
>> this bug was introduced.
>
> It might be useful to do a bisect.  If you choose to do that, you
> might want to use wireless-next-2.6 instead, since that doesn't have
> the occasional pulls from Linus that make bisecting wireless-testing
> more painful.

Thanks for the tip, it helped a lot. My new laptop is really slow to
compile kernels :/

I bisected it finally and found the culprit:

66b0470aeef10a3b0f9a6a1c60d908b5a06c62ae is the first bad commit
commit 66b0470aeef10a3b0f9a6a1c60d908b5a06c62ae
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Tue Apr 6 11:18:45 2010 +0200

    mac80211: remove ieee80211_sta_stop_rx_ba_session
    
    All callers of ieee80211_sta_stop_rx_ba_session can
    just call __ieee80211_stop_rx_ba_session instead
    because they already have the station struct, so do
    that and remove ieee80211_sta_stop_rx_ba_session.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

I verified that reverting these three patches make my laptop stable
again:

54297e4d60b74e602138594c131097347d128b5a mac80211: fix some RX aggregation...
098a607091426e79178b9a6c318d993fea131791 mac80211: clean up/fix aggregation..
66b0470aeef10a3b0f9a6a1c60d908b5a06c62ae mac80211: remove ieee80211_sta_...

(I had to revert all three because of conflicts.)

I took a quick peek of the patches but I wasn't able to immediately
say what was wrong. This just made me suspicious:

-       ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
-                                        (u16)*ptid, WLAN_BACK_TIMER,
-                                        WLAN_REASON_QSTA_TIMEOUT);
+       __ieee80211_stop_rx_ba_session(sta, *ptid,
-                                        WLAN_BACK_RECIPIENT,
+                                      WLAN_REASON_QSTA_TIMEOUT);

WLAN_BACK_TIMER was changed to WLAN_BACK_RECIPIENT, but I don't know
if it was in purpose or not. Johannes, any ideas?

-- 
Kalle Valo

^ permalink raw reply

* Re: [PATCH 7/9] mac80211: add flags for STBC (Space-Time Block Coding)
From: Johannes Berg @ 2010-04-19  5:57 UTC (permalink / raw)
  To: Felix Fietkau; +Cc: linux-wireless, linville, lrodriguez
In-Reply-To: <4BCB2DB3.3020700@openwrt.org>

On Sun, 2010-04-18 at 18:05 +0200, Felix Fietkau wrote:

> >> + * @IEEE80211_TX_CTL_STBC: tells the driver to use Space-Time Block Coding
> >> + *  (STBC) for this frame.
> >>   */
> >>  enum mac80211_tx_control_flags {
> >>  	IEEE80211_TX_CTL_REQ_TX_STATUS		= BIT(0),
> >> @@ -299,6 +301,7 @@ enum mac80211_tx_control_flags {
> >>  	IEEE80211_TX_INTFL_HAS_RADIOTAP		= BIT(20),
> >>  	IEEE80211_TX_INTFL_NL80211_FRAME_TX	= BIT(21),
> >>  	IEEE80211_TX_CTL_LDPC			= BIT(22),
> >> +	IEEE80211_TX_CTL_STBC			= BIT(23),
> > 
> > What if the # of streams is different? That doesn't look sufficient.

> Hm, you're right. I initially thought the combination of the MCS index
> and the STBC flag would be enough, but there are still some corner cases.

Hm actually I guess that should be sufficient? What corner case are you
thinking of?

johannes


^ permalink raw reply

* Re: [RFC PATCH] mac80211: Prevent running sta_cleanup timer unnecessarily
From: Johannes Berg @ 2010-04-19  5:57 UTC (permalink / raw)
  To: Juuso Oikarinen; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <1271652964.6205.4211.camel@wimaxnb.nmp.nokia.com>

On Mon, 2010-04-19 at 07:56 +0300, Juuso Oikarinen wrote:

> > > --- a/net/mac80211/tx.c
> > > +++ b/net/mac80211/tx.c
> > > @@ -429,6 +429,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
> > >  	struct sta_info *sta = tx->sta;
> > >  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
> > >  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
> > > +	struct ieee80211_local *local = tx->local;
> > >  	u32 staflags;
> > >  
> > >  	if (unlikely(!sta ||
> > > @@ -476,6 +477,12 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
> > >  		info->control.vif = &tx->sdata->vif;
> > >  		info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
> > >  		skb_queue_tail(&sta->ps_tx_buf, tx->skb);
> > > +
> > > +		if (!timer_pending(&local->sta_cleanup))
> > > +			mod_timer(&local->sta_cleanup,
> > > +				  round_jiffies(jiffies +
> > > +						STA_INFO_CLEANUP_INTERVAL));
> > > +
> > 
> > Why bother to check !timer_pending?
> > 
> 
> Otherwise, if we have some periodic TX going on with an interval less
> than STA_INFO_CLEANUP_INTERVAL, the sta_cleanup could be delayed
> considerably.

Ok, makes sense, I didn't check the context there.

johannes


^ permalink raw reply

* Re: [RFC PATCH] mac80211: Prevent running sta_cleanup timer unnecessarily
From: Juuso Oikarinen @ 2010-04-19  4:56 UTC (permalink / raw)
  To: ext Johannes Berg; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <1271449060.4184.1.camel@jlt3.sipsolutions.net>

On Fri, 2010-04-16 at 22:17 +0200, ext Johannes Berg wrote:
> On Fri, 2010-04-16 at 10:35 +0300, Juuso Oikarinen wrote:
> > The sta_cleanup timer is used to periodically expire buffered frames from the
> > tx buf. The timer is executing periodically, regardless of the need for it.
> > This is wasting resources.
> > 
> > Fix this simply by not restarting the sta_cleanup timer if the tx buffer was
> > empty. Restart the timer when there is some more tx-traffic.
> > 
> > Cc: Janne Ylälehto <janne.ylalehto@nokia.com>
> > Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
> > ---
> >  net/mac80211/sta_info.c |   13 ++++++++++---
> >  net/mac80211/tx.c       |    7 +++++++
> >  2 files changed, 17 insertions(+), 3 deletions(-)
> > 
> > diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
> > index ff0eb94..3de7a22 100644
> > --- a/net/mac80211/sta_info.c
> > +++ b/net/mac80211/sta_info.c
> > @@ -575,7 +575,7 @@ static int sta_info_buffer_expired(struct sta_info *sta,
> >  }
> >  
> > 
> > -static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
> > +static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
> >  					     struct sta_info *sta)
> >  {
> >  	unsigned long flags;
> > @@ -583,7 +583,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
> >  	struct ieee80211_sub_if_data *sdata;
> >  
> >  	if (skb_queue_empty(&sta->ps_tx_buf))
> > -		return;
> > +		return false;
> >  
> >  	for (;;) {
> >  		spin_lock_irqsave(&sta->ps_tx_buf.lock, flags);
> > @@ -608,6 +608,8 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
> >  		if (skb_queue_empty(&sta->ps_tx_buf))
> >  			sta_info_clear_tim_bit(sta);
> >  	}
> > +
> > +	return true;
> >  }
> >  
> >  static int __must_check __sta_info_destroy(struct sta_info *sta)
> > @@ -755,15 +757,20 @@ static void sta_info_cleanup(unsigned long data)
> >  {
> >  	struct ieee80211_local *local = (struct ieee80211_local *) data;
> >  	struct sta_info *sta;
> > +	bool timer_needed = false;
> >  
> >  	rcu_read_lock();
> >  	list_for_each_entry_rcu(sta, &local->sta_list, list)
> > -		sta_info_cleanup_expire_buffered(local, sta);
> > +		if (sta_info_cleanup_expire_buffered(local, sta))
> > +			timer_needed = true;
> >  	rcu_read_unlock();
> >  
> >  	if (local->quiescing)
> >  		return;
> >  
> > +	if (!timer_needed)
> > +		return;
> > +
> >  	local->sta_cleanup.expires =
> >  		round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
> >  	add_timer(&local->sta_cleanup);
> > diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
> > index 2cb7726..e2aa972 100644
> > --- a/net/mac80211/tx.c
> > +++ b/net/mac80211/tx.c
> > @@ -429,6 +429,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
> >  	struct sta_info *sta = tx->sta;
> >  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
> >  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
> > +	struct ieee80211_local *local = tx->local;
> >  	u32 staflags;
> >  
> >  	if (unlikely(!sta ||
> > @@ -476,6 +477,12 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
> >  		info->control.vif = &tx->sdata->vif;
> >  		info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
> >  		skb_queue_tail(&sta->ps_tx_buf, tx->skb);
> > +
> > +		if (!timer_pending(&local->sta_cleanup))
> > +			mod_timer(&local->sta_cleanup,
> > +				  round_jiffies(jiffies +
> > +						STA_INFO_CLEANUP_INTERVAL));
> > +
> 
> Why bother to check !timer_pending?
> 

Otherwise, if we have some periodic TX going on with an interval less
than STA_INFO_CLEANUP_INTERVAL, the sta_cleanup could be delayed
considerably.

-Juuso

> johannes
> 



^ permalink raw reply

* Re: [PATCH 1/2] ath5k: Use high bitrates for ACK/CTS
From: Bruno Randolf @ 2010-04-19  0:24 UTC (permalink / raw)
  To: Stanislaw Gruszka; +Cc: linville, ath5k-devel, linux-wireless
In-Reply-To: <20100416155907.6e33c722@dhcp-lab-109.englab.brq.redhat.com>

On Friday 16 April 2010 22:59:07 Stanislaw Gruszka wrote:
> On Mon, 12 Apr 2010 16:38:47 +0900
> 
> Bruno Randolf <br1@einfach.org> wrote:
> > There was a confusion in the usage of the bits AR5K_STA_ID1_ACKCTS_6MB
> > and AR5K_STA_ID1_BASE_RATE_11B. If they are set (1), we will get lower
> > bitrates for ACK and CTS. Therefore ath5k_hw_set_ack_bitrate_high(ah,
> > false) actually resulted in high bitrates, which i think is what we want
> > anyways. Cleared the confusion and added some documentation.
> 
> I thought ACK and other control frames have to be modulated at slow/robust
> bitrates, but can't remember where I read that ...

this has been discussed on ath5k-devel before. i'm copying it here. please let 
me know if i missed something...

(https://lists.ath5k.org/pipermail/ath5k-devel/2010-March/003391.html)

control frames have to be sent at one of the lower bitrates - one of the 
"basic rates". in G mode these are 1, 2, 5.5, 11, 6, 12, 24Mbps. 

this is from the 802.11g spec:
"a STA responding to a received frame shall transmit its Control Response
(either CTS or ACK) frames at the highest rate in the BSSBasicRateSet that is 
less than or equal to the rate of the immediately previous frame in the frame 
exchange sequence (as defined in 9.7)"

basically we have to make a tradeoff here: using lower rates for ACK/CTS will 
improve reliability, but lower performance. for example i could get only 
10Mbps truput with ACK/CTS at the lowest bitrates and RTS/CTS enabled 
(iwconfig wlan0 rts 250) and i can get more than 20Mbps with higher bitrates. 
so i think it's worth to use high bitrates. actually also this should be 
tuneable for the user, too...

bruno

^ permalink raw reply

* Re: 3dsp shared a USB Wifi Dongle Source Code
From: Gábor Stefanik @ 2010-04-18 18:35 UTC (permalink / raw)
  To: João Neto; +Cc: linux-wireless
In-Reply-To: <m2y58f5e62a1004181102gd58a214at3419e7a4b96c099c@mail.gmail.com>

There is no license provided in the file. In addition, files in the
driver_src/wlan directory explicitly forbid any form of distribution
or modification, in source, binary, or any other form. Even quoting
comments, and thus the license block in the files, is forbidden!

On Sun, Apr 18, 2010 at 8:02 PM, João Neto <joao.gsneto@gmail.com> wrote:
> Hello
>
> Recently 3dsp has shared the source code of your Wifi and Bluetooth USB card:
>
>
> ftp://3dsp_lpkt_usb:m4rt9s@3dsp.com.cn/
>
> in the folder "Open Source"
>
> --
> Joao Neto - Web Developer | PHP Zend Certified Engineer
> @joao_neto | http://www.joaoneto.blog.br
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>



-- 
Vista: [V]iruses, [I]ntruders, [S]pyware, [T]rojans and [A]dware. :-)

^ permalink raw reply

* 3dsp shared a USB Wifi Dongle Source Code
From: João Neto @ 2010-04-18 18:02 UTC (permalink / raw)
  To: linux-wireless

Hello

Recently 3dsp has shared the source code of your Wifi and Bluetooth USB card:


ftp://3dsp_lpkt_usb:m4rt9s@3dsp.com.cn/

in the folder "Open Source"

--
Joao Neto - Web Developer | PHP Zend Certified Engineer
@joao_neto | http://www.joaoneto.blog.br

^ permalink raw reply

* [PATCH] mac80211: fix typo in comments
From: Daniel Halperin @ 2010-04-18 16:28 UTC (permalink / raw)
  To: linux-wireless

The flag is called IEEE80211_TX_STAT_AMPDU rather than using the whole word
STATUS.

Signed-off-by: Daniel Halperin <dhalperi@cs.washington.edu>
---
 include/net/mac80211.h |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index dcf3c5f..ecf2273 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -395,11 +395,11 @@ struct ieee80211_tx_rate {
  * @status: union for status data
  * @driver_data: array of driver_data pointers
  * @ampdu_ack_len: number of acked aggregated frames.
- * 	relevant only if IEEE80211_TX_STATUS_AMPDU was set.
+ * 	relevant only if IEEE80211_TX_STAT_AMPDU was set.
  * @ampdu_ack_map: block ack bit map for the aggregation.
- * 	relevant only if IEEE80211_TX_STATUS_AMPDU was set.
+ * 	relevant only if IEEE80211_TX_STAT_AMPDU was set.
  * @ampdu_len: number of aggregated frames.
- * 	relevant only if IEEE80211_TX_STATUS_AMPDU was set.
+ * 	relevant only if IEEE80211_TX_STAT_AMPDU was set.
  * @ack_signal: signal strength of the ACK frame
  */
 struct ieee80211_tx_info {
-- 
1.5.4.3

			

^ permalink raw reply related

* Re: [PATCH 7/9] mac80211: add flags for STBC (Space-Time Block Coding)
From: Felix Fietkau @ 2010-04-18 16:05 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, linville, lrodriguez
In-Reply-To: <1271606009.3873.0.camel@jlt3.sipsolutions.net>

On 2010-04-18 5:53 PM, Johannes Berg wrote:
> On Sun, 2010-04-18 at 16:56 +0200, Felix Fietkau wrote:
>> Signed-off-by: Felix Fietkau <nbd@openwrt.org>
>> ---
>>  include/linux/ieee80211.h |    1 +
>>  include/net/mac80211.h    |    3 +++
>>  2 files changed, 4 insertions(+), 0 deletions(-)
>> 
>> diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
>> index 1252ba1..97b2eae 100644
>> --- a/include/linux/ieee80211.h
>> +++ b/include/linux/ieee80211.h
>> @@ -876,6 +876,7 @@ struct ieee80211_ht_cap {
>>  #define IEEE80211_HT_CAP_SGI_40			0x0040
>>  #define IEEE80211_HT_CAP_TX_STBC		0x0080
>>  #define IEEE80211_HT_CAP_RX_STBC		0x0300
>> +#define		IEEE80211_HT_CAP_RX_STBC_SHIFT	8
>>  #define IEEE80211_HT_CAP_DELAY_BA		0x0400
>>  #define IEEE80211_HT_CAP_MAX_AMSDU		0x0800
>>  #define IEEE80211_HT_CAP_DSSSCCK40		0x1000
>> diff --git a/include/net/mac80211.h b/include/net/mac80211.h
>> index 75056dd..eadf794 100644
>> --- a/include/net/mac80211.h
>> +++ b/include/net/mac80211.h
>> @@ -275,6 +275,8 @@ struct ieee80211_bss_conf {
>>   *	MLME command (internal to mac80211 to figure out whether to send TX
>>   *	status to user space)
>>   * @IEEE80211_TX_CTL_LDPC: tells the driver to use LDPC for this frame
>> + * @IEEE80211_TX_CTL_STBC: tells the driver to use Space-Time Block Coding
>> + *  (STBC) for this frame.
>>   */
>>  enum mac80211_tx_control_flags {
>>  	IEEE80211_TX_CTL_REQ_TX_STATUS		= BIT(0),
>> @@ -299,6 +301,7 @@ enum mac80211_tx_control_flags {
>>  	IEEE80211_TX_INTFL_HAS_RADIOTAP		= BIT(20),
>>  	IEEE80211_TX_INTFL_NL80211_FRAME_TX	= BIT(21),
>>  	IEEE80211_TX_CTL_LDPC			= BIT(22),
>> +	IEEE80211_TX_CTL_STBC			= BIT(23),
> 
> What if the # of streams is different? That doesn't look sufficient.
Hm, you're right. I initially thought the combination of the MCS index
and the STBC flag would be enough, but there are still some corner cases.
Want me to use BIT(23)|BIT(24) for this and add a shift, as with the HT
capability?

- Felix

^ permalink raw reply

* [PATCH 5/9] ath9k: reduce the bits_per_symbol table size, support more streams
From: Felix Fietkau @ 2010-04-18 14:56 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez
In-Reply-To: <1271602602-8538-4-git-send-email-nbd@openwrt.org>

Instead of increasing bits_per_symbol for supporting more streams, keep
it single-stream only and multiply the values by the numer of streams.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/xmit.c |   19 ++++++-------------
 1 files changed, 6 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 4078982..2237658 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -34,7 +34,7 @@
 
 #define OFDM_SIFS_TIME    	    16
 
-static u32 bits_per_symbol[][2] = {
+static u16 bits_per_symbol[][2] = {
 	/* 20MHz 40MHz */
 	{    26,   54 },     /*  0: BPSK */
 	{    52,  108 },     /*  1: QPSK 1/2 */
@@ -44,14 +44,6 @@ static u32 bits_per_symbol[][2] = {
 	{   208,  432 },     /*  5: 64-QAM 2/3 */
 	{   234,  486 },     /*  6: 64-QAM 3/4 */
 	{   260,  540 },     /*  7: 64-QAM 5/6 */
-	{    52,  108 },     /*  8: BPSK */
-	{   104,  216 },     /*  9: QPSK 1/2 */
-	{   156,  324 },     /* 10: QPSK 3/4 */
-	{   208,  432 },     /* 11: 16-QAM 1/2 */
-	{   312,  648 },     /* 12: 16-QAM 3/4 */
-	{   416,  864 },     /* 13: 64-QAM 2/3 */
-	{   468,  972 },     /* 14: 64-QAM 3/4 */
-	{   520, 1080 },     /* 15: 64-QAM 5/6 */
 };
 
 #define IS_HT_RATE(_rate)     ((_rate) & 0x80)
@@ -601,7 +593,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
 	u32 nsymbits, nsymbols;
 	u16 minlen;
 	u8 flags, rix;
-	int width, half_gi, ndelim, mindelim;
+	int width, streams, half_gi, ndelim, mindelim;
 
 	/* Select standard number of delimiters based on frame length alone */
 	ndelim = ATH_AGGR_GET_NDELIM(frmlen);
@@ -641,7 +633,8 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
 	if (nsymbols == 0)
 		nsymbols = 1;
 
-	nsymbits = bits_per_symbol[rix][width];
+	streams = HT_RC_2_STREAMS(rix);
+	nsymbits = bits_per_symbol[rix % 8][width] * streams;
 	minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
 
 	if (frmlen < minlen) {
@@ -1533,8 +1526,9 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
 	pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
 
 	/* find number of symbols: PLCP + data */
+	streams = HT_RC_2_STREAMS(rix);
 	nbits = (pktlen << 3) + OFDM_PLCP_BITS;
-	nsymbits = bits_per_symbol[rix][width];
+	nsymbits = bits_per_symbol[rix % 8][width] * streams;
 	nsymbols = (nbits + nsymbits - 1) / nsymbits;
 
 	if (!half_gi)
@@ -1543,7 +1537,6 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
 		duration = SYMBOL_TIME_HALFGI(nsymbols);
 
 	/* addup duration for legacy/ht training and signal fields */
-	streams = HT_RC_2_STREAMS(rix);
 	duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
 
 	return duration;
-- 
1.6.4.2


^ permalink raw reply related

* [PATCH 8/9] ath9k: add support for Tx and Rx STBC
From: Felix Fietkau @ 2010-04-18 14:56 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez
In-Reply-To: <1271602602-8538-7-git-send-email-nbd@openwrt.org>

Supported only for single stream rates by the hardware

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/init.c |    6 ++++++
 drivers/net/wireless/ath/ath9k/mac.h  |    8 +++++++-
 drivers/net/wireless/ath/ath9k/xmit.c |    2 ++
 3 files changed, 15 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 2c0630e..8c79548 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -216,6 +216,12 @@ static void setup_ht_cap(struct ath_softc *sc,
 	else
 		max_streams = 2;
 
+	if (AR_SREV_9280_10_OR_LATER(ah)) {
+		if (max_streams >= 2)
+			ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
+		ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
+	}
+
 	/* set up supported mcs set */
 	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
 	tx_streams = count_streams(common->tx_chainmask, max_streams);
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index 66d0d5e..00f3e0c 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -37,6 +37,8 @@
 	  AR_2040_##_index : 0)						\
 	 |((_series)[_index].RateFlags & ATH9K_RATESERIES_HALFGI ?	\
 	   AR_GI##_index : 0)						\
+	 |((_series)[_index].RateFlags & ATH9K_RATESERIES_STBC ?	\
+	   AR_STBC##_index : 0)						\
 	 |SM((_series)[_index].ChSel, AR_ChainSel##_index))
 
 #define CCK_SIFS_TIME        10
@@ -434,7 +436,10 @@ struct ar5416_desc {
 #define AR_ChainSel3_S      17
 #define AR_RTSCTSRate       0x0ff00000
 #define AR_RTSCTSRate_S     20
-#define AR_TxCtlRsvd70      0xf0000000
+#define AR_STBC0            0x10000000
+#define AR_STBC1            0x20000000
+#define AR_STBC2            0x40000000
+#define AR_STBC3            0x80000000
 
 #define AR_TxRSSIAnt00      0x000000ff
 #define AR_TxRSSIAnt00_S    0
@@ -647,6 +652,7 @@ enum ath9k_rx_filter {
 #define ATH9K_RATESERIES_RTS_CTS  0x0001
 #define ATH9K_RATESERIES_2040     0x0002
 #define ATH9K_RATESERIES_HALFGI   0x0004
+#define ATH9K_RATESERIES_STBC     0x0008
 
 struct ath9k_11n_rate_series {
 	u32 Tries;
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 2237658..b0d345a 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1607,6 +1607,8 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
 			series[i].Rate = rix | 0x80;
 			series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
 				 is_40, is_sgi, is_sp);
+			if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
+				series[i].RateFlags |= ATH9K_RATESERIES_STBC;
 			continue;
 		}
 
-- 
1.6.4.2


^ permalink raw reply related

* [PATCH 2/9] ath9k: clean up tx buffer handling
From: Felix Fietkau @ 2010-04-18 14:56 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez
In-Reply-To: <1271602602-8538-1-git-send-email-nbd@openwrt.org>

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/xmit.c |   67 ++++++++++++++++-----------------
 1 files changed, 32 insertions(+), 35 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index cac178a..fcbb4a8 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -261,19 +261,40 @@ static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
 	hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY);
 }
 
-static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
+static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
 {
-	struct ath_buf *tbf;
+	struct ath_buf *bf = NULL;
 
 	spin_lock_bh(&sc->tx.txbuflock);
-	if (WARN_ON(list_empty(&sc->tx.txbuf))) {
+
+	if (unlikely(list_empty(&sc->tx.txbuf))) {
 		spin_unlock_bh(&sc->tx.txbuflock);
 		return NULL;
 	}
-	tbf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
-	list_del(&tbf->list);
+
+	bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
+	list_del(&bf->list);
+
 	spin_unlock_bh(&sc->tx.txbuflock);
 
+	return bf;
+}
+
+static void ath_tx_return_buffer(struct ath_softc *sc, struct ath_buf *bf)
+{
+	spin_lock_bh(&sc->tx.txbuflock);
+	list_add_tail(&bf->list, &sc->tx.txbuf);
+	spin_unlock_bh(&sc->tx.txbuflock);
+}
+
+static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
+{
+	struct ath_buf *tbf;
+
+	tbf = ath_tx_get_buffer(sc);
+	if (WARN_ON(!tbf))
+		return NULL;
+
 	ATH_TXBUF_RESET(tbf);
 
 	tbf->aphy = bf->aphy;
@@ -1081,9 +1102,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
 				list_del(&bf->list);
 				spin_unlock_bh(&txq->axq_lock);
 
-				spin_lock_bh(&sc->tx.txbuflock);
-				list_add_tail(&bf->list, &sc->tx.txbuf);
-				spin_unlock_bh(&sc->tx.txbuflock);
+				ath_tx_return_buffer(sc, bf);
 				continue;
 			}
 		}
@@ -1325,25 +1344,6 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
 	txq->axq_depth++;
 }
 
-static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
-{
-	struct ath_buf *bf = NULL;
-
-	spin_lock_bh(&sc->tx.txbuflock);
-
-	if (unlikely(list_empty(&sc->tx.txbuf))) {
-		spin_unlock_bh(&sc->tx.txbuflock);
-		return NULL;
-	}
-
-	bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
-	list_del(&bf->list);
-
-	spin_unlock_bh(&sc->tx.txbuflock);
-
-	return bf;
-}
-
 static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
 			      struct list_head *bf_head,
 			      struct ath_tx_control *txctl)
@@ -1825,9 +1825,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
 		}
 		spin_unlock_bh(&txq->axq_lock);
 
-		spin_lock_bh(&sc->tx.txbuflock);
-		list_add_tail(&bf->list, &sc->tx.txbuf);
-		spin_unlock_bh(&sc->tx.txbuflock);
+		ath_tx_return_buffer(sc, bf);
 
 		return r;
 	}
@@ -2141,13 +2139,12 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
 		txq->axq_depth--;
 		txok = !(ts.ts_status & ATH9K_TXERR_MASK);
 		txq->axq_tx_inprogress = false;
+		if (bf_held)
+			list_del(&bf_held->list);
 		spin_unlock_bh(&txq->axq_lock);
 
-		if (bf_held) {
-			spin_lock_bh(&sc->tx.txbuflock);
-			list_move_tail(&bf_held->list, &sc->tx.txbuf);
-			spin_unlock_bh(&sc->tx.txbuflock);
-		}
+		if (bf_held)
+			ath_tx_return_buffer(sc, bf_held);
 
 		if (!bf_isampdu(bf)) {
 			/*
-- 
1.6.4.2


^ permalink raw reply related

* Re: [PATCH 7/9] mac80211: add flags for STBC (Space-Time Block Coding)
From: Johannes Berg @ 2010-04-18 15:53 UTC (permalink / raw)
  To: Felix Fietkau; +Cc: linux-wireless, linville, lrodriguez
In-Reply-To: <1271602602-8538-7-git-send-email-nbd@openwrt.org>

On Sun, 2010-04-18 at 16:56 +0200, Felix Fietkau wrote:
> Signed-off-by: Felix Fietkau <nbd@openwrt.org>
> ---
>  include/linux/ieee80211.h |    1 +
>  include/net/mac80211.h    |    3 +++
>  2 files changed, 4 insertions(+), 0 deletions(-)
> 
> diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
> index 1252ba1..97b2eae 100644
> --- a/include/linux/ieee80211.h
> +++ b/include/linux/ieee80211.h
> @@ -876,6 +876,7 @@ struct ieee80211_ht_cap {
>  #define IEEE80211_HT_CAP_SGI_40			0x0040
>  #define IEEE80211_HT_CAP_TX_STBC		0x0080
>  #define IEEE80211_HT_CAP_RX_STBC		0x0300
> +#define		IEEE80211_HT_CAP_RX_STBC_SHIFT	8
>  #define IEEE80211_HT_CAP_DELAY_BA		0x0400
>  #define IEEE80211_HT_CAP_MAX_AMSDU		0x0800
>  #define IEEE80211_HT_CAP_DSSSCCK40		0x1000
> diff --git a/include/net/mac80211.h b/include/net/mac80211.h
> index 75056dd..eadf794 100644
> --- a/include/net/mac80211.h
> +++ b/include/net/mac80211.h
> @@ -275,6 +275,8 @@ struct ieee80211_bss_conf {
>   *	MLME command (internal to mac80211 to figure out whether to send TX
>   *	status to user space)
>   * @IEEE80211_TX_CTL_LDPC: tells the driver to use LDPC for this frame
> + * @IEEE80211_TX_CTL_STBC: tells the driver to use Space-Time Block Coding
> + *  (STBC) for this frame.
>   */
>  enum mac80211_tx_control_flags {
>  	IEEE80211_TX_CTL_REQ_TX_STATUS		= BIT(0),
> @@ -299,6 +301,7 @@ enum mac80211_tx_control_flags {
>  	IEEE80211_TX_INTFL_HAS_RADIOTAP		= BIT(20),
>  	IEEE80211_TX_INTFL_NL80211_FRAME_TX	= BIT(21),
>  	IEEE80211_TX_CTL_LDPC			= BIT(22),
> +	IEEE80211_TX_CTL_STBC			= BIT(23),

What if the # of streams is different? That doesn't look sufficient.

johannes


^ permalink raw reply

* [PATCH 3/9] ath9k: update the MCS mask for MCS16 and above
From: Felix Fietkau @ 2010-04-18 14:56 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez
In-Reply-To: <1271602602-8538-2-git-send-email-nbd@openwrt.org>

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/xmit.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index fcbb4a8..5d3d563 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -19,7 +19,7 @@
 
 #define BITS_PER_BYTE           8
 #define OFDM_PLCP_BITS          22
-#define HT_RC_2_MCS(_rc)        ((_rc) & 0x0f)
+#define HT_RC_2_MCS(_rc)        ((_rc) & 0x1f)
 #define HT_RC_2_STREAMS(_rc)    ((((_rc) & 0x78) >> 3) + 1)
 #define L_STF                   8
 #define L_LTF                   8
-- 
1.6.4.2


^ permalink raw reply related

* [PATCH 1/9] ath9k: check for specific rx stuck conditions and recover from them
From: Felix Fietkau @ 2010-04-18 14:56 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/hw.c   |   28 ++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath9k/hw.h   |    1 +
 drivers/net/wireless/ath/ath9k/main.c |    3 ++-
 3 files changed, 31 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 9aa40df..5a29048 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1160,6 +1160,34 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
 	return true;
 }
 
+bool ath9k_hw_check_alive(struct ath_hw *ah)
+{
+	int count = 50;
+	u32 reg;
+
+	if (AR_SREV_9285_10_OR_LATER(ah))
+		return true;
+
+	do {
+		reg = REG_READ(ah, AR_OBS_BUS_1);
+
+		if ((reg & 0x7E7FFFEF) == 0x00702400)
+			continue;
+
+		switch (reg & 0x7E000B00) {
+		case 0x1E000000:
+		case 0x52000B00:
+		case 0x18000B00:
+			continue;
+		default:
+			return true;
+		}
+	} while (count-- > 0);
+
+	return false;
+}
+EXPORT_SYMBOL(ath9k_hw_check_alive);
+
 int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 		    bool bChannelChange)
 {
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 8158e8e..a78e09b 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -869,6 +869,7 @@ void ath9k_hw_set11nmac2040(struct ath_hw *ah);
 void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period);
 void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
 				    const struct ath9k_beacon_state *bs);
+bool ath9k_hw_check_alive(struct ath_hw *ah);
 
 bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode);
 
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 1f4ea74..0246e7a 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -405,7 +405,8 @@ void ath9k_tasklet(unsigned long data)
 
 	ath9k_ps_wakeup(sc);
 
-	if (status & ATH9K_INT_FATAL) {
+	if ((status & ATH9K_INT_FATAL) ||
+	    !ath9k_hw_check_alive(ah)) {
 		ath_reset(sc, false);
 		ath9k_ps_restore(sc);
 		return;
-- 
1.6.4.2


^ permalink raw reply related

* [PATCH 4/9] ath9k: update the ath_max_4ms_framelen table
From: Felix Fietkau @ 2010-04-18 14:56 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez
In-Reply-To: <1271602602-8538-3-git-send-email-nbd@openwrt.org>

Include MCS0-31 and also add SGI for HT20. This makes it
possible to support more different rate combinations with
newer hardware.

Based on a patch by Selvam. T.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/xmit.c |   41 +++++++++++++++++++++-----------
 1 files changed, 27 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 5d3d563..4078982 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -71,24 +71,36 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
 			     int nbad, int txok, bool update_rc);
 
 enum {
-	MCS_DEFAULT,
+	MCS_HT20,
+	MCS_HT20_SGI,
 	MCS_HT40,
 	MCS_HT40_SGI,
 };
 
-static int ath_max_4ms_framelen[3][16] = {
-	[MCS_DEFAULT] = {
-		3216,  6434,  9650,  12868, 19304, 25740,  28956,  32180,
-		6430,  12860, 19300, 25736, 38600, 51472,  57890,  64320,
+static int ath_max_4ms_framelen[4][32] = {
+	[MCS_HT20] = {
+		3212,  6432,  9648,  12864,  19300,  25736,  28952,  32172,
+		6424,  12852, 19280, 25708,  38568,  51424,  57852,  64280,
+		9628,  19260, 28896, 38528,  57792,  65532,  65532,  65532,
+		12828, 25656, 38488, 51320,  65532,  65532,  65532,  65532,
+	},
+	[MCS_HT20_SGI] = {
+		3572,  7144,  10720,  14296,  21444,  28596,  32172,  35744,
+		7140,  14284, 21428,  28568,  42856,  57144,  64288,  65532,
+		10700, 21408, 32112,  42816,  64228,  65532,  65532,  65532,
+		14256, 28516, 42780,  57040,  65532,  65532,  65532,  65532,
 	},
 	[MCS_HT40] = {
-		6684,  13368, 20052, 26738, 40104, 53476,  60156,  66840,
-		13360, 26720, 40080, 53440, 80160, 106880, 120240, 133600,
+		6680,  13360,  20044,  26724,  40092,  53456,  60140,  65532,
+		13348, 26700,  40052,  53400,  65532,  65532,  65532,  65532,
+		20004, 40008,  60016,  65532,  65532,  65532,  65532,  65532,
+		26644, 53292,  65532,  65532,  65532,  65532,  65532,  65532,
 	},
 	[MCS_HT40_SGI] = {
-		/* TODO: Only MCS 7 and 15 updated, recalculate the rest */
-		6684,  13368, 20052, 26738, 40104, 53476,  60156,  74200,
-		13360, 26720, 40080, 53440, 80160, 106880, 120240, 148400,
+		7420,  14844,  22272,  29696,  44544,  59396,  65532,  65532,
+		14832, 29668,  44504,  59340,  65532,  65532,  65532,  65532,
+		22232, 44464,  65532,  65532,  65532,  65532,  65532,  65532,
+		29616, 59232,  65532,  65532,  65532,  65532,  65532,  65532,
 	}
 };
 
@@ -538,12 +550,13 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
 				break;
 			}
 
-			if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
-				modeidx = MCS_HT40_SGI;
-			else if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+			if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
 				modeidx = MCS_HT40;
 			else
-				modeidx = MCS_DEFAULT;
+				modeidx = MCS_HT20;
+
+			if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
+				modeidx++;
 
 			frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx];
 			max_4ms_framelen = min(max_4ms_framelen, frmlen);
-- 
1.6.4.2


^ permalink raw reply related

* [PATCH 6/9] ath9k: initialize the number of tx/rx streams correctly
From: Felix Fietkau @ 2010-04-18 14:56 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez
In-Reply-To: <1271602602-8538-5-git-send-email-nbd@openwrt.org>

AR9300 based hardware can 3x3 MCS rates, this should be set in the
HT capabilities.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/init.c |   39 +++++++++++++++++++++++---------
 1 files changed, 28 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index ca6e781..2c0630e 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -175,6 +175,18 @@ static const struct ath_ops ath9k_common_ops = {
 	.write = ath9k_iowrite32,
 };
 
+static int count_streams(unsigned int chainmask, int max)
+{
+	int streams = 0;
+
+	do {
+		if (++streams == max)
+			break;
+	} while ((chainmask = chainmask & (chainmask - 1)));
+
+	return streams;
+}
+
 /**************************/
 /*     Initialization     */
 /**************************/
@@ -182,8 +194,10 @@ static const struct ath_ops ath9k_common_ops = {
 static void setup_ht_cap(struct ath_softc *sc,
 			 struct ieee80211_sta_ht_cap *ht_info)
 {
-	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
 	u8 tx_streams, rx_streams;
+	int i, max_streams;
 
 	ht_info->ht_supported = true;
 	ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
@@ -197,25 +211,28 @@ static void setup_ht_cap(struct ath_softc *sc,
 	ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
 	ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
 
+	if (AR_SREV_9300_20_OR_LATER(ah))
+		max_streams = 3;
+	else
+		max_streams = 2;
+
 	/* set up supported mcs set */
 	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
-	tx_streams = !(common->tx_chainmask & (common->tx_chainmask - 1)) ?
-		     1 : 2;
-	rx_streams = !(common->rx_chainmask & (common->rx_chainmask - 1)) ?
-		     1 : 2;
+	tx_streams = count_streams(common->tx_chainmask, max_streams);
+	rx_streams = count_streams(common->rx_chainmask, max_streams);
+
+	ath_print(common, ATH_DBG_CONFIG,
+		  "TX streams %d, RX streams: %d\n",
+		  tx_streams, rx_streams);
 
 	if (tx_streams != rx_streams) {
-		ath_print(common, ATH_DBG_CONFIG,
-			  "TX streams %d, RX streams: %d\n",
-			  tx_streams, rx_streams);
 		ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
 		ht_info->mcs.tx_params |= ((tx_streams - 1) <<
 				IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
 	}
 
-	ht_info->mcs.rx_mask[0] = 0xff;
-	if (rx_streams >= 2)
-		ht_info->mcs.rx_mask[1] = 0xff;
+	for (i = 0; i < rx_streams; i++)
+		ht_info->mcs.rx_mask[i] = 0xff;
 
 	ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
 }
-- 
1.6.4.2


^ permalink raw reply related

* [PATCH 7/9] mac80211: add flags for STBC (Space-Time Block Coding)
From: Felix Fietkau @ 2010-04-18 14:56 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez
In-Reply-To: <1271602602-8538-6-git-send-email-nbd@openwrt.org>

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 include/linux/ieee80211.h |    1 +
 include/net/mac80211.h    |    3 +++
 2 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 1252ba1..97b2eae 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -876,6 +876,7 @@ struct ieee80211_ht_cap {
 #define IEEE80211_HT_CAP_SGI_40			0x0040
 #define IEEE80211_HT_CAP_TX_STBC		0x0080
 #define IEEE80211_HT_CAP_RX_STBC		0x0300
+#define		IEEE80211_HT_CAP_RX_STBC_SHIFT	8
 #define IEEE80211_HT_CAP_DELAY_BA		0x0400
 #define IEEE80211_HT_CAP_MAX_AMSDU		0x0800
 #define IEEE80211_HT_CAP_DSSSCCK40		0x1000
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 75056dd..eadf794 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -275,6 +275,8 @@ struct ieee80211_bss_conf {
  *	MLME command (internal to mac80211 to figure out whether to send TX
  *	status to user space)
  * @IEEE80211_TX_CTL_LDPC: tells the driver to use LDPC for this frame
+ * @IEEE80211_TX_CTL_STBC: tells the driver to use Space-Time Block Coding
+ *  (STBC) for this frame.
  */
 enum mac80211_tx_control_flags {
 	IEEE80211_TX_CTL_REQ_TX_STATUS		= BIT(0),
@@ -299,6 +301,7 @@ enum mac80211_tx_control_flags {
 	IEEE80211_TX_INTFL_HAS_RADIOTAP		= BIT(20),
 	IEEE80211_TX_INTFL_NL80211_FRAME_TX	= BIT(21),
 	IEEE80211_TX_CTL_LDPC			= BIT(22),
+	IEEE80211_TX_CTL_STBC			= BIT(23),
 };
 
 /**
-- 
1.6.4.2


^ permalink raw reply related

* [PATCH 9/9] ath9k: set the STBC flag in rate control if the peer supports it
From: Felix Fietkau @ 2010-04-18 14:56 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez
In-Reply-To: <1271602602-8538-8-git-send-email-nbd@openwrt.org>

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/rc.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index bf3ad7a..7f2000c 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -700,6 +700,10 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 	    (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING))
 		tx_info->flags |= IEEE80211_TX_CTL_LDPC;
 
+	if (conf_is_ht(&sc->hw->conf) &&
+	    (sta->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC))
+		tx_info->flags |= IEEE80211_TX_CTL_STBC;
+
 	if (is_probe) {
 		/* set one try for probe rates. For the
 		 * probes don't enable rts */
-- 
1.6.4.2


^ permalink raw reply related


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