Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [ath9k-devel] On ath9k debugfs, having trouble recompiling and inserting only ath9k
From: Rakesh Kumar @ 2010-04-16  1:46 UTC (permalink / raw)
  To: Pavel Roskin; +Cc: ath9k-devel, linux-wireless
In-Reply-To: <1271108966.15194.4.camel@mj>

> Maybe /sys/kernel/debug/ath9k is already present.  You may want to
> reboot to "fix" it.

Yeah, it was due to the order of delete entry calls. I had included
one more debugfs u8 entry which was being deleted after the
directory's entry and thus not being deleted at all and on the next
run it would cause trouble on creation.  Thanks.

--
Rakesh

^ permalink raw reply

* Re: [PATCH v2] wl1251: register platform_device to pass board data
From: Kalle Valo @ 2010-04-16  5:03 UTC (permalink / raw)
  To: Grazvydas Ignotas; +Cc: John W. Linville, linux-wireless
In-Reply-To: <1271345003-15453-1-git-send-email-notasas@gmail.com>

Grazvydas Ignotas <notasas@gmail.com> writes:

> wl1251 is embedded chip that can be connected using SDIO bus, and is not
> an actual SDIO card. For this reason there is a need to pass some board
> specific data, like 'EEPROM is attached' flag or power control callback.
>
> However currently there is no way to pass this data through SDIO subsystem,
> so this patch registers dummy platform_device to allow that, until we
> have a better solution to this.

Looks very good now, thanks a lot for doing this.

> Signed-off-by: Grazvydas Ignotas <notasas@gmail.com>

Acked-by: Kalle Valo <kvalo@adurom.com>

-- 
Kalle Valo

^ permalink raw reply

* Re: [RFC PATCHv2 1/2] mac80211: Determine dynamic PS timeout based on ps-qos network latency
From: Kalle Valo @ 2010-04-16  5:17 UTC (permalink / raw)
  To: Juuso Oikarinen; +Cc: linux-wireless
In-Reply-To: <1271228079-27321-2-git-send-email-juuso.oikarinen@nokia.com>

Juuso Oikarinen <juuso.oikarinen@nokia.com> writes:

> Determine the dynamic PS timeout based on the configured ps-qos network
> latency. For backwards wext compatibility, allow the dynamic PS timeout
> configured by the cfg80211 to overrule the automatically determined value.

Thanks. I took a quick look, but I haven't tested this yet myself.

> +		timeout = local->hw.conf.dynamic_ps_forced_timeout;
> +		if (timeout < 0) {
> +			if (latency <= 50000)
> +				timeout = 300;
> +			else if (latency <= 2000000000)
> +				timeout = 100;
> +			else
> +				timeout = 0;
> +		}
> +		local->hw.conf.dynamic_ps_timeout = timeout;

What will be the timeout value when there are no pm_qos requirements
from user space applications? Do you know what will be the default
latency value in that case?

I'm mostly worried about timeout 0 case, for example I suspect ath9k
is broken with that value.

Also does this patch change the default value of dynamic ps timeout?

-- 
Kalle Valo

^ permalink raw reply

* Re: [RFC PATCHv2 1/2] mac80211: Determine dynamic PS timeout based on ps-qos network latency
From: Juuso Oikarinen @ 2010-04-16  5:29 UTC (permalink / raw)
  To: ext Kalle Valo; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <87eiigm0vu.fsf@purkki.valot.fi>

Hi,

On Fri, 2010-04-16 at 07:17 +0200, ext Kalle Valo wrote:
> Juuso Oikarinen <juuso.oikarinen@nokia.com> writes:
> 
> > Determine the dynamic PS timeout based on the configured ps-qos network
> > latency. For backwards wext compatibility, allow the dynamic PS timeout
> > configured by the cfg80211 to overrule the automatically determined value.
> 
> Thanks. I took a quick look, but I haven't tested this yet myself.
> 
> > +		timeout = local->hw.conf.dynamic_ps_forced_timeout;
> > +		if (timeout < 0) {
> > +			if (latency <= 50000)
> > +				timeout = 300;
> > +			else if (latency <= 2000000000)
> > +				timeout = 100;
> > +			else
> > +				timeout = 0;
> > +		}
> > +		local->hw.conf.dynamic_ps_timeout = timeout;
> 
> What will be the timeout value when there are no pm_qos requirements
> from user space applications? Do you know what will be the default
> latency value in that case?

Yes, the default value is 2000000000 (2000 seconds, ugh.) Hence the
value in the if statement for 100ms.

> I'm mostly worried about timeout 0 case, for example I suspect ath9k
> is broken with that value.
> 
> Also does this patch change the default value of dynamic ps timeout?
> 

No, the current default does not change. As the default value for the
latency is 2000s, we will, by default, get a timeout of 100ms.

-Juuso


^ permalink raw reply

* Re: [RFC PATCHv2 1/2] mac80211: Determine dynamic PS timeout based on ps-qos network latency
From: Kalle Valo @ 2010-04-16  6:10 UTC (permalink / raw)
  To: Juuso Oikarinen; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <1271395747.6205.23.camel@wimaxnb.nmp.nokia.com>

Juuso Oikarinen <juuso.oikarinen@nokia.com> writes:

> Hi,

Moi,

>> > +		timeout = local->hw.conf.dynamic_ps_forced_timeout;
>> > +		if (timeout < 0) {
>> > +			if (latency <= 50000)
>> > +				timeout = 300;
>> > +			else if (latency <= 2000000000)
>> > +				timeout = 100;
>> > +			else
>> > +				timeout = 0;
>> > +		}
>> > +		local->hw.conf.dynamic_ps_timeout = timeout;
>> 
>> What will be the timeout value when there are no pm_qos requirements
>> from user space applications? Do you know what will be the default
>> latency value in that case?
>
> Yes, the default value is 2000000000 (2000 seconds, ugh.) Hence the
> value in the if statement for 100ms.

Ah, now I understand better.

And ugh indeed, having a default of 2000 seconds for latency is very
awkward. I would have preferred to have a magic value denoting (like
-1 or something) that user space doesn't care. But I guess we have to
live with this :/

Maybe at some point we can talk with QoS framework about this.

>> I'm mostly worried about timeout 0 case, for example I suspect ath9k
>> is broken with that value.
>> 
>> Also does this patch change the default value of dynamic ps timeout?
>> 
>
> No, the current default does not change. As the default value for the
> latency is 2000s, we will, by default, get a timeout of 100ms.

Excellent. Thank you for explaining these.

>From my point of view these patches look good and I have nothing to
complain. 

(I hope Juuso didn't hit his head when falling off from his chair when
reading this.)

-- 
Kalle Valo

^ permalink raw reply

* [PATCH PING] ssb patches for SPROM location
From: Rafał Miłecki @ 2010-04-16  6:20 UTC (permalink / raw)
  To: linux-wireless, John W. Linville

John, I posted some time ago following patches:

[RFT][PATCH] ssb: Look for SPROM at different offset on higher rev CC
[PATCH 1/2] ssb: Use relative offsets for SPROM
[PATCH 2/2] ssb: Fix order of definitions and some text space indents

while Michael has some doubts about "ssb: Look for SPROM at different
offset on higher rev CC" I explained to him that what he does not like
was fixed in next 2 posted patches.

AFAIR you got some device with this recently-discovered location of
SPROM. Could you test my set if it makes your card working? If so,
could you take that patches to your tree?

-- 
Rafał

^ permalink raw reply

* Re: [RFC PATCHv2 1/2] mac80211: Determine dynamic PS timeout based on ps-qos network latency
From: Juuso Oikarinen @ 2010-04-16  6:17 UTC (permalink / raw)
  To: ext Kalle Valo; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <87aat4lygg.fsf@purkki.valot.fi>

On Fri, 2010-04-16 at 08:10 +0200, ext Kalle Valo wrote:
> Maybe at some point we can talk with QoS framework about this.
> 
> >> I'm mostly worried about timeout 0 case, for example I suspect ath9k
> >> is broken with that value.
> >> 
> >> Also does this patch change the default value of dynamic ps timeout?
> >> 
> >
> > No, the current default does not change. As the default value for the
> > latency is 2000s, we will, by default, get a timeout of 100ms.
> 
> Excellent. Thank you for explaining these.
> 
> From my point of view these patches look good and I have nothing to
> complain. 

You're definitely getting soft. I will stretch my luck by submitting a
v3 with one more latency range, giving a dynamic PS timeout of 50 ms.

> (I hope Juuso didn't hit his head when falling off from his chair when
> reading this.)
> 

*ouch*

-Juuso


^ permalink raw reply

* [PATCH 00/10] ath9k_htc updates
From: Sujith @ 2010-04-16  6:23 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless

John,

This series contains all the pending patches
for ath9k_htc, rebased over Luis' latest series.

Sujith

Sujith (10):
  ath9k_htc: Cleanup beacon configuration
  ath: Add buffered register write operations
  ath9k_htc: Implement multiple register write support
  ath9k_hw: Add macros for multiple register writes
  ath9k_hw: Relocate Opmode initialization
  ath9k_hw: Use buffered register writes
  ath9k_htc: Remove GPIO set on unload
  ath9k_htc: Add dropped SKB count to debugfs
  ath9k_htc: Handle WMI timeouts properly
  ath9k_htc: Fix sparse endian warnings

 drivers/net/wireless/ath/ath.h                  |   14 +++-
 drivers/net/wireless/ath/ath9k/ani.c            |   23 +++++
 drivers/net/wireless/ath/ath9k/ar5008_phy.c     |   28 ++++++
 drivers/net/wireless/ath/ath9k/ar9002_calib.c   |    5 +
 drivers/net/wireless/ath/ath9k/ar9002_hw.c      |    7 ++-
 drivers/net/wireless/ath/ath9k/ar9002_phy.c     |    5 +
 drivers/net/wireless/ath/ath9k/eeprom_4k.c      |   10 ++
 drivers/net/wireless/ath/ath9k/hif_usb.c        |   13 ++-
 drivers/net/wireless/ath/ath9k/htc.h            |   19 ++--
 drivers/net/wireless/ath/ath9k/htc_drv_beacon.c |   29 +++----
 drivers/net/wireless/ath/ath9k/htc_drv_init.c   |  104 ++++++++++++++++++++++-
 drivers/net/wireless/ath/ath9k/htc_drv_main.c   |   20 +++--
 drivers/net/wireless/ath/ath9k/htc_drv_txrx.c   |   11 +--
 drivers/net/wireless/ath/ath9k/htc_hst.c        |    8 +-
 drivers/net/wireless/ath/ath9k/htc_hst.h        |   24 +++---
 drivers/net/wireless/ath/ath9k/hw.c             |   79 ++++++++++++++++--
 drivers/net/wireless/ath/ath9k/hw.h             |   18 ++++
 drivers/net/wireless/ath/ath9k/mac.c            |   27 ++++++
 drivers/net/wireless/ath/ath9k/mac.h            |   10 +-
 drivers/net/wireless/ath/ath9k/wmi.c            |   16 +++-
 drivers/net/wireless/ath/ath9k/wmi.h            |   19 ++++-
 21 files changed, 407 insertions(+), 82 deletions(-)


^ permalink raw reply

* [PATCH 01/10] ath9k_htc: Cleanup beacon configuration
From: Sujith @ 2010-04-16  6:23 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless

This patch cleans up beacon configuration,
removing a redundant interface type check
and updating beacon interval in the correct place.

Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
 drivers/net/wireless/ath/ath9k/htc_drv_beacon.c |   23 +++++++++--------------
 drivers/net/wireless/ath/ath9k/htc_drv_main.c   |    2 +-
 2 files changed, 10 insertions(+), 15 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index 5e21f4d..d104028 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -244,25 +244,20 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
 			     struct ieee80211_vif *vif)
 {
 	struct ath_common *common = ath9k_hw_common(priv->ah);
-	enum nl80211_iftype iftype;
 	struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf;
+	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
 
-	if (vif) {
-		struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
-		iftype = vif->type;
-		cur_conf->beacon_interval = bss_conf->beacon_int;
-		cur_conf->dtim_period = bss_conf->dtim_period;
-		cur_conf->listen_interval = 1;
-		cur_conf->dtim_count = 1;
-		cur_conf->bmiss_timeout =
-			ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
-	} else
-		iftype = priv->ah->opmode;
-
+	cur_conf->beacon_interval = bss_conf->beacon_int;
 	if (cur_conf->beacon_interval == 0)
 		cur_conf->beacon_interval = 100;
 
-	switch (iftype) {
+	cur_conf->dtim_period = bss_conf->dtim_period;
+	cur_conf->listen_interval = 1;
+	cur_conf->dtim_count = 1;
+	cur_conf->bmiss_timeout =
+		ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
+
+	switch (vif->type) {
 	case NL80211_IFTYPE_STATION:
 		ath9k_htc_beacon_config_sta(priv, cur_conf);
 		break;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index eb7722b..08a4a58 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1687,7 +1687,7 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
 	spin_unlock_bh(&priv->beacon_lock);
 	priv->op_flags |= OP_FULL_RESET;
 	if (priv->op_flags & OP_ASSOCIATED)
-		ath9k_htc_beacon_config(priv, NULL);
+		ath9k_htc_beacon_config(priv, priv->vif);
 	ath_start_ani(priv);
 	mutex_unlock(&priv->mutex);
 	ath9k_htc_ps_restore(priv);
-- 
1.7.0.5


^ permalink raw reply related

* [PATCH 02/10] ath: Add buffered register write operations
From: Sujith @ 2010-04-16  6:23 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless

This is required to implement delayed/buffered
register writes in ath9k_htc.

Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
 drivers/net/wireless/ath/ath.h |   14 +++++++++++++-
 1 files changed, 13 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index 1fbf6b1..d32f282 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -71,9 +71,21 @@ struct ath_regulatory {
 	struct reg_dmn_pair_mapping *regpair;
 };
 
+/**
+ * struct ath_ops - Register read/write operations
+ *
+ * @read: Register read
+ * @write: Register write
+ * @enable_write_buffer: Enable multiple register writes
+ * @disable_write_buffer: Disable multiple register writes
+ * @write_flush: Flush buffered register writes
+ */
 struct ath_ops {
 	unsigned int (*read)(void *, u32 reg_offset);
-        void (*write)(void *, u32 val, u32 reg_offset);
+	void (*write)(void *, u32 val, u32 reg_offset);
+	void (*enable_write_buffer)(void *);
+	void (*disable_write_buffer)(void *);
+	void (*write_flush) (void *);
 };
 
 struct ath_common;
-- 
1.7.0.5


^ permalink raw reply related

* [PATCH 03/10] ath9k_htc: Implement multiple register write support
From: Sujith @ 2010-04-16  6:23 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless

This patch adds support for writing multiple registers
in a single USB command.

Specific calls from the HW code that performs multiple
register writes would be modified to make use of this
in subsequent patches.

Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
 drivers/net/wireless/ath/ath9k/htc_drv_init.c |  104 ++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath9k/wmi.c          |    1 +
 drivers/net/wireless/ath/ath9k/wmi.h          |   12 +++
 3 files changed, 113 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index aed5357..a861896 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -213,7 +213,7 @@ static int ath9k_reg_notifier(struct wiphy *wiphy,
 				      ath9k_hw_regulatory(priv->ah));
 }
 
-static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset)
+static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset)
 {
 	struct ath_hw *ah = (struct ath_hw *) hw_priv;
 	struct ath_common *common = ath9k_hw_common(ah);
@@ -235,7 +235,7 @@ static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset)
 	return be32_to_cpu(val);
 }
 
-static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset)
+static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset)
 {
 	struct ath_hw *ah = (struct ath_hw *) hw_priv;
 	struct ath_common *common = ath9k_hw_common(ah);
@@ -257,9 +257,105 @@ static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset)
 	}
 }
 
+static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset)
+{
+	struct ath_hw *ah = (struct ath_hw *) hw_priv;
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+	u32 rsp_status;
+	int r;
+
+	mutex_lock(&priv->wmi->multi_write_mutex);
+
+	/* Store the register/value */
+	priv->wmi->multi_write[priv->wmi->multi_write_idx].reg =
+		cpu_to_be32(reg_offset);
+	priv->wmi->multi_write[priv->wmi->multi_write_idx].val =
+		cpu_to_be32(val);
+
+	priv->wmi->multi_write_idx++;
+
+	/* If the buffer is full, send it out. */
+	if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) {
+		r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
+			  (u8 *) &priv->wmi->multi_write,
+			  sizeof(struct register_write) * priv->wmi->multi_write_idx,
+			  (u8 *) &rsp_status, sizeof(rsp_status),
+			  100);
+		if (unlikely(r)) {
+			ath_print(common, ATH_DBG_WMI,
+				  "REGISTER WRITE FAILED, multi len: %d\n",
+				  priv->wmi->multi_write_idx);
+		}
+		priv->wmi->multi_write_idx = 0;
+	}
+
+	mutex_unlock(&priv->wmi->multi_write_mutex);
+}
+
+static void ath9k_regwrite(void *hw_priv, u32 val, u32 reg_offset)
+{
+	struct ath_hw *ah = (struct ath_hw *) hw_priv;
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+
+	if (atomic_read(&priv->wmi->mwrite_cnt))
+		ath9k_regwrite_buffer(hw_priv, val, reg_offset);
+	else
+		ath9k_regwrite_single(hw_priv, val, reg_offset);
+}
+
+static void ath9k_enable_regwrite_buffer(void *hw_priv)
+{
+	struct ath_hw *ah = (struct ath_hw *) hw_priv;
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+
+	atomic_inc(&priv->wmi->mwrite_cnt);
+}
+
+static void ath9k_disable_regwrite_buffer(void *hw_priv)
+{
+	struct ath_hw *ah = (struct ath_hw *) hw_priv;
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+
+	atomic_dec(&priv->wmi->mwrite_cnt);
+}
+
+static void ath9k_regwrite_flush(void *hw_priv)
+{
+	struct ath_hw *ah = (struct ath_hw *) hw_priv;
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+	u32 rsp_status;
+	int r;
+
+	mutex_lock(&priv->wmi->multi_write_mutex);
+
+	if (priv->wmi->multi_write_idx) {
+		r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
+			  (u8 *) &priv->wmi->multi_write,
+			  sizeof(struct register_write) * priv->wmi->multi_write_idx,
+			  (u8 *) &rsp_status, sizeof(rsp_status),
+			  100);
+		if (unlikely(r)) {
+			ath_print(common, ATH_DBG_WMI,
+				  "REGISTER WRITE FAILED, multi len: %d\n",
+				  priv->wmi->multi_write_idx);
+		}
+		priv->wmi->multi_write_idx = 0;
+	}
+
+	mutex_unlock(&priv->wmi->multi_write_mutex);
+}
+
 static const struct ath_ops ath9k_common_ops = {
-	.read = ath9k_ioread32,
-	.write = ath9k_iowrite32,
+	.read = ath9k_regread,
+	.write = ath9k_regwrite,
+	.enable_write_buffer = ath9k_enable_regwrite_buffer,
+	.disable_write_buffer = ath9k_disable_regwrite_buffer,
+	.write_flush = ath9k_regwrite_flush,
 };
 
 static void ath_usb_read_cachesize(struct ath_common *common, int *csz)
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index f2ff18c..355e0db 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -101,6 +101,7 @@ struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv)
 	wmi->drv_priv = priv;
 	wmi->stopped = false;
 	mutex_init(&wmi->op_mutex);
+	mutex_init(&wmi->multi_write_mutex);
 	init_completion(&wmi->cmd_wait);
 
 	return wmi;
diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h
index 39ef926..fd8c9c5 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.h
+++ b/drivers/net/wireless/ath/ath9k/wmi.h
@@ -84,6 +84,13 @@ enum wmi_event_id {
 	WMI_TXRATE_EVENTID,
 };
 
+#define MAX_CMD_NUMBER 62
+
+struct register_write {
+	u32 reg;
+	u32 val;
+};
+
 struct wmi {
 	struct ath9k_htc_priv *drv_priv;
 	struct htc_target *htc;
@@ -97,6 +104,11 @@ struct wmi {
 
 	struct sk_buff *wmi_skb;
 	spinlock_t wmi_lock;
+
+	atomic_t mwrite_cnt;
+	struct register_write multi_write[MAX_CMD_NUMBER];
+	u32 multi_write_idx;
+	struct mutex multi_write_mutex;
 };
 
 struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv);
-- 
1.7.0.5


^ permalink raw reply related

* [PATCH 04/10] ath9k_hw: Add macros for multiple register writes
From: Sujith @ 2010-04-16  6:23 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless

Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
 drivers/net/wireless/ath/ath9k/hw.h |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 7ce5420..8158e8e 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -68,6 +68,24 @@
 #define REG_READ(_ah, _reg) \
 	ath9k_hw_common(_ah)->ops->read((_ah), (_reg))
 
+#define ENABLE_REGWRITE_BUFFER(_ah)					\
+	do {								\
+		if (AR_SREV_9271(_ah))					\
+			ath9k_hw_common(_ah)->ops->enable_write_buffer((_ah)); \
+	} while (0)
+
+#define DISABLE_REGWRITE_BUFFER(_ah)					\
+	do {								\
+		if (AR_SREV_9271(_ah))					\
+			ath9k_hw_common(_ah)->ops->disable_write_buffer((_ah)); \
+	} while (0)
+
+#define REGWRITE_BUFFER_FLUSH(_ah)					\
+	do {								\
+		if (AR_SREV_9271(_ah))					\
+			ath9k_hw_common(_ah)->ops->write_flush((_ah));	\
+	} while (0)
+
 #define SM(_v, _f)  (((_v) << _f##_S) & _f)
 #define MS(_v, _f)  (((_v) & _f) >> _f##_S)
 #define REG_RMW(_a, _r, _set, _clr)    \
-- 
1.7.0.5


^ permalink raw reply related

* [PATCH 05/10] ath9k_hw: Relocate Opmode initialization
From: Sujith @ 2010-04-16  6:23 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless

Programming the opmode in the HW can be done
before the assoc_id and STA_ID registers are
setup. This helps ath9k_htc when multiple register
writes are used.

Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
 drivers/net/wireless/ath/ath9k/hw.c |    8 ++------
 1 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index b9921e9..18cbb19 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1239,6 +1239,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 	ath9k_hw_spur_mitigate_freq(ah, chan);
 	ah->eep_ops->set_board_values(ah, chan);
 
+	ath9k_hw_set_operating_mode(ah, ah->opmode);
+
 	REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr));
 	REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(common->macaddr + 4)
 		  | macStaId1
@@ -1246,16 +1248,10 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 		  | (ah->config.
 		     ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0)
 		  | ah->sta_id1_defaults);
-	ath9k_hw_set_operating_mode(ah, ah->opmode);
-
 	ath_hw_setbssidmask(common);
-
 	REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);
-
 	ath9k_hw_write_associd(ah);
-
 	REG_WRITE(ah, AR_ISR, ~0);
-
 	REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
 
 	r = ath9k_hw_rf_set_freq(ah, chan);
-- 
1.7.0.5


^ permalink raw reply related

* [PATCH 06/10] ath9k_hw: Use buffered register writes
From: Sujith @ 2010-04-16  6:23 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless

This patch adds macros at certain places
which could be optimized for multiple register writes.

The performance of ath9k_htc improves considerably,
especially reducing the latency involved in a scan run.

Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
 drivers/net/wireless/ath/ath9k/ani.c          |   23 ++++++++
 drivers/net/wireless/ath/ath9k/ar5008_phy.c   |   28 ++++++++++
 drivers/net/wireless/ath/ath9k/ar9002_calib.c |    5 ++
 drivers/net/wireless/ath/ath9k/ar9002_hw.c    |    7 ++-
 drivers/net/wireless/ath/ath9k/ar9002_phy.c   |    5 ++
 drivers/net/wireless/ath/ath9k/eeprom_4k.c    |   10 ++++
 drivers/net/wireless/ath/ath9k/hw.c           |   71 +++++++++++++++++++++++++
 drivers/net/wireless/ath/ath9k/mac.c          |   27 +++++++++
 8 files changed, 175 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index 5a2d867..cec62d3 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -79,11 +79,17 @@ static void ath9k_ani_restart(struct ath_hw *ah)
 		  "Writing ofdmbase=%u   cckbase=%u\n",
 		  aniState->ofdmPhyErrBase,
 		  aniState->cckPhyErrBase);
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
 	REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
 	REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
 	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
 
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
+
 	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
 
 	aniState->ofdmPhyErrCount = 0;
@@ -357,8 +363,14 @@ void ath9k_ani_reset(struct ath_hw *ah)
 	ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
 			     ~ATH9K_RX_FILTER_PHYERR);
 	ath9k_ani_restart(ah);
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
 	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
 }
 
 void ath9k_hw_ani_monitor(struct ath_hw *ah,
@@ -456,6 +468,8 @@ void ath9k_enable_mib_counters(struct ath_hw *ah)
 
 	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	REG_WRITE(ah, AR_FILT_OFDM, 0);
 	REG_WRITE(ah, AR_FILT_CCK, 0);
 	REG_WRITE(ah, AR_MIBC,
@@ -463,6 +477,9 @@ void ath9k_enable_mib_counters(struct ath_hw *ah)
 		  & 0x0f);
 	REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
 	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
 }
 
 /* Freeze the MIB counters, get the stats and then clear them */
@@ -626,8 +643,14 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
 	ath_print(common, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
 		  ah->ani[0].cckPhyErrBase);
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase);
 	REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
+
 	ath9k_enable_mib_counters(ah);
 
 	ah->aniperiod = ATH9K_ANI_PERIOD;
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index 94eb069..de8ce12 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -590,10 +590,14 @@ static void ar5008_hw_init_chain_masks(struct ath_hw *ah)
 	rx_chainmask = ah->rxchainmask;
 	tx_chainmask = ah->txchainmask;
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	switch (rx_chainmask) {
 	case 0x5:
+		DISABLE_REGWRITE_BUFFER(ah);
 		REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
 			    AR_PHY_SWAP_ALT_CHAIN);
+		ENABLE_REGWRITE_BUFFER(ah);
 	case 0x3:
 		if (ah->hw_version.macVersion == AR_SREV_REVISION_5416_10) {
 			REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7);
@@ -611,6 +615,10 @@ static void ar5008_hw_init_chain_masks(struct ath_hw *ah)
 	}
 
 	REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
+
 	if (tx_chainmask == 0x5) {
 		REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
 			    AR_PHY_SWAP_ALT_CHAIN);
@@ -689,8 +697,13 @@ static void ar5008_hw_set_channel_regs(struct ath_hw *ah,
 
 	ath9k_hw_set11nmac2040(ah);
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S);
 	REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
 }
 
 
@@ -773,6 +786,8 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
 
 	REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC);
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	for (i = 0; i < ah->iniModes.ia_rows; i++) {
 		u32 reg = INI_RA(&ah->iniModes, i, 0);
 		u32 val = INI_RA(&ah->iniModes, i, modesIndex);
@@ -790,6 +805,9 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
 		DO_DELAY(regWrites);
 	}
 
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
+
 	if (AR_SREV_9280(ah) || AR_SREV_9287_10_OR_LATER(ah))
 		REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites);
 
@@ -801,6 +819,8 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
 		REG_WRITE_ARRAY(&ah->iniModes_9271_1_0_only,
 				modesIndex, regWrites);
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	/* Write common array parameters */
 	for (i = 0; i < ah->iniCommon.ia_rows; i++) {
 		u32 reg = INI_RA(&ah->iniCommon, i, 0);
@@ -816,6 +836,9 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
 		DO_DELAY(regWrites);
 	}
 
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
+
 	if (AR_SREV_9271(ah)) {
 		if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == 1)
 			REG_WRITE_ARRAY(&ah->iniModes_high_power_tx_gain_9271,
@@ -1303,6 +1326,8 @@ static void ar5008_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
 		udelay(50);
 	}
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	for (i = 0; i < NUM_NF_READINGS; i++) {
 		if (chainmask & (1 << i)) {
 			val = REG_READ(ah, ar5416_cca_regs[i]);
@@ -1311,6 +1336,9 @@ static void ar5008_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
 			REG_WRITE(ah, ar5416_cca_regs[i], val);
 		}
 	}
+
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
 }
 
 void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
index 968529b..5fdbb53 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
@@ -527,6 +527,8 @@ static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset)
 		ah->pacal_info.prev_offset = regVal;
 	}
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	regVal = REG_READ(ah, 0x7834);
 	regVal |= 0x1;
 	REG_WRITE(ah, 0x7834, regVal);
@@ -536,6 +538,9 @@ static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset)
 
 	for (i = 0; i < ARRAY_SIZE(regList); i++)
 		REG_WRITE(ah, regList[i][0], regList[i][1]);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
 }
 
 static inline void ar9285_hw_pa_cal(struct ath_hw *ah, bool is_reset)
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
index 17b98a3..adb33b3 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
@@ -488,10 +488,15 @@ static int ar9002_hw_get_radiorev(struct ath_hw *ah)
 	u32 val;
 	int i;
 
-	REG_WRITE(ah, AR_PHY(0x36), 0x00007058);
+	ENABLE_REGWRITE_BUFFER(ah);
 
+	REG_WRITE(ah, AR_PHY(0x36), 0x00007058);
 	for (i = 0; i < 8; i++)
 		REG_WRITE(ah, AR_PHY(0x20), 0x00010000);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
+
 	val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff;
 	val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
 
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
index a0a2f58..18cfe1a 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
@@ -236,6 +236,8 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah,
 
 	tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0));
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
 			AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
 			AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
@@ -411,6 +413,9 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah,
 		| (mask_p[47] << 2) | (mask_p[46] << 0);
 	REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask);
 	REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
 }
 
 static void ar9002_olc_init(struct ath_hw *ah)
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index 2384a9f..41a77d1 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -454,6 +454,8 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
 					    &tMinCalPower, gainBoundaries,
 					    pdadcValues, numXpdGain);
 
+			ENABLE_REGWRITE_BUFFER(ah);
+
 			if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) {
 				REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset,
 					  SM(pdGainOverlap_t2,
@@ -494,6 +496,9 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
 
 				regOffset += 4;
 			}
+
+			REGWRITE_BUFFER_FLUSH(ah);
+			DISABLE_REGWRITE_BUFFER(ah);
 		}
 	}
 
@@ -759,6 +764,8 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
 			ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
 	}
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	/* OFDM power per rate */
 	REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
 		  ATH9K_POW_SM(ratesArray[rate18mb], 24)
@@ -821,6 +828,9 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
 			  | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
 			  | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
 	}
+
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
 }
 
 static void ath9k_hw_4k_set_addac(struct ath_hw *ah,
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 18cbb19..daca9d3 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -275,6 +275,8 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah)
 	if (AR_SREV_9100(ah))
 		return;
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
 	REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
 	REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029);
@@ -286,6 +288,9 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah)
 	REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007);
 
 	REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
 }
 
 /* This should work for all families including legacy */
@@ -639,6 +644,8 @@ EXPORT_SYMBOL(ath9k_hw_init);
 
 static void ath9k_hw_init_qos(struct ath_hw *ah)
 {
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa);
 	REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210);
 
@@ -652,6 +659,9 @@ static void ath9k_hw_init_qos(struct ath_hw *ah)
 	REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF);
 	REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF);
 	REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
 }
 
 static void ath9k_hw_init_pll(struct ath_hw *ah,
@@ -703,6 +713,8 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
 	if (opmode == NL80211_IFTYPE_AP)
 		imr_reg |= AR_IMR_MIB;
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	REG_WRITE(ah, AR_IMR, imr_reg);
 	ah->imrs2_reg |= AR_IMR_S2_GTT;
 	REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
@@ -713,6 +725,9 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
 		REG_WRITE(ah, AR_INTR_SYNC_MASK, 0);
 	}
 
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
+
 	if (AR_SREV_9300_20_OR_LATER(ah)) {
 		REG_WRITE(ah, AR_INTR_PRIO_ASYNC_ENABLE, 0);
 		REG_WRITE(ah, AR_INTR_PRIO_ASYNC_MASK, 0);
@@ -841,6 +856,8 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
 	struct ath_common *common = ath9k_hw_common(ah);
 	u32 regval;
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	/*
 	 * set AHB_MODE not to do cacheline prefetches
 	*/
@@ -855,6 +872,9 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
 	regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK;
 	REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
 
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
+
 	/*
 	 * Restore TX Trigger Level to its pre-reset value.
 	 * The initial value depends on whether aggregation is enabled, and is
@@ -863,6 +883,8 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
 	if (!AR_SREV_9300_20_OR_LATER(ah))
 		REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->tx_trig_level);
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	/*
 	 * let mac dma writes be in 128 byte chunks
 	 */
@@ -898,6 +920,9 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
 			  AR_PCU_TXBUF_CTRL_USABLE_SIZE);
 	}
 
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
+
 	if (AR_SREV_9300_20_OR_LATER(ah))
 		ath9k_hw_reset_txstatus_ring(ah);
 }
@@ -957,6 +982,8 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
 		(void)REG_READ(ah, AR_RTC_DERIVED_CLK);
 	}
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
 		  AR_RTC_FORCE_WAKE_ON_INT);
 
@@ -985,6 +1012,10 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
 	}
 
 	REG_WRITE(ah, AR_RTC_RC, rst_flags);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
+
 	udelay(50);
 
 	REG_WRITE(ah, AR_RTC_RC, 0);
@@ -1005,6 +1036,8 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
 
 static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
 {
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
 		  AR_RTC_FORCE_WAKE_ON_INT);
 
@@ -1013,6 +1046,9 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
 
 	REG_WRITE(ah, AR_RTC_RESET, 0);
 
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
+
 	if (!AR_SREV_9300_20_OR_LATER(ah))
 		udelay(2);
 
@@ -1241,6 +1277,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
 	ath9k_hw_set_operating_mode(ah, ah->opmode);
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr));
 	REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(common->macaddr + 4)
 		  | macStaId1
@@ -1254,13 +1292,21 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 	REG_WRITE(ah, AR_ISR, ~0);
 	REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
 
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
+
 	r = ath9k_hw_rf_set_freq(ah, chan);
 	if (r)
 		return r;
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	for (i = 0; i < AR_NUM_DCU; i++)
 		REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);
 
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
+
 	ah->intr_txqs = 0;
 	for (i = 0; i < ah->caps.total_queues; i++)
 		ath9k_hw_resettxqueue(ah, i);
@@ -1300,9 +1346,14 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 	if (!ath9k_hw_init_cal(ah, chan))
 		return -EIO;
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	ath9k_hw_restore_chainmask(ah);
 	REG_WRITE(ah, AR_CFG_LED, saveLedState | AR_CFG_SCLK_32KHZ);
 
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
+
 	/*
 	 * For big endian systems turn on swapping for descriptors
 	 */
@@ -1766,6 +1817,8 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
 
 	ah->beacon_interval = beacon_period;
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	switch (ah->opmode) {
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_MONITOR:
@@ -1809,6 +1862,9 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
 	REG_WRITE(ah, AR_SWBA_PERIOD, TU_TO_USEC(beacon_period));
 	REG_WRITE(ah, AR_NDP_PERIOD, TU_TO_USEC(beacon_period));
 
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
+
 	beacon_period &= ~ATH9K_BEACON_ENA;
 	if (beacon_period & ATH9K_BEACON_RESET_TSF) {
 		ath9k_hw_reset_tsf(ah);
@@ -1825,6 +1881,8 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
 	struct ath9k_hw_capabilities *pCap = &ah->caps;
 	struct ath_common *common = ath9k_hw_common(ah);
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt));
 
 	REG_WRITE(ah, AR_BEACON_PERIOD,
@@ -1832,6 +1890,9 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
 	REG_WRITE(ah, AR_DMA_BEACON_PERIOD,
 		  TU_TO_USEC(bs->bs_intval & ATH9K_BEACON_PERIOD));
 
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
+
 	REG_RMW_FIELD(ah, AR_RSSI_THR,
 		      AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold);
 
@@ -1854,6 +1915,8 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
 	ath_print(common, ATH_DBG_BEACON, "beacon period %d\n", beaconintval);
 	ath_print(common, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod);
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	REG_WRITE(ah, AR_NEXT_DTIM,
 		  TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP));
 	REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP));
@@ -1873,6 +1936,9 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
 	REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval));
 	REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod));
 
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
+
 	REG_SET_BIT(ah, AR_TIMER_MODE,
 		    AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN |
 		    AR_DTIM_TIMER_EN);
@@ -2330,6 +2396,8 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
 {
 	u32 phybits;
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	REG_WRITE(ah, AR_RX_FILTER, bits);
 
 	phybits = 0;
@@ -2345,6 +2413,9 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
 	else
 		REG_WRITE(ah, AR_RXCFG,
 			  REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
 }
 EXPORT_SYMBOL(ath9k_hw_setrxfilter);
 
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index b54e857..7bbf502 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -25,6 +25,8 @@ static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah,
 		  ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask,
 		  ah->txurn_interrupt_mask);
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	REG_WRITE(ah, AR_IMR_S0,
 		  SM(ah->txok_interrupt_mask, AR_IMR_S0_QCU_TXOK)
 		  | SM(ah->txdesc_interrupt_mask, AR_IMR_S0_QCU_TXDESC));
@@ -35,6 +37,9 @@ static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah,
 	ah->imrs2_reg &= ~AR_IMR_S2_QCU_TXURN;
 	ah->imrs2_reg |= (ah->txurn_interrupt_mask & AR_IMR_S2_QCU_TXURN);
 	REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
 }
 
 u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q)
@@ -470,6 +475,8 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
 	} else
 		cwMin = qi->tqi_cwmin;
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	REG_WRITE(ah, AR_DLCL_IFS(q),
 		  SM(cwMin, AR_D_LCL_IFS_CWMIN) |
 		  SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) |
@@ -484,6 +491,8 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
 	REG_WRITE(ah, AR_DMISC(q),
 		  AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
 
+	REGWRITE_BUFFER_FLUSH(ah);
+
 	if (qi->tqi_cbrPeriod) {
 		REG_WRITE(ah, AR_QCBRCFG(q),
 			  SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |
@@ -499,6 +508,8 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
 			  AR_Q_RDYTIMECFG_EN);
 	}
 
+	REGWRITE_BUFFER_FLUSH(ah);
+
 	REG_WRITE(ah, AR_DCHNTIME(q),
 		  SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
 		  (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
@@ -516,6 +527,10 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
 			  REG_READ(ah, AR_DMISC(q)) |
 			  AR_D_MISC_POST_FR_BKOFF_DIS);
 	}
+
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
+
 	if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) {
 		REG_WRITE(ah, AR_DMISC(q),
 			  REG_READ(ah, AR_DMISC(q)) |
@@ -523,6 +538,8 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
 	}
 	switch (qi->tqi_type) {
 	case ATH9K_TX_QUEUE_BEACON:
+		ENABLE_REGWRITE_BUFFER(ah);
+
 		REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
 			  | AR_Q_MISC_FSP_DBA_GATED
 			  | AR_Q_MISC_BEACON_USE
@@ -533,6 +550,10 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
 			     AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
 			  | AR_D_MISC_BEACON_USE
 			  | AR_D_MISC_POST_FR_BKOFF_DIS);
+
+		REGWRITE_BUFFER_FLUSH(ah);
+		DISABLE_REGWRITE_BUFFER(ah);
+
 		/* cwmin and cwmax should be 0 for beacon queue */
 		if (AR_SREV_9300_20_OR_LATER(ah)) {
 			REG_WRITE(ah, AR_DLCL_IFS(q), SM(0, AR_D_LCL_IFS_CWMIN)
@@ -541,6 +562,8 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
 		}
 		break;
 	case ATH9K_TX_QUEUE_CAB:
+		ENABLE_REGWRITE_BUFFER(ah);
+
 		REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
 			  | AR_Q_MISC_FSP_DBA_GATED
 			  | AR_Q_MISC_CBR_INCR_DIS1
@@ -554,6 +577,10 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
 		REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
 			  | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
 			     AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
+
+		REGWRITE_BUFFER_FLUSH(ah);
+		DISABLE_REGWRITE_BUFFER(ah);
+
 		break;
 	case ATH9K_TX_QUEUE_PSPOLL:
 		REG_WRITE(ah, AR_QMISC(q),
-- 
1.7.0.5


^ permalink raw reply related

* [PATCH 08/10] ath9k_htc: Add dropped SKB count to debugfs
From: Sujith @ 2010-04-16  6:24 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless

Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
 drivers/net/wireless/ath/ath9k/hif_usb.c      |   13 +++++++++----
 drivers/net/wireless/ath/ath9k/htc.h          |    1 +
 drivers/net/wireless/ath/ath9k/htc_drv_main.c |    3 +++
 3 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index fe994e2..3091bb3 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -129,6 +129,7 @@ static void hif_usb_tx_cb(struct urb *urb)
 				TX_STAT_INC(skb_completed);
 			} else {
 				dev_kfree_skb_any(skb);
+				TX_STAT_INC(skb_dropped);
 			}
 		}
 
@@ -149,11 +150,15 @@ static void hif_usb_tx_cb(struct urb *urb)
 	}
 }
 
-static inline void ath9k_skb_queue_purge(struct sk_buff_head *list)
+static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev,
+					 struct sk_buff_head *list)
 {
 	struct sk_buff *skb;
-	while ((skb = __skb_dequeue(list)) != NULL)
+
+	while ((skb = __skb_dequeue(list)) != NULL) {
 		dev_kfree_skb_any(skb);
+		TX_STAT_INC(skb_dropped);
+	}
 }
 
 /* TX lock has to be taken */
@@ -214,7 +219,7 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev)
 	ret = usb_submit_urb(tx_buf->urb, GFP_ATOMIC);
 	if (ret) {
 		tx_buf->len = tx_buf->offset = 0;
-		ath9k_skb_queue_purge(&tx_buf->skb_queue);
+		ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
 		__skb_queue_head_init(&tx_buf->skb_queue);
 		list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf);
 		hif_dev->tx.tx_buf_cnt++;
@@ -281,7 +286,7 @@ static void hif_usb_stop(void *hif_handle, u8 pipe_id)
 	unsigned long flags;
 
 	spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
-	ath9k_skb_queue_purge(&hif_dev->tx.tx_skb_queue);
+	ath9k_skb_queue_purge(hif_dev, &hif_dev->tx.tx_skb_queue);
 	hif_dev->tx.tx_skb_cnt = 0;
 	hif_dev->tx.flags |= HIF_USB_TX_STOP;
 	spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index 78213fc..6a4614a 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -261,6 +261,7 @@ struct ath_tx_stats {
 	u32 buf_completed;
 	u32 skb_queued;
 	u32 skb_completed;
+	u32 skb_dropped;
 };
 
 struct ath_rx_stats {
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 2cea577..081f445 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -609,6 +609,9 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
 	len += snprintf(buf + len, sizeof(buf) - len,
 			"%20s : %10u\n", "SKBs completed",
 			priv->debug.tx_stats.skb_completed);
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "SKBs dropped",
+			priv->debug.tx_stats.skb_dropped);
 
 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
-- 
1.7.0.5


^ permalink raw reply related

* [PATCH 09/10] ath9k_htc: Handle WMI timeouts properly
From: Sujith @ 2010-04-16  6:24 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless

If a WMI command has timed out for some reason,
a late WMI response would end up updating the
response region of a new WMI request that has been
issued in the meantime.

Fix this race condition by dropping a WMI response
if a new WMI command has been issued.

Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
 drivers/net/wireless/ath/ath9k/wmi.c |   13 +++++++++++++
 drivers/net/wireless/ath/ath9k/wmi.h |    1 +
 2 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index 355e0db..afbf63d 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -204,6 +204,14 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
 		return;
 	}
 
+	/* Check if there has been a timeout. */
+	spin_lock(&wmi->wmi_lock);
+	if (cmd_id != wmi->last_cmd_id) {
+		spin_unlock(&wmi->wmi_lock);
+		goto free_skb;
+	}
+	spin_unlock(&wmi->wmi_lock);
+
 	/* WMI command response */
 	ath9k_wmi_rsp_callback(wmi, skb);
 
@@ -266,6 +274,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
 	struct sk_buff *skb;
 	u8 *data;
 	int time_left, ret = 0;
+	unsigned long flags;
 
 	if (!wmi)
 		return -EINVAL;
@@ -297,6 +306,10 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
 	if (ret)
 		goto out;
 
+	spin_lock_irqsave(&wmi->wmi_lock, flags);
+	wmi->last_cmd_id = cmd_id;
+	spin_unlock_irqrestore(&wmi->wmi_lock, flags);
+
 	time_left = wait_for_completion_timeout(&wmi->cmd_wait, timeout);
 	if (!time_left) {
 		ath_print(common, ATH_DBG_WMI,
diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h
index fd8c9c5..6113571 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.h
+++ b/drivers/net/wireless/ath/ath9k/wmi.h
@@ -97,6 +97,7 @@ struct wmi {
 	enum htc_endpoint_id ctrl_epid;
 	struct mutex op_mutex;
 	struct completion cmd_wait;
+	enum wmi_cmd_id last_cmd_id;
 	u16 tx_seq_id;
 	u8 *cmd_rsp_buf;
 	u32 cmd_rsp_len;
-- 
1.7.0.5


^ permalink raw reply related

* [PATCH 07/10] ath9k_htc: Remove GPIO set on unload
From: Sujith @ 2010-04-16  6:25 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless

There is no point in trying to set the LED pin
when the module is being unloaded. The target
would be reset anyway.

Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
 drivers/net/wireless/ath/ath9k/htc_drv_main.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 08a4a58..2cea577 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -960,7 +960,6 @@ void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
 	ath9k_unregister_led(&priv->tx_led);
 	ath9k_unregister_led(&priv->rx_led);
 	ath9k_unregister_led(&priv->radio_led);
-	ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
 }
 
 void ath9k_init_leds(struct ath9k_htc_priv *priv)
-- 
1.7.0.5


^ permalink raw reply related

* [PATCH 10/10] ath9k_htc: Fix sparse endian warnings
From: Sujith @ 2010-04-16  6:26 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless

This patch fixes a bunch of endian issues that
were exposed by sparse. It's a miracle that the driver
worked at all till now.

The Lord be praised.

Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
 drivers/net/wireless/ath/ath9k/htc.h            |   18 ++++++++--------
 drivers/net/wireless/ath/ath9k/htc_drv_beacon.c |    6 +++-
 drivers/net/wireless/ath/ath9k/htc_drv_main.c   |   14 +++++++-----
 drivers/net/wireless/ath/ath9k/htc_drv_txrx.c   |   11 ++-------
 drivers/net/wireless/ath/ath9k/htc_hst.c        |    8 +++---
 drivers/net/wireless/ath/ath9k/htc_hst.h        |   24 +++++++++++-----------
 drivers/net/wireless/ath/ath9k/mac.h            |   10 ++++----
 drivers/net/wireless/ath/ath9k/wmi.c            |    2 +-
 drivers/net/wireless/ath/ath9k/wmi.h            |   10 ++++----
 9 files changed, 51 insertions(+), 52 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index 6a4614a..c765ff4 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -124,13 +124,13 @@ struct ath9k_htc_cap_target {
 struct ath9k_htc_target_vif {
 	u8 index;
 	u8 des_bssid[ETH_ALEN];
-	enum htc_opmode opmode;
+	__be32 opmode;
 	u8 myaddr[ETH_ALEN];
 	u8 bssid[ETH_ALEN];
 	u32 flags;
 	u32 flags_ext;
 	u16 ps_sta;
-	u16 rtsthreshold;
+	__be16 rtsthreshold;
 	u8 ath_cap;
 	u8 node;
 	s8 mcast_rate;
@@ -151,7 +151,7 @@ struct ath9k_htc_target_sta {
 	u8 sta_index;
 	u8 vif_index;
 	u8 vif_sta;
-	u16 flags; /* ATH_HTC_STA_* */
+	__be16 flags; /* ATH_HTC_STA_* */
 	u16 htcap;
 	u8 valid;
 	u16 capinfo;
@@ -191,16 +191,16 @@ struct ath9k_htc_rate {
 struct ath9k_htc_target_rate {
 	u8 sta_index;
 	u8 isnew;
-	u32 capflags;
+	__be32 capflags;
 	struct ath9k_htc_rate rates;
 };
 
 struct ath9k_htc_target_stats {
-	u32 tx_shortretry;
-	u32 tx_longretry;
-	u32 tx_xretries;
-	u32 ht_txunaggr_xretry;
-	u32 ht_tx_xretries;
+	__be32 tx_shortretry;
+	__be32 tx_longretry;
+	__be32 tx_xretries;
+	__be32 ht_txunaggr_xretry;
+	__be32 ht_tx_xretries;
 } __packed;
 
 struct ath9k_htc_vif {
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index d104028..7cb55f5 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -26,7 +26,8 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
 	enum ath9k_int imask = 0;
 	int dtimperiod, dtimcount, sleepduration;
 	int cfpperiod, cfpcount, bmiss_timeout;
-	u32 nexttbtt = 0, intval, tsftu, htc_imask = 0;
+	u32 nexttbtt = 0, intval, tsftu;
+	__be32 htc_imask = 0;
 	u64 tsf;
 	int num_beacons, offset, dtim_dec_count, cfp_dec_count;
 	int ret;
@@ -142,7 +143,8 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
 {
 	struct ath_common *common = ath9k_hw_common(priv->ah);
 	enum ath9k_int imask = 0;
-	u32 nexttbtt, intval, htc_imask = 0;
+	u32 nexttbtt, intval;
+	__be32 htc_imask = 0;
 	int ret;
 	u8 cmd_rsp;
 
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 081f445..ec7bcc8 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -125,7 +125,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
 	bool fastcc = true;
 	struct ieee80211_channel *channel = hw->conf.channel;
 	enum htc_phymode mode;
-	u16 htc_mode;
+	__be16 htc_mode;
 	u8 cmd_rsp;
 	int ret;
 
@@ -378,7 +378,7 @@ static int ath9k_htc_init_rate(struct ath9k_htc_priv *priv,
 	priv->tgt_rate.sta_index = ista->index;
 	priv->tgt_rate.isnew = 1;
 	trate = priv->tgt_rate;
-	priv->tgt_rate.capflags = caps;
+	priv->tgt_rate.capflags = cpu_to_be32(caps);
 	trate.capflags = cpu_to_be32(caps);
 
 	WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate);
@@ -426,6 +426,7 @@ static void ath9k_htc_rc_update(struct ath9k_htc_priv *priv, bool is_cw40)
 	struct ath9k_htc_target_rate trate;
 	struct ath_common *common = ath9k_hw_common(priv->ah);
 	int ret;
+	u32 caps = be32_to_cpu(priv->tgt_rate.capflags);
 	u8 cmd_rsp;
 
 	memset(&trate, 0, sizeof(trate));
@@ -433,11 +434,12 @@ static void ath9k_htc_rc_update(struct ath9k_htc_priv *priv, bool is_cw40)
 	trate = priv->tgt_rate;
 
 	if (is_cw40)
-		priv->tgt_rate.capflags |= WLAN_RC_40_FLAG;
+		caps |= WLAN_RC_40_FLAG;
 	else
-		priv->tgt_rate.capflags &= ~WLAN_RC_40_FLAG;
+		caps &= ~WLAN_RC_40_FLAG;
 
-	trate.capflags = cpu_to_be32(priv->tgt_rate.capflags);
+	priv->tgt_rate.capflags = cpu_to_be32(caps);
+	trate.capflags = cpu_to_be32(caps);
 
 	WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate);
 	if (ret) {
@@ -1104,7 +1106,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
 	struct ath9k_channel *init_channel;
 	int ret = 0;
 	enum htc_phymode mode;
-	u16 htc_mode;
+	__be16 htc_mode;
 	u8 cmd_rsp;
 
 	ath_print(common, ATH_DBG_CONFIG,
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index 0a7cb30..2c3c510 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -530,7 +530,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
 			priv->ah->stats.avgbrssi = rxbuf->rxstatus.rs_rssi;
 	}
 
-	rx_status->mactime = rxbuf->rxstatus.rs_tstamp;
+	rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp);
 	rx_status->band = hw->conf.channel->band;
 	rx_status->freq = hw->conf.channel->center_freq;
 	rx_status->signal =  rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR;
@@ -634,13 +634,8 @@ void ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb,
 
 	rxstatus = (struct ath_htc_rx_status *)skb->data;
 
-	rxstatus->rs_tstamp = be64_to_cpu(rxstatus->rs_tstamp);
-	rxstatus->rs_datalen = be16_to_cpu(rxstatus->rs_datalen);
-	rxstatus->evm0 = be32_to_cpu(rxstatus->evm0);
-	rxstatus->evm1 = be32_to_cpu(rxstatus->evm1);
-	rxstatus->evm2 = be32_to_cpu(rxstatus->evm2);
-
-	if (rxstatus->rs_datalen - (len - HTC_RX_FRAME_HEADER_SIZE) != 0) {
+	if (be16_to_cpu(rxstatus->rs_datalen) -
+	    (len - HTC_RX_FRAME_HEADER_SIZE) != 0) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Corrupted RX data len, dropping "
 			  "(epid: %d, dlen: %d, skblen: %d)\n",
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
index 587d98e..f2dca25 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -368,7 +368,7 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle,
 	struct htc_frame_hdr *htc_hdr;
 	enum htc_endpoint_id epid;
 	struct htc_endpoint *endpoint;
-	u16 *msg_id;
+	__be16 *msg_id;
 
 	if (!htc_handle || !skb)
 		return;
@@ -388,14 +388,14 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle,
 
 		/* Handle trailer */
 		if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER) {
-			if (be32_to_cpu(*(u32 *) skb->data) == 0x00C60000)
+			if (be32_to_cpu(*(__be32 *) skb->data) == 0x00C60000)
 				/* Move past the Watchdog pattern */
 				htc_hdr = (struct htc_frame_hdr *)(skb->data + 4);
 		}
 
 		/* Get the message ID */
-		msg_id = (u16 *) ((void *) htc_hdr +
-					   sizeof(struct htc_frame_hdr));
+		msg_id = (__be16 *) ((void *) htc_hdr +
+				     sizeof(struct htc_frame_hdr));
 
 		/* Now process HTC messages */
 		switch (be16_to_cpu(*msg_id)) {
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h
index cd7048f..ea50ab0 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.h
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.h
@@ -59,20 +59,20 @@ enum htc_endpoint_id {
 struct htc_frame_hdr {
 	u8 endpoint_id;
 	u8 flags;
-	u16 payload_len;
+	__be16 payload_len;
 	u8 control[4];
 } __packed;
 
 struct htc_ready_msg {
-	u16 message_id;
-	u16 credits;
-	u16 credit_size;
+	__be16 message_id;
+	__be16 credits;
+	__be16 credit_size;
 	u8 max_endpoints;
 	u8 pad;
 } __packed;
 
 struct htc_config_pipe_msg {
-	u16 message_id;
+	__be16 message_id;
 	u8 pipe_id;
 	u8 credits;
 } __packed;
@@ -192,9 +192,9 @@ enum htc_service_group_ids{
 #define WMI_DATA_BK_SVC   MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 8)
 
 struct htc_conn_svc_msg {
-	u16 msg_id;
-	u16 service_id;
-	u16 con_flags;
+	__be16 msg_id;
+	__be16 service_id;
+	__be16 con_flags;
 	u8 dl_pipeid;
 	u8 ul_pipeid;
 	u8 svc_meta_len;
@@ -209,17 +209,17 @@ struct htc_conn_svc_msg {
 #define HTC_SERVICE_NO_MORE_EP   4
 
 struct htc_conn_svc_rspmsg {
-	u16 msg_id;
-	u16 service_id;
+	__be16 msg_id;
+	__be16 service_id;
 	u8 status;
 	u8 endpoint_id;
-	u16 max_msg_len;
+	__be16 max_msg_len;
 	u8 svc_meta_len;
 	u8 pad;
 } __packed;
 
 struct htc_comp_msg {
-	u16 msg_id;
+	__be16 msg_id;
 } __packed;
 
 int htc_init(struct htc_target *target);
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index 68eb8d0..66d0d5e 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -155,8 +155,8 @@ struct ath_rx_status {
 };
 
 struct ath_htc_rx_status {
-	u64 rs_tstamp;
-	u16 rs_datalen;
+	__be64 rs_tstamp;
+	__be16 rs_datalen;
 	u8 rs_status;
 	u8 rs_phyerr;
 	int8_t rs_rssi;
@@ -175,9 +175,9 @@ struct ath_htc_rx_status {
 	u8 rs_num_delims;
 	u8 rs_flags;
 	u8 rs_dummy;
-	u32 evm0;
-	u32 evm1;
-	u32 evm2;
+	__be32 evm0;
+	__be32 evm1;
+	__be32 evm2;
 };
 
 #define ATH9K_RXERR_CRC           0x01
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index afbf63d..dc6c6fc 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -129,7 +129,7 @@ void ath9k_wmi_tasklet(unsigned long data)
 	void *wmi_event;
 	unsigned long flags;
 #ifdef CONFIG_ATH9K_HTC_DEBUGFS
-	u32 txrate;
+	__be32 txrate;
 #endif
 
 	spin_lock_irqsave(&priv->wmi->wmi_lock, flags);
diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h
index 6113571..167e15c 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.h
+++ b/drivers/net/wireless/ath/ath9k/wmi.h
@@ -19,7 +19,7 @@
 
 
 struct wmi_event_txrate {
-	u32 txrate;
+	__be32 txrate;
 	struct {
 		u8 rssi_thresh;
 		u8 per;
@@ -27,8 +27,8 @@ struct wmi_event_txrate {
 } __packed;
 
 struct wmi_cmd_hdr {
-	u16 command_id;
-	u16 seq_no;
+	__be16 command_id;
+	__be16 seq_no;
 } __packed;
 
 struct wmi_swba {
@@ -87,8 +87,8 @@ enum wmi_event_id {
 #define MAX_CMD_NUMBER 62
 
 struct register_write {
-	u32 reg;
-	u32 val;
+	__be32 reg;
+	__be32 val;
 };
 
 struct wmi {
-- 
1.7.0.5


^ permalink raw reply related

* Re: Survey mode volunteers
From: Holger Schurig @ 2010-04-16  6:45 UTC (permalink / raw)
  To: Luis R. Rodriguez
  Cc: Luis Rodriguez, Anton Puolakka, Benoit PAPILLAULT,
	linux-wireless@vger.kernel.org
In-Reply-To: <20100414173044.GA2841@tux>

> Nice, it should be very similar for ath9k

... but please be aware that is is only about 20% of survey. Things that need 
to be addressed are the reporting of some kind of duty-cycle (how much is this 
channel occupied) and logic inside scanning to actually trigger this for 
channels other than the current one.

> BTW, one enhancement which we've
> been meanint to address but haven't had the time yet is to split noise
> floor per channel. This can be seen how its done on the legacy HAL with
> the code sprinkled with the ATH_NF_PER_CHAN ifdef.

Nice, knowing the noise-per-channel AND the channel occupation would be quite 
helpful to select the "best" channel.

-- 
http://www.holgerschurig.de

^ permalink raw reply

* Re: Survey mode volunteers
From: Holger Schurig @ 2010-04-16  6:47 UTC (permalink / raw)
  To: Anton Puolakka; +Cc: Luis Rodriguez, linux-wireless@vger.kernel.org
In-Reply-To: <0290AB2F0A8E124B9FFC144088A1A95609D6097401@EX-MBS04.nbl.local>

> We checked the most recent wireless-testing and saw no related patch on
> mac80211 yet. So, Holger, do You have one for that, too? Or anyone else on
> the mailing-list? Could You please share?

Sure. I thought I already posted that patch. This is a patch that
applied to compat-wireless 2010-03-23:

---------------
Subject: [PATCH] mac80211: sample survey implementation for mac80211_hwsim

This adds the survey function to both mac80211 itself and to mac80211_hwsim.
For the latter driver, we simply invent some noise level.

Signed-off-by: Holger Schurig <holgerschurig@gmail.com>

---
 drivers/net/wireless/mac80211_hwsim.c |   28 ++++++++++++++++++++++++++++
 include/net/mac80211.h                |    3 ++-
 net/mac80211/cfg.c                    |   12 ++++++++++++
 net/mac80211/driver-ops.h             |    9 +++++++++
 4 files changed, 51 insertions(+), 1 deletion(-)

--- compat-wireless-2010-03-15.orig/include/net/mac80211.h
+++ compat-wireless-2010-03-15/include/net/mac80211.h
@@ -1646,7 +1646,8 @@ struct ieee80211_ops {
 			    struct ieee80211_vif *vif,
 			    enum ieee80211_ampdu_mlme_action action,
 			    struct ieee80211_sta *sta, u16 tid, u16 *ssn);
-
+	int (*get_survey)(struct ieee80211_hw *hw, int idx,
+		struct survey_info *survey);
 	void (*rfkill_poll)(struct ieee80211_hw *hw);
 	void (*set_coverage_class)(struct ieee80211_hw *hw, u8 coverage_class);
 #ifdef CONFIG_NL80211_TESTMODE
--- compat-wireless-2010-03-15.orig/net/mac80211/cfg.c
+++ compat-wireless-2010-03-15/net/mac80211/cfg.c
@@ -412,6 +412,17 @@ static int ieee80211_dump_station(struct
 	return ret;
 }
 
+static int ieee80211_dump_survey(struct wiphy *wiphy, struct net_device *dev,
+				 int idx, struct survey_info *survey)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+	if (!local->ops->get_survey)
+		return -EOPNOTSUPP;
+
+	return drv_get_survey(local, idx, survey);
+}
+
 static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
 				 u8 *mac, struct station_info *sinfo)
 {
@@ -1476,6 +1487,7 @@ struct cfg80211_ops mac80211_config_ops
 	.change_station = ieee80211_change_station,
 	.get_station = ieee80211_get_station,
 	.dump_station = ieee80211_dump_station,
+	.dump_survey = ieee80211_dump_survey,
 #ifdef CONFIG_MAC80211_MESH
 	.add_mpath = ieee80211_add_mpath,
 	.del_mpath = ieee80211_del_mpath,
--- compat-wireless-2010-03-15.orig/net/mac80211/driver-ops.h
+++ compat-wireless-2010-03-15/net/mac80211/driver-ops.h
@@ -346,6 +346,15 @@ static inline int drv_ampdu_action(struc
 	return ret;
 }
 
+static inline int drv_get_survey(struct ieee80211_local *local, int idx,
+				struct survey_info *survey)
+{
+	int ret = -EOPNOTSUPP;
+	if (local->ops->get_survey)
+		ret = local->ops->get_survey(&local->hw, idx, survey);
+	/* trace_drv_get_survey(local, idx, survey, ret); */
+	return ret;
+}
 
 static inline void drv_rfkill_poll(struct ieee80211_local *local)
 {
--- compat-wireless-2010-03-15.orig/drivers/net/wireless/mac80211_hwsim.c
+++ compat-wireless-2010-03-15/drivers/net/wireless/mac80211_hwsim.c
@@ -828,6 +828,33 @@ static int mac80211_hwsim_conf_tx(
 	return 0;
 }
 
+static int mac80211_hwsim_get_survey(
+	struct ieee80211_hw *hw, int idx,
+	struct survey_info *survey)
+{
+	struct ieee80211_conf *conf = &hw->conf;
+
+	printk(KERN_DEBUG "%s:%s (idx=%d)\n",
+	       wiphy_name(hw->wiphy), __func__, idx);
+
+	if (idx != 0)
+		return -ENOENT;
+
+	/* Current channel */
+	survey->channel = conf->channel;
+
+	/*
+	 * Magically conjured noise level --- this is only ok for simulated hardware.
+	 *
+	 * A real driver which cannot determine the real channel noise MUST NOT
+	 * report any noise, especially not a magically conjured one :-)
+	 */
+	survey->filled = SURVEY_INFO_NOISE_DBM;
+	survey->noise = -92;
+
+	return 0;
+}
+
 #ifdef CONFIG_NL80211_TESTMODE
 /*
  * This section contains example code for using netlink
@@ -981,6 +1008,7 @@ static struct ieee80211_ops mac80211_hws
 	.sta_notify = mac80211_hwsim_sta_notify,
 	.set_tim = mac80211_hwsim_set_tim,
 	.conf_tx = mac80211_hwsim_conf_tx,
+	.get_survey = mac80211_hwsim_get_survey,
 	CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
 	.ampdu_action = mac80211_hwsim_ampdu_action,
 	.flush = mac80211_hwsim_flush,

^ permalink raw reply

* [RFC PATCH] mac80211: sta_cleanup timer handling
From: Juuso Oikarinen @ 2010-04-16  7:35 UTC (permalink / raw)
  To: linux-wireless

The sta_cleanup timer is used to expire frames in the sta structure ps_tx_buf 
-list. To perform this, the timer is executed periodically.

The timer is executed periodically, regardless if there are frames in the
buffer or not. As a result, the system gets periodically woken up for no
reason at all, wasting precious resources.

This patch proposes a simple fix. It prevent rescheduling the sta_cleanup
timer if on the particular invocation the ps_tx_buf buffers for all sta's 
were empty. On the TX path, the timer is restarted upon queueing frames to
those buffers.

Due to the way checking is performed, this approach will "leak" a few 
unnecessary invocations of the timer handler, but in the big picture those
do not matter.

Comments are appreciated.

Juuso Oikarinen (1):
  mac80211: Prevent running sta_cleanup timer unnecessarily

 net/mac80211/sta_info.c |   13 ++++++++++---
 net/mac80211/tx.c       |    7 +++++++
 2 files changed, 17 insertions(+), 3 deletions(-)


^ permalink raw reply

* [RFC PATCH] mac80211: Prevent running sta_cleanup timer unnecessarily
From: Juuso Oikarinen @ 2010-04-16  7:35 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <1271403308-23416-1-git-send-email-juuso.oikarinen@nokia.com>

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

* [RFC PATCHv3 1/2] mac80211: Determine dynamic PS timeout based on ps-qos network latency
From: Juuso Oikarinen @ 2010-04-16  9:14 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <1271409274-17162-1-git-send-email-juuso.oikarinen@nokia.com>

Determine the dynamic PS timeout based on the configured ps-qos network
latency. For backwards wext compatibility, allow the dynamic PS timeout
configured by the cfg80211 to overrule the automatically determined value.

Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
---
 include/net/mac80211.h |    5 ++++-
 net/mac80211/cfg.c     |    4 ++--
 net/mac80211/main.c    |    2 ++
 net/mac80211/mlme.c    |   14 ++++++++++++++
 4 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index dcf3c5f..243e4ab 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -661,6 +661,9 @@ enum ieee80211_smps_mode {
  * @dynamic_ps_timeout: The dynamic powersave timeout (in ms), see the
  *	powersave documentation below. This variable is valid only when
  *	the CONF_PS flag is set.
+ * @dynamic_ps_forced_timeout: The dynamic powersave timeout (in ms) configured
+ *	by cfg80211 (essentially, wext) If set, this value overrules the value
+ *	chosen by mac80211 based on ps qos network latency.
  *
  * @power_level: requested transmit power (in dBm)
  *
@@ -680,7 +683,7 @@ enum ieee80211_smps_mode {
  */
 struct ieee80211_conf {
 	u32 flags;
-	int power_level, dynamic_ps_timeout;
+	int power_level, dynamic_ps_timeout, dynamic_ps_forced_timeout;
 	int max_sleep_period;
 
 	u16 listen_interval;
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 7dd7cda..9a1a91c 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1388,11 +1388,11 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
 		return -EOPNOTSUPP;
 
 	if (enabled == sdata->u.mgd.powersave &&
-	    timeout == conf->dynamic_ps_timeout)
+	    timeout == conf->dynamic_ps_forced_timeout)
 		return 0;
 
 	sdata->u.mgd.powersave = enabled;
-	conf->dynamic_ps_timeout = timeout;
+	conf->dynamic_ps_forced_timeout = timeout;
 
 	/* no change, but if automatic follow powersave */
 	mutex_lock(&sdata->u.mgd.mtx);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 4afe851..ebcca0e 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -569,6 +569,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 
 	local->hw.conf.listen_interval = local->hw.max_listen_interval;
 
+	local->hw.conf.dynamic_ps_forced_timeout = -1;
+
 	result = sta_info_start(local);
 	if (result < 0)
 		goto fail_sta_info;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 35d8502..6402997 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -476,6 +476,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
 {
 	struct ieee80211_sub_if_data *sdata, *found = NULL;
 	int count = 0;
+	int timeout;
 
 	if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) {
 		local->ps_sdata = NULL;
@@ -509,6 +510,19 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
 		beaconint_us = ieee80211_tu_to_usec(
 					found->vif.bss_conf.beacon_int);
 
+		timeout = local->hw.conf.dynamic_ps_forced_timeout;
+		if (timeout < 0) {
+			if (latency <= 50000)
+				timeout = 300;
+			else if (latency <= 2000000000)
+				timeout = 100;
+			else if (latency <= 2100000000)
+				timeout = 50;
+			else
+				timeout = 0;
+		}
+		local->hw.conf.dynamic_ps_timeout = timeout;
+
 		if (beaconint_us > latency) {
 			local->ps_sdata = NULL;
 		} else {
-- 
1.6.3.3


^ permalink raw reply related

* [RFC PATCHv3 2/2] cfg80211: Remove default dynamic PS timeout value
From: Juuso Oikarinen @ 2010-04-16  9:14 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <1271409274-17162-1-git-send-email-juuso.oikarinen@nokia.com>

Now that the mac80211 is choosing dynamic ps timeouts based on the ps-qos
network latency configuration, configure a default value of -1 as the dynamic
ps timeout in cfg80211. This value allows the mac80211 to determine the value
to be used.

Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
---
 net/wireless/core.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/net/wireless/core.c b/net/wireless/core.c
index 6ac70c1..37d0e0a 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -705,7 +705,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
 			wdev->ps = true;
 		else
 			wdev->ps = false;
-		wdev->ps_timeout = 100;
+		/* allow mac80211 to determine the timeout */
+		wdev->ps_timeout = -1;
 		if (rdev->ops->set_power_mgmt)
 			if (rdev->ops->set_power_mgmt(wdev->wiphy, dev,
 						      wdev->ps,
-- 
1.6.3.3


^ permalink raw reply related

* [RFC PATCHv3 0/2] mac80211: cfg80211: dynamic ps timeout based on pm-qos
From: Juuso Oikarinen @ 2010-04-16  9:14 UTC (permalink / raw)
  To: linux-wireless

These patches propose a way to adjust the dynamic ps timeout in the mac80211
based on the pm-qos network latency value. This allows user space to influence
the level of power saving performed by the mac80211.

These patches will the current 100ms timeout for the default network
latency value (2000s), so that for non-adjusted pm-qos the functionality will
remain as it is currently. Dynamic ps is disabled for any larger latency
values, and a timeout of 300s is used for latency values smaller than 50ms.

v3 of these patches ad a 50s dynamic ps configuration.

As wext still has an interface to adjust the dynamic ps timeout from userspace,
the wext configuration will override the above, to remain backwards
compatible.

Comments are appreciated.

Juuso Oikarinen (2):
  mac80211: Determine dynamic PS timeout based on ps-qos network
    latency
  cfg80211: Remove default dynamic PS timeout value

 include/net/mac80211.h |    5 ++++-
 net/mac80211/cfg.c     |    4 ++--
 net/mac80211/main.c    |    2 ++
 net/mac80211/mlme.c    |   14 ++++++++++++++
 net/wireless/core.c    |    3 ++-
 5 files changed, 24 insertions(+), 4 deletions(-)


^ 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