Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [PATCH v2] mac80211: Add HT IE to IBSS beacons and probe responses.
From: Johannes Berg @ 2010-05-11 10:48 UTC (permalink / raw)
  To: Benoit Papillault; +Cc: linux-wireless
In-Reply-To: <4BE49BDD.8010803@free.fr>

On Sat, 2010-05-08 at 01:01 +0200, Benoit Papillault wrote:

> > It would be helpful if you were to rebase over my patch that adds the
> > channel type tracking.
> 
> Your patches are now in wireless-testing, so I am doing it at the moment.

Thanks.

> >> +	if (channel_type != NL80211_CHAN_NO_HT&&
> >> +	    sband->ht_cap.ht_supported) {
> >
> > You shouldn't be able to get here with an HT channel but !ht_supported,
> > no? Or is that to support the case where you have HT only on one band?
> 
> Good point. I think there are several cases here :
> 
> - a non-HT STA is joining an HT IBSS (we need to check 802.11n-2009 to 
> see how it's supposed to be handled). In this case channel_type could be 
> ht40+ and ht_supported = false

Hmm, true.

> - an HT STA is joining a non-HT IBSS. It's clear in this case that no HT 
> IE should be sent, which is catched by (channel_type != 
> NL80211_CHAN_NO_HT) condition.

Right.

> Could we examine those cases in a follow up patch?

Well what do we actually need to do then?

> >> +}
> >> +
> >> +int ieee80211_add_ht_info(u8 **ppos,
> >> +			  struct ieee80211_supported_band *sband,
> >> +			  struct ieee80211_channel *channel,
> >> +			  enum nl80211_channel_type channel_type)
> >
> > what's wrong with ieee80211_add_ht_ie()
> 
> Seems it's close to what I'm doing, but not entirely the same. I will 
> read it. If applicable, should I move ieee80211_add_ht_ie to util.c (and 
> declaration to ieee80211_i.h) then ?

Yes.

Also I just noticed that there's a TODO item in rx.c when we receive an
HT frame from a peer we don't know about yet. Not sure what to do there,
but you'll need to look at it.

johannes


^ permalink raw reply

* [PATCH 1/5] ath9k_htc: Lock sta_notify() callback
From: Sujith.Manoharan @ 2010-05-11 10:54 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless

Since ->sta_notify() can sleep, protect
the callback with a mutex.

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

diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 6c386da..9d371c1 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1452,6 +1452,8 @@ static void ath9k_htc_sta_notify(struct ieee80211_hw *hw,
 	struct ath9k_htc_priv *priv = hw->priv;
 	int ret;
 
+	mutex_lock(&priv->mutex);
+
 	switch (cmd) {
 	case STA_NOTIFY_ADD:
 		ret = ath9k_htc_add_station(priv, vif, sta);
@@ -1464,6 +1466,8 @@ static void ath9k_htc_sta_notify(struct ieee80211_hw *hw,
 	default:
 		break;
 	}
+
+	mutex_unlock(&priv->mutex);
 }
 
 static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue,
-- 
1.7.1


-- 

^ permalink raw reply related

* [PATCH 2/5] ath9k_htc: Allocate URBs properly
From: Sujith.Manoharan @ 2010-05-11 10:54 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless

The URBs have to be allocated before uploading
the firmware to the target. This is needed to process
the target ready message properly.

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

diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 74872ca..453cf56 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -735,6 +735,14 @@ err:
 	return -ENOMEM;
 }
 
+static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev)
+{
+	usb_kill_anchored_urbs(&hif_dev->regout_submitted);
+	ath9k_hif_usb_dealloc_reg_in_urb(hif_dev);
+	ath9k_hif_usb_dealloc_tx_urbs(hif_dev);
+	ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
+}
+
 static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev)
 {
 	int transfer, err;
@@ -794,14 +802,6 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev,
 		goto err_fw_req;
 	}
 
-	/* Download firmware */
-	ret = ath9k_hif_usb_download_fw(hif_dev);
-	if (ret) {
-		dev_err(&hif_dev->udev->dev,
-			"ath9k_htc: Firmware - %s download failed\n", fw_name);
-		goto err_fw_download;
-	}
-
 	/* Alloc URBs */
 	ret = ath9k_hif_usb_alloc_urbs(hif_dev);
 	if (ret) {
@@ -810,25 +810,25 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev,
 		goto err_urb;
 	}
 
+	/* Download firmware */
+	ret = ath9k_hif_usb_download_fw(hif_dev);
+	if (ret) {
+		dev_err(&hif_dev->udev->dev,
+			"ath9k_htc: Firmware - %s download failed\n", fw_name);
+		goto err_fw_download;
+	}
+
 	return 0;
 
-err_urb:
-	/* Nothing */
 err_fw_download:
+	ath9k_hif_usb_dealloc_urbs(hif_dev);
+err_urb:
 	release_firmware(hif_dev->firmware);
 err_fw_req:
 	hif_dev->firmware = NULL;
 	return ret;
 }
 
-static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev)
-{
-	usb_kill_anchored_urbs(&hif_dev->regout_submitted);
-	ath9k_hif_usb_dealloc_reg_in_urb(hif_dev);
-	ath9k_hif_usb_dealloc_tx_urbs(hif_dev);
-	ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
-}
-
 static void ath9k_hif_usb_dev_deinit(struct hif_device_usb *hif_dev)
 {
 	ath9k_hif_usb_dealloc_urbs(hif_dev);
-- 
1.7.1


-- 

^ permalink raw reply related

* [PATCH 3/5] ath9k_htc: Reorder HTC initialization
From: Sujith.Manoharan @ 2010-05-11 10:54 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless

The HTC state has to be setup before initializing
the target because the ready message could possibly
come before the control endpoints in HTC have been
identified.

Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
 drivers/net/wireless/ath/ath9k/hif_usb.c |   22 ++++++++--------
 drivers/net/wireless/ath/ath9k/htc_hst.c |   38 +++++++++++++++---------------
 drivers/net/wireless/ath/ath9k/htc_hst.h |    9 ++++---
 3 files changed, 35 insertions(+), 34 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 453cf56..46dc41a 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -859,21 +859,21 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
 #endif
 	usb_set_intfdata(interface, hif_dev);
 
+	hif_dev->htc_handle = ath9k_htc_hw_alloc(hif_dev, &hif_usb,
+						 &hif_dev->udev->dev);
+	if (hif_dev->htc_handle == NULL) {
+		ret = -ENOMEM;
+		goto err_htc_hw_alloc;
+	}
+
 	ret = ath9k_hif_usb_dev_init(hif_dev, fw_name);
 	if (ret) {
 		ret = -EINVAL;
 		goto err_hif_init_usb;
 	}
 
-	hif_dev->htc_handle = ath9k_htc_hw_alloc(hif_dev);
-	if (hif_dev->htc_handle == NULL) {
-		ret = -ENOMEM;
-		goto err_htc_hw_alloc;
-	}
-
-	ret = ath9k_htc_hw_init(&hif_usb, hif_dev->htc_handle, hif_dev,
-				&hif_dev->udev->dev, hif_dev->device_id,
-				ATH9K_HIF_USB);
+	ret = ath9k_htc_hw_init(hif_dev->htc_handle,
+				&hif_dev->udev->dev, hif_dev->device_id);
 	if (ret) {
 		ret = -EINVAL;
 		goto err_htc_hw_init;
@@ -884,10 +884,10 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
 	return 0;
 
 err_htc_hw_init:
-	ath9k_htc_hw_free(hif_dev->htc_handle);
-err_htc_hw_alloc:
 	ath9k_hif_usb_dev_deinit(hif_dev);
 err_hif_init_usb:
+	ath9k_htc_hw_free(hif_dev->htc_handle);
+err_htc_hw_alloc:
 	usb_set_intfdata(interface, NULL);
 	kfree(hif_dev);
 	usb_put_dev(udev);
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
index 7bf6ce1..2c8006a 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -425,29 +425,19 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle,
 	}
 }
 
-struct htc_target *ath9k_htc_hw_alloc(void *hif_handle)
+struct htc_target *ath9k_htc_hw_alloc(void *hif_handle,
+				      struct ath9k_htc_hif *hif,
+				      struct device *dev)
 {
+	struct htc_endpoint *endpoint;
 	struct htc_target *target;
 
 	target = kzalloc(sizeof(struct htc_target), GFP_KERNEL);
-	if (!target)
+	if (!target) {
 		printk(KERN_ERR "Unable to allocate memory for"
 			"target device\n");
-
-	return target;
-}
-
-void ath9k_htc_hw_free(struct htc_target *htc)
-{
-	kfree(htc);
-}
-
-int ath9k_htc_hw_init(struct ath9k_htc_hif *hif, struct htc_target *target,
-		      void *hif_handle, struct device *dev, u16 devid,
-		      enum ath9k_hif_transports transport)
-{
-	struct htc_endpoint *endpoint;
-	int err = 0;
+		return NULL;
+	}
 
 	init_completion(&target->target_wait);
 	init_completion(&target->cmd_wait);
@@ -461,8 +451,18 @@ int ath9k_htc_hw_init(struct ath9k_htc_hif *hif, struct htc_target *target,
 	endpoint->ul_pipeid = hif->control_ul_pipe;
 	endpoint->dl_pipeid = hif->control_dl_pipe;
 
-	err = ath9k_htc_probe_device(target, dev, devid);
-	if (err) {
+	return target;
+}
+
+void ath9k_htc_hw_free(struct htc_target *htc)
+{
+	kfree(htc);
+}
+
+int ath9k_htc_hw_init(struct htc_target *target,
+		      struct device *dev, u16 devid)
+{
+	if (ath9k_htc_probe_device(target, dev, devid)) {
 		printk(KERN_ERR "Failed to initialize the device\n");
 		return -ENODEV;
 	}
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h
index ea50ab0..d216c0f 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.h
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.h
@@ -236,11 +236,12 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle,
 void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,
 			       struct sk_buff *skb, bool txok);
 
-struct htc_target *ath9k_htc_hw_alloc(void *hif_handle);
+struct htc_target *ath9k_htc_hw_alloc(void *hif_handle,
+				      struct ath9k_htc_hif *hif,
+				      struct device *dev);
 void ath9k_htc_hw_free(struct htc_target *htc);
-int ath9k_htc_hw_init(struct ath9k_htc_hif *hif, struct htc_target *target,
-		      void *hif_handle, struct device *dev, u16 devid,
-		      enum ath9k_hif_transports transport);
+int ath9k_htc_hw_init(struct htc_target *target,
+		      struct device *dev, u16 devid);
 void ath9k_htc_hw_deinit(struct htc_target *target, bool hot_unplug);
 
 #endif /* HTC_HST_H */
-- 
1.7.1


-- 

^ permalink raw reply related

* [PATCH 4/5] ath9k_htc: Fix target ready race condition
From: Sujith.Manoharan @ 2010-05-11 10:54 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless

The ready message from the target could be processed
before the host HW init has completed. In this case,
htc_process_target_rdy() would assume the target has timed
out, when it hasn't. Fix this by checking if the target
has sent the ready message properly.

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

diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 17111fc..dc01507 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -81,6 +81,11 @@ static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv)
 {
 	int time_left;
 
+	if (atomic_read(&priv->htc->tgt_ready) > 0) {
+		atomic_dec(&priv->htc->tgt_ready);
+		return 0;
+	}
+
 	/* Firmware can take up to 50ms to get ready, to be safe use 1 second */
 	time_left = wait_for_completion_timeout(&priv->htc->target_wait, HZ);
 	if (!time_left) {
@@ -88,6 +93,8 @@ static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv)
 		return -ETIMEDOUT;
 	}
 
+	atomic_dec(&priv->htc->tgt_ready);
+
 	return 0;
 }
 
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
index 2c8006a..e86e172 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -95,6 +95,7 @@ static void htc_process_target_rdy(struct htc_target *target,
 	endpoint = &target->endpoint[ENDPOINT0];
 	endpoint->service_id = HTC_CTRL_RSVD_SVC;
 	endpoint->max_msglen = HTC_MAX_CONTROL_MESSAGE_LENGTH;
+	atomic_inc(&target->tgt_ready);
 	complete(&target->target_wait);
 }
 
@@ -451,6 +452,8 @@ struct htc_target *ath9k_htc_hw_alloc(void *hif_handle,
 	endpoint->ul_pipeid = hif->control_ul_pipe;
 	endpoint->dl_pipeid = hif->control_dl_pipe;
 
+	atomic_set(&target->tgt_ready, 0);
+
 	return target;
 }
 
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h
index d216c0f..4f1cdb0 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.h
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.h
@@ -147,6 +147,7 @@ struct htc_target {
 	u16 credits;
 	u16 credit_size;
 	u8 htc_flags;
+	atomic_t tgt_ready;
 };
 
 enum htc_msg_id {
-- 
1.7.1


-- 

^ permalink raw reply related

* [PATCH 5/5] ath9k_htc: Fix array overflow
From: Sujith.Manoharan @ 2010-05-11 10:55 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, error27

Use ENDPOINT_MAX instead of HST_ENDPOINT_MAX.
This fixes a stack corruption issue.

This is based on a patch sent by Dan Carpenter <error27@gmail.com>.

Cc: Dan Carpenter <error27@gmail.com>
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
 drivers/net/wireless/ath/ath9k/htc_hst.c |    8 ++++----
 drivers/net/wireless/ath/ath9k/htc_hst.h |    5 +----
 2 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
index e86e172..5cd5e2f 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -39,7 +39,7 @@ static struct htc_endpoint *get_next_avail_ep(struct htc_endpoint *endpoint)
 {
 	enum htc_endpoint_id avail_epid;
 
-	for (avail_epid = ENDPOINT_MAX; avail_epid > ENDPOINT0; avail_epid--)
+	for (avail_epid = (ENDPOINT_MAX - 1); avail_epid > ENDPOINT0; avail_epid--)
 		if (endpoint[avail_epid].service_id == 0)
 			return &endpoint[avail_epid];
 	return NULL;
@@ -117,7 +117,7 @@ static void htc_process_conn_rsp(struct htc_target *target,
 		max_msglen = be16_to_cpu(svc_rspmsg->max_msg_len);
 		endpoint = &target->endpoint[epid];
 
-		for (tepid = ENDPOINT_MAX; tepid > ENDPOINT0; tepid--) {
+		for (tepid = (ENDPOINT_MAX - 1); tepid > ENDPOINT0; tepid--) {
 			tmp_endpoint = &target->endpoint[tepid];
 			if (tmp_endpoint->service_id == service_id) {
 				tmp_endpoint->service_id = 0;
@@ -298,7 +298,7 @@ void htc_stop(struct htc_target *target)
 	enum htc_endpoint_id epid;
 	struct htc_endpoint *endpoint;
 
-	for (epid = ENDPOINT0; epid <= ENDPOINT_MAX; epid++) {
+	for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) {
 		endpoint = &target->endpoint[epid];
 		if (endpoint->service_id != 0)
 			target->hif->stop(target->hif_dev, endpoint->ul_pipeid);
@@ -310,7 +310,7 @@ void htc_start(struct htc_target *target)
 	enum htc_endpoint_id epid;
 	struct htc_endpoint *endpoint;
 
-	for (epid = ENDPOINT0; epid <= ENDPOINT_MAX; epid++) {
+	for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) {
 		endpoint = &target->endpoint[epid];
 		if (endpoint->service_id != 0)
 			target->hif->start(target->hif_dev,
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h
index 4f1cdb0..faba679 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.h
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.h
@@ -123,9 +123,6 @@ struct htc_endpoint {
 #define HTC_CONTROL_BUFFER_SIZE	\
 	(HTC_MAX_CONTROL_MESSAGE_LENGTH + sizeof(struct htc_frame_hdr))
 
-#define NUM_CONTROL_BUFFERS 8
-#define HST_ENDPOINT_MAX 8
-
 struct htc_control_buf {
 	struct htc_packet htc_pkt;
 	u8 buf[HTC_CONTROL_BUFFER_SIZE];
@@ -139,7 +136,7 @@ struct htc_target {
 	struct ath9k_htc_priv *drv_priv;
 	struct device *dev;
 	struct ath9k_htc_hif *hif;
-	struct htc_endpoint endpoint[HST_ENDPOINT_MAX];
+	struct htc_endpoint endpoint[ENDPOINT_MAX];
 	struct completion target_wait;
 	struct completion cmd_wait;
 	struct list_head list;
-- 
1.7.1


^ permalink raw reply related

* Re: [PATCH 1/5] ath9k_htc: Lock sta_notify() callback
From: Johannes Berg @ 2010-05-11 10:57 UTC (permalink / raw)
  To: Sujith.Manoharan; +Cc: linville, linux-wireless
In-Reply-To: <19433.14190.31764.174876@gargle.gargle.HOWL>

On Tue, 2010-05-11 at 16:24 +0530, Sujith.Manoharan@atheros.com wrote:
> Since ->sta_notify() can sleep, protect
> the callback with a mutex.

While this may be a correct change, it's not a correct description :)

You should be locking _data_, not _code_, and due to mac80211 the
callback cannot be invoked twice at the same time anyway.

johannes



^ permalink raw reply

* Re: [PATCH 1/5] ath9k_htc: Lock sta_notify() callback
From: Sujith.Manoharan @ 2010-05-11 11:17 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linville@tuxdriver.com, linux-wireless@vger.kernel.org
In-Reply-To: <1273575453.3669.55.camel@jlt3.sipsolutions.net>

Johannes Berg wrote:
> On Tue, 2010-05-11 at 16:24 +0530, Sujith.Manoharan@atheros.com wrote:
> > Since ->sta_notify() can sleep, protect
> > the callback with a mutex.
> 
> While this may be a correct change, it's not a correct description :)
> 
> You should be locking _data_, not _code_, and due to mac80211 the
> callback cannot be invoked twice at the same time anyway.

It protects all the binary data between lock and unlock. :-)

I encountered a problem with sta_notify() with a script doing
a load/scan/connect/unload cycle and NetworkManager also running,
doing its own scan/connect processing. And at some point,
ath9k_htc_remove_station() failed. Which led me to suspect overlapping
calls to sta_notify().

I do see sta_mtx being taken at all the places where sta_remove() is called
in mac80211, so am not sure how I managed to hit it.

Sujith

^ permalink raw reply

* Re: [PATCH 5/5] ath9k_htc: Fix array overflow
From: Dan Carpenter @ 2010-05-11 11:23 UTC (permalink / raw)
  To: Sujith.Manoharan; +Cc: linville, linux-wireless
In-Reply-To: <19433.14244.829946.555964@gargle.gargle.HOWL>

On Tue, May 11, 2010 at 04:25:32PM +0530, Sujith.Manoharan@atheros.com wrote:
> Use ENDPOINT_MAX instead of HST_ENDPOINT_MAX.
> This fixes a stack corruption issue.
> 
> This is based on a patch sent by Dan Carpenter <error27@gmail.com>.
> 

There is a bit missing.  The tmp_endpoint variable is always non-null 
here.  Can you just roll this into your patch?

Signed-off-by: Dan Carpenter <error27@gmail.com>

diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
index 6a062a3..02e8e0f 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -124,7 +124,7 @@ static void htc_process_conn_rsp(struct htc_target *target,
 			}
 		}
 
-		if (!tmp_endpoint)
+		if (tepid == ENDPOINT0)
 			return;
 
 		endpoint->service_id = service_id;

^ permalink raw reply related

* Re: [PATCH 5/5] ath9k_htc: Fix array overflow
From: Sujith.Manoharan @ 2010-05-11 11:30 UTC (permalink / raw)
  To: Dan Carpenter; +Cc: linville@tuxdriver.com, linux-wireless@vger.kernel.org
In-Reply-To: <20100511112332.GZ27064@bicker>

Dan Carpenter wrote:
> On Tue, May 11, 2010 at 04:25:32PM +0530, Sujith.Manoharan@atheros.com wrote:
> > Use ENDPOINT_MAX instead of HST_ENDPOINT_MAX.
> > This fixes a stack corruption issue.
> > 
> > This is based on a patch sent by Dan Carpenter <error27@gmail.com>.
> > 
> 
> There is a bit missing.  The tmp_endpoint variable is always non-null 
> here.  Can you just roll this into your patch?

Sure, patch on its way.

Sujith

^ permalink raw reply

* [PATCH v2 5/5] ath9k_htc: Fix array overflow
From: Sujith.Manoharan @ 2010-05-11 11:33 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, error27

Use ENDPOINT_MAX instead of HST_ENDPOINT_MAX.
This fixes a stack corruption issue.

This is based on a patch sent by Dan Carpenter <error27@gmail.com>.

Signed-off-by: Dan Carpenter <error27@gmail.com>
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
 drivers/net/wireless/ath/ath9k/htc_hst.c |   10 +++++-----
 drivers/net/wireless/ath/ath9k/htc_hst.h |    5 +----
 2 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
index e86e172..064397f 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -39,7 +39,7 @@ static struct htc_endpoint *get_next_avail_ep(struct htc_endpoint *endpoint)
 {
 	enum htc_endpoint_id avail_epid;
 
-	for (avail_epid = ENDPOINT_MAX; avail_epid > ENDPOINT0; avail_epid--)
+	for (avail_epid = (ENDPOINT_MAX - 1); avail_epid > ENDPOINT0; avail_epid--)
 		if (endpoint[avail_epid].service_id == 0)
 			return &endpoint[avail_epid];
 	return NULL;
@@ -117,7 +117,7 @@ static void htc_process_conn_rsp(struct htc_target *target,
 		max_msglen = be16_to_cpu(svc_rspmsg->max_msg_len);
 		endpoint = &target->endpoint[epid];
 
-		for (tepid = ENDPOINT_MAX; tepid > ENDPOINT0; tepid--) {
+		for (tepid = (ENDPOINT_MAX - 1); tepid > ENDPOINT0; tepid--) {
 			tmp_endpoint = &target->endpoint[tepid];
 			if (tmp_endpoint->service_id == service_id) {
 				tmp_endpoint->service_id = 0;
@@ -125,7 +125,7 @@ static void htc_process_conn_rsp(struct htc_target *target,
 			}
 		}
 
-		if (!tmp_endpoint)
+		if (tepid == ENDPOINT0)
 			return;
 
 		endpoint->service_id = service_id;
@@ -298,7 +298,7 @@ void htc_stop(struct htc_target *target)
 	enum htc_endpoint_id epid;
 	struct htc_endpoint *endpoint;
 
-	for (epid = ENDPOINT0; epid <= ENDPOINT_MAX; epid++) {
+	for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) {
 		endpoint = &target->endpoint[epid];
 		if (endpoint->service_id != 0)
 			target->hif->stop(target->hif_dev, endpoint->ul_pipeid);
@@ -310,7 +310,7 @@ void htc_start(struct htc_target *target)
 	enum htc_endpoint_id epid;
 	struct htc_endpoint *endpoint;
 
-	for (epid = ENDPOINT0; epid <= ENDPOINT_MAX; epid++) {
+	for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) {
 		endpoint = &target->endpoint[epid];
 		if (endpoint->service_id != 0)
 			target->hif->start(target->hif_dev,
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h
index 4f1cdb0..faba679 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.h
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.h
@@ -123,9 +123,6 @@ struct htc_endpoint {
 #define HTC_CONTROL_BUFFER_SIZE	\
 	(HTC_MAX_CONTROL_MESSAGE_LENGTH + sizeof(struct htc_frame_hdr))
 
-#define NUM_CONTROL_BUFFERS 8
-#define HST_ENDPOINT_MAX 8
-
 struct htc_control_buf {
 	struct htc_packet htc_pkt;
 	u8 buf[HTC_CONTROL_BUFFER_SIZE];
@@ -139,7 +136,7 @@ struct htc_target {
 	struct ath9k_htc_priv *drv_priv;
 	struct device *dev;
 	struct ath9k_htc_hif *hif;
-	struct htc_endpoint endpoint[HST_ENDPOINT_MAX];
+	struct htc_endpoint endpoint[ENDPOINT_MAX];
 	struct completion target_wait;
 	struct completion cmd_wait;
 	struct list_head list;
-- 
1.7.1


^ permalink raw reply related

* Re: Using wireless.kernel.org for Bluetooth documentation as well ?
From: John W. Linville @ 2010-05-11 13:37 UTC (permalink / raw)
  To: Luis R. Rodriguez
  Cc: linux-wireless, linux-bluetooth, linux-kernel, Marcel Holtmann,
	Johannes Berg
In-Reply-To: <k2z43e72e891005101245se32796ex47a17683ab05d8b5@mail.gmail.com>

On Mon, May 10, 2010 at 12:45:41PM -0700, Luis R. Rodriguez wrote:
> Today we have a wealth of information on 802.11 Linux wireless on
> http://wireless.kernel.org and I think the wiki model has worked
> wonders for us. I wanted to see what you thought of using the same
> site as a source of documentation for Bluetooth as well. We already
> have *some* Bluetooth documentation [1], and we could just point to
> the BlueZ pages for other docs but it doesn't seem to use a wiki and
> those google ads do blind my right eye.
> 
> Thoughts?
> 
> [1] http://wireless.kernel.org/en/users/Documentation/Bluetooth-coexistence
> [2] http://www.bluez.org

Personally, I have no objection.

John
-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply

* Re: [PATCH v2 1/2] mac80211: add offload channel switch support
From: Johannes Berg @ 2010-05-11 14:00 UTC (permalink / raw)
  To: Luis R. Rodriguez; +Cc: wey-yi.w.guy, linux-wireless
In-Reply-To: <x2z43e72e891005061458uabf4a6cxae3f5dd4067f0fbb@mail.gmail.com>

I think I'll adopt this patchset.

On Thu, 2010-05-06 at 14:58 -0700, Luis R. Rodriguez wrote:
> On Thu, May 6, 2010 at 8:25 AM,  <wey-yi.w.guy@intel.com> wrote:
> > From: Wey-Yi Guy <wey-yi.w.guy@intel.com>
> >
> > Adding support to offload the channel switch operation to driver if
> > driver can support the function.
> 
> Can you please reword this a little, maybe, "This adds support for a
> driver specific channel switch callback to be used by drivers which
> might require a finer grain control of the operation, typically if you
> have a respective firmware API call".

Easy enough.

> > The original approach, mac80211 utilize the mac_config callback function
> 
> Do you mean the mac80211 config() callback?

Yeah, mac_config (or rather iwl_mac_config) is the iwlwifi callback
function's name.

> > and set the CHANNEL_CHANGE flag which is difficult to separate the true
> > channel switch request from all the other channel changes condition;
> 
> Good point, but why is this needed? More below.

Mostly because we get much better timing with firmware assist.

> > with this offload approach, driver has more control on how to handle the
> > channel switch request from AP, also can provide more accurate timing
> > calculation
> 
> Is the current timing insufficient, and if so can you provide more
> details. If the real reason for this callback is not timing
> considerations is the real reason a firmware API thing? If so it
> doesn't hurt to just say that to avoid confusing developer in deciding
> which approach to take.

The current mac80211 approach is flawed, for various reasons which I
won't get into here, most of which we can fix. However, due to
regulatory concerns our firmware also wants to have more control, like
checking that the AP is beaconing again after a channel switch before
letting us transmit frames. Timing is obviously also a consideration,
since the firmware can re-enable transmission quickly after the channel
switch, regardless of the delay in processing the frame or the timer on
the host.

> > The drivers like to support the channel switch offloading function
> 
> Maybe: "The drivers that require a dedicated channel switch callback"...
> 
> > will have
> > to provide the mactime information (at least for mgmt and action frames)
> 
> Might be good to specify why, or at least in the documentation code below.

Actually, it's up to them. But if you implement the callback, you'll
want to know precisely when to expect the channel switch, so you'll want
to know when the frame that contained the CSA was received, which you
have to provide to mac80211 in the "mactime" rx status field.

> > + * @timestamp: value in microseconds of the 64-bit Time Synchronization
> > + *     Function (TSF) timer when the channel switch ie received.
> 
> Might be good to indicate this is derived from the rx status mactime
> and the beacon interval from the BSS.

It's not derived from the beacon interval, it's just the plain mactime
passed through. As such, where else would it come from? But yeah I guess
it could say that.

> > +/**
> > + * ieee80211_chswitch_done - Complete channel switch process
> > + * @vif: &struct ieee80211_vif pointer from the add_interface callback.
> > + * @is_seccess: make the channel switch successful or not
> 
> Typo, is_seccess, not success. Also, I don't get what this is for, can
> you elaborate?

Channel switching could fail, for instance if the AP doesn't show up on
the new channel. We don't have a way to handle that yet in mac80211, but
why not let it know.

> > + *
> > + * Complete the channel switch post-process: set the new operational channel
> > + * and wake up the suspended queues.
> 
> I don't get it.. who calls this and why, under what conditions?
> 
> If drivers have to call this once they are done with the channel
> switch operation callback then you might want to specify that and/or
> check for the existance of the op upon it being called and warn if it
> is not.

Can't check that since it's also called by mac80211 itself for software
implemented channel switch.

> > --- a/net/mac80211/mlme.c
> > +++ b/net/mac80211/mlme.c
> > @@ -340,7 +340,11 @@ static void ieee80211_chswitch_work(struct work_struct *work)
> >                goto out;
> >
> >        sdata->local->oper_channel = sdata->local->csa_channel;
> 
> If the new driver callback for channel switch failed this operation
> channel is still being set to the csa_channel. This *only* works
> because on the channels witch done routine you write below you
> overwrite the csa_channel variable to the existing operation channel.
> This seem rather hackish... if the channel switch callback failed why
> would we call the work to do the channel switch?

Not the callback failed .. the switch itself failed. Ap not showing up,
or advertising the wrong channel could be reasons.

> > -       ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL);
> > +       if (!sdata->local->ops->channel_switch) {
> > +               /* call "hw_config" only if doing sw channel switch */
> > +               ieee80211_hw_config(sdata->local,
> > +                       IEEE80211_CONF_CHANGE_CHANNEL);
> > +       }
> 
> Notice how the existing implementation also addresses quiescing in the
> timer, how will you address this with this new driver API?

The timer is not started when the callback exists. It can still be
deleted even if it was never started, right? What's the question?

> > +void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool is_success)
> > +{
> > +       struct ieee80211_sub_if_data *sdata;
> > +       struct ieee80211_if_managed *ifmgd;
> > +
> > +       sdata = vif_to_sdata(vif);
> > +       ifmgd = &sdata->u.mgd;
> > +
> > +       trace_api_chswitch_done(sdata, is_success);
> > +       if (!is_success)
> > +               sdata->local->csa_channel = sdata->local->oper_channel;
> 
> If this routine is to be called by drivers once they complete the
> channel switch operation why do we continue by queuing the channel
> switch work below?
> 
> > +
> > +       ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
> > +}
> > +EXPORT_SYMBOL(ieee80211_chswitch_done);


because that will complete the channel switch. I think you're getting
confused by the name, chswitch_work should be called chswitch_done_work
but blame that on Sujith :P

> > +       if (sdata->local->ops->channel_switch) {
> > +               /* use driver's channel switch callback */
> > +               struct ieee80211_channel_switch ch_switch;
> > +               memset(&ch_switch, 0, sizeof(ch_switch));
> > +               ch_switch.timestamp = timestamp;
> 
> If timestamp is 0 (when the driver does not set it) then this is all
> busted and I can see a few bug reports coming out due to it. These bug
> reports could be avoided if you check for the timestamp to be
> reasonable here and fail otherwise, in fact if the we know the channel
> switch operation is busted we may just want to disassociate given the
> DFS considerations are sensitive. What do you think?

I don't follow? The mactime only gets back to the driver, so if the
driver didn't report it properly it will get bogus values, mac80211
won't ever care. As such, in the unlikely event that the driver doesn't
need it, it wouldn't have to provide it, so any such checking doesn't
seem proper?

> I'd appreciate more feedback on the why this is being done. Its not
> clear to me how we are limited by the current implementation. 

Ok like I said -- timing is a big thing. Regulatory enforcement in our
firmware is another.

> If you
> have a firmware API need that is different and I think that should be
> made clear, but if you do need it we need to ensure both methods are
> properly documented and their different use cases outlined. I also
> think the way these method are split are rather hacky right now.

I'm not sure how you could split it better?

I'll fix up some docs and stuff and respin.

johannes


^ permalink raw reply

* [PATCH v3 1/2] mac80211: add offload channel switch support
From: Johannes Berg @ 2010-05-11 14:20 UTC (permalink / raw)
  To: wey-yi.w.guy, John Linville; +Cc: linux-wireless, Luis R. Rodriguez
In-Reply-To: <1273159552-5579-1-git-send-email-wey-yi.w.guy@intel.com>

This adds support for offloading the channel switch
operation to devices that support such, typically
by having specific firmware API for it. The reasons
for this could be that the firmware provides better
timing or that regulatory enforcement done by the
device requires special handling of CSAs.

In order to allow drivers to specify the timing to
the device, the new channel_switch callback will
pass through the received frame's mactime, where
available.

Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 include/net/mac80211.h      |   39 ++++++++++++++++++++++++++++++
 net/mac80211/driver-ops.h   |   11 ++++++++
 net/mac80211/driver-trace.h |   49 +++++++++++++++++++++++++++++++++++++
 net/mac80211/ieee80211_i.h  |    3 +-
 net/mac80211/mlme.c         |   56 +++++++++++++++++++++++++++++++++++++++---
 5 files changed, 153 insertions(+), 5 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 9448a5b..389e86a 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -712,6 +712,28 @@ struct ieee80211_conf {
 };
 
 /**
+ * struct ieee80211_channel_switch - holds the channel switch data
+ *
+ * The information provided in this structure is required for channel switch
+ * operation.
+ *
+ * @timestamp: value in microseconds of the 64-bit Time Synchronization
+ *	Function (TSF) timer when the frame containing the channel switch
+ *	announcement was received. This is simply the rx.mactime parameter
+ *	the driver passed into mac80211.
+ * @block_tx: Indicates whether transmission must be blocked before the
+ *	scheduled channel switch, as indicated by the AP.
+ * @channel: the new channel to switch to
+ * @count: the number of TBTT's until the channel switch event
+ */
+struct ieee80211_channel_switch {
+	u64 timestamp;
+	bool block_tx;
+	struct ieee80211_channel *channel;
+	u8 count;
+};
+
+/**
  * struct ieee80211_vif - per-interface data
  *
  * Data in this structure is continually present for driver
@@ -1631,6 +1653,11 @@ enum ieee80211_ampdu_mlme_action {
  * @flush: Flush all pending frames from the hardware queue, making sure
  *	that the hardware queues are empty. If the parameter @drop is set
  *	to %true, pending frames may be dropped. The callback can sleep.
+ *
+ * @channel_switch: Drivers that need (or want) to offload the channel
+ *	switch operation for CSAs received from the AP may implement this
+ *	callback. They must then call ieee80211_chswitch_done() to indicate
+ *	completion of the channel switch.
  */
 struct ieee80211_ops {
 	int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -1694,6 +1721,8 @@ struct ieee80211_ops {
 	int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len);
 #endif
 	void (*flush)(struct ieee80211_hw *hw, bool drop);
+	void (*channel_switch)(struct ieee80211_hw *hw,
+			       struct ieee80211_channel_switch *ch_switch);
 };
 
 /**
@@ -2444,6 +2473,16 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
 			       enum nl80211_cqm_rssi_threshold_event rssi_event,
 			       gfp_t gfp);
 
+/**
+ * ieee80211_chswitch_done - Complete channel switch process
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ * @success: make the channel switch successful or not
+ *
+ * Complete the channel switch post-process: set the new operational channel
+ * and wake up the suspended queues.
+ */
+void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success);
+
 /* Rate control API */
 
 /**
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 997008e..5662bb5 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -373,4 +373,15 @@ static inline void drv_flush(struct ieee80211_local *local, bool drop)
 	if (local->ops->flush)
 		local->ops->flush(&local->hw, drop);
 }
+
+static inline void drv_channel_switch(struct ieee80211_local *local,
+				     struct ieee80211_channel_switch *ch_switch)
+{
+	might_sleep();
+
+	local->ops->channel_switch(&local->hw, ch_switch);
+
+	trace_drv_channel_switch(local, ch_switch);
+}
+
 #endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index ce734b5..6a9b234 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -774,6 +774,34 @@ TRACE_EVENT(drv_flush,
 	)
 );
 
+TRACE_EVENT(drv_channel_switch,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_channel_switch *ch_switch),
+
+	TP_ARGS(local, ch_switch),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(u64, timestamp)
+		__field(bool, block_tx)
+		__field(u16, freq)
+		__field(u8, count)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->timestamp = ch_switch->timestamp;
+		__entry->block_tx = ch_switch->block_tx;
+		__entry->freq = ch_switch->channel->center_freq;
+		__entry->count = ch_switch->count;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT " new freq:%u count:%d",
+		LOCAL_PR_ARG, __entry->freq, __entry->count
+	)
+);
+
 /*
  * Tracing for API calls that drivers call.
  */
@@ -992,6 +1020,27 @@ TRACE_EVENT(api_sta_block_awake,
 	)
 );
 
+TRACE_EVENT(api_chswitch_done,
+	TP_PROTO(struct ieee80211_sub_if_data *sdata, bool success),
+
+	TP_ARGS(sdata, success),
+
+	TP_STRUCT__entry(
+		VIF_ENTRY
+		__field(bool, success)
+	),
+
+	TP_fast_assign(
+		VIF_ASSIGN;
+		__entry->success = success;
+	),
+
+	TP_printk(
+		VIF_PR_FMT " success=%d",
+		VIF_PR_ARG, __entry->success
+	)
+);
+
 /*
  * Tracing for internal functions
  * (which may also be called in response to driver calls)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 69e7f41..1c8e247 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -999,7 +999,8 @@ int ieee80211_max_network_latency(struct notifier_block *nb,
 				  unsigned long data, void *dummy);
 void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 				      struct ieee80211_channel_sw_ie *sw_elem,
-				      struct ieee80211_bss *bss);
+				      struct ieee80211_bss *bss,
+				      u64 timestamp);
 void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata);
 void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);
 
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 3093e46..b2f7f9f 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -342,7 +342,11 @@ static void ieee80211_chswitch_work(struct work_struct *work)
 		goto out;
 
 	sdata->local->oper_channel = sdata->local->csa_channel;
-	ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL);
+	if (!sdata->local->ops->channel_switch) {
+		/* call "hw_config" only if doing sw channel switch */
+		ieee80211_hw_config(sdata->local,
+			IEEE80211_CONF_CHANGE_CHANNEL);
+	}
 
 	/* XXX: shouldn't really modify cfg80211-owned data! */
 	ifmgd->associated->channel = sdata->local->oper_channel;
@@ -354,6 +358,29 @@ static void ieee80211_chswitch_work(struct work_struct *work)
 	mutex_unlock(&ifmgd->mtx);
 }
 
+void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
+{
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_if_managed *ifmgd;
+
+	sdata = vif_to_sdata(vif);
+	ifmgd = &sdata->u.mgd;
+
+	trace_api_chswitch_done(sdata, success);
+	if (!success) {
+		/*
+		 * If the channel switch was not successful, stay
+		 * around on the old channel. We currently lack
+		 * good handling of this situation, possibly we
+		 * should just drop the association.
+		 */
+		sdata->local->csa_channel = sdata->local->oper_channel;
+	}
+
+	ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
+}
+EXPORT_SYMBOL(ieee80211_chswitch_done);
+
 static void ieee80211_chswitch_timer(unsigned long data)
 {
 	struct ieee80211_sub_if_data *sdata =
@@ -370,7 +397,8 @@ static void ieee80211_chswitch_timer(unsigned long data)
 
 void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 				      struct ieee80211_channel_sw_ie *sw_elem,
-				      struct ieee80211_bss *bss)
+				      struct ieee80211_bss *bss,
+				      u64 timestamp)
 {
 	struct cfg80211_bss *cbss =
 		container_of((void *)bss, struct cfg80211_bss, priv);
@@ -398,6 +426,24 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 
 	sdata->local->csa_channel = new_ch;
 
+	if (sdata->local->ops->channel_switch) {
+		/* use driver's channel switch callback */
+		struct ieee80211_channel_switch ch_switch;
+		memset(&ch_switch, 0, sizeof(ch_switch));
+		ch_switch.timestamp = timestamp;
+		if (sw_elem->mode) {
+			ch_switch.block_tx = true;
+			ieee80211_stop_queues_by_reason(&sdata->local->hw,
+					IEEE80211_QUEUE_STOP_REASON_CSA);
+		}
+		ch_switch.channel = new_ch;
+		ch_switch.count = sw_elem->count;
+		ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
+		drv_channel_switch(sdata->local, &ch_switch);
+		return;
+	}
+
+	/* channel switch handled in software */
 	if (sw_elem->count <= 1) {
 		ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
 	} else {
@@ -1317,7 +1363,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 							ETH_ALEN) == 0)) {
 		struct ieee80211_channel_sw_ie *sw_elem =
 			(struct ieee80211_channel_sw_ie *)elems->ch_switch_elem;
-		ieee80211_sta_process_chanswitch(sdata, sw_elem, bss);
+		ieee80211_sta_process_chanswitch(sdata, sw_elem,
+						 bss, rx_status->mactime);
 	}
 }
 
@@ -1649,7 +1696,8 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 
 			ieee80211_sta_process_chanswitch(sdata,
 					&mgmt->u.action.u.chan_switch.sw_elem,
-					(void *)ifmgd->associated->priv);
+					(void *)ifmgd->associated->priv,
+					rx_status->mactime);
 			break;
 		}
 		mutex_unlock(&ifmgd->mtx);
-- 
1.7.0.5




^ permalink raw reply related

* [PATCH 2/4] ath9k: add debugfs files for reading/writing the rx and tx chainmask
From: Felix Fietkau @ 2010-05-11 15:23 UTC (permalink / raw)
  To: linux-wireless; +Cc: lrodriguez, linville
In-Reply-To: <1273591383-76696-1-git-send-email-nbd@openwrt.org>

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

diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 679257c..8d7c046 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -78,6 +78,90 @@ static const struct file_operations fops_debug = {
 
 #define DMA_BUF_LEN 1024
 
+static ssize_t read_file_tx_chainmask(struct file *file, char __user *user_buf,
+			     size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	char buf[32];
+	unsigned int len;
+
+	len = snprintf(buf, sizeof(buf), "0x%08x\n", common->tx_chainmask);
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_tx_chainmask(struct file *file, const char __user *user_buf,
+			     size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	unsigned long mask;
+	char buf[32];
+	ssize_t len;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EINVAL;
+
+	buf[len] = '\0';
+	if (strict_strtoul(buf, 0, &mask))
+		return -EINVAL;
+
+	common->tx_chainmask = mask;
+	sc->sc_ah->caps.tx_chainmask = mask;
+	return count;
+}
+
+static const struct file_operations fops_tx_chainmask = {
+	.read = read_file_tx_chainmask,
+	.write = write_file_tx_chainmask,
+	.open = ath9k_debugfs_open,
+	.owner = THIS_MODULE
+};
+
+
+static ssize_t read_file_rx_chainmask(struct file *file, char __user *user_buf,
+			     size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	char buf[32];
+	unsigned int len;
+
+	len = snprintf(buf, sizeof(buf), "0x%08x\n", common->rx_chainmask);
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_rx_chainmask(struct file *file, const char __user *user_buf,
+			     size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	unsigned long mask;
+	char buf[32];
+	ssize_t len;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EINVAL;
+
+	buf[len] = '\0';
+	if (strict_strtoul(buf, 0, &mask))
+		return -EINVAL;
+
+	common->rx_chainmask = mask;
+	sc->sc_ah->caps.rx_chainmask = mask;
+	return count;
+}
+
+static const struct file_operations fops_rx_chainmask = {
+	.read = read_file_rx_chainmask,
+	.write = write_file_rx_chainmask,
+	.open = ath9k_debugfs_open,
+	.owner = THIS_MODULE
+};
+
+
 static ssize_t read_file_dma(struct file *file, char __user *user_buf,
 			     size_t count, loff_t *ppos)
 {
@@ -754,6 +838,14 @@ int ath9k_init_debug(struct ath_hw *ah)
 			sc, &fops_recv))
 		goto err;
 
+	if (!debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR,
+			sc->debug.debugfs_phy, sc, &fops_rx_chainmask))
+		goto err;
+
+	if (!debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR,
+			sc->debug.debugfs_phy, sc, &fops_tx_chainmask))
+		goto err;
+
 	return 0;
 err:
 	ath9k_exit_debug(ah);
-- 
1.6.4.2


^ permalink raw reply related

* [PATCH 4/4] ath9k_hw: clean up EEPROM endian handling on AR9003
From: Felix Fietkau @ 2010-05-11 15:23 UTC (permalink / raw)
  To: linux-wireless; +Cc: lrodriguez, linville
In-Reply-To: <1273591383-76696-3-git-send-email-nbd@openwrt.org>

Remove the double swapping of the descriptor data structure, instead
keep it little-endian (native format of the eeprom data), and byteswap
on access.
This allows sparse to verify endian access to the eeprom struct.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/ar9003_eeprom.c |  174 ++++++++++-------------
 drivers/net/wireless/ath/ath9k/ar9003_eeprom.h |   10 +-
 2 files changed, 81 insertions(+), 103 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index 8a79550..23eb60e 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -38,6 +38,9 @@
 #define AR_SWITCH_TABLE_ALL (0xfff)
 #define AR_SWITCH_TABLE_ALL_S (0)
 
+#define LE16(x) __constant_cpu_to_le16(x)
+#define LE32(x) __constant_cpu_to_le32(x)
+
 static const struct ar9300_eeprom ar9300_default = {
 	.eepromVersion = 2,
 	.templateVersion = 2,
@@ -45,7 +48,7 @@ static const struct ar9300_eeprom ar9300_default = {
 	.custData = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 		     0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
 	.baseEepHeader = {
-		.regDmn = {0, 0x1f},
+		.regDmn = { LE16(0), LE16(0x1f) },
 		.txrxMask =  0x77, /* 4 bits tx and 4 bits rx */
 		.opCapFlags = {
 			.opFlags = AR9300_OPFLAGS_11G | AR9300_OPFLAGS_11A,
@@ -76,15 +79,15 @@ static const struct ar9300_eeprom ar9300_default = {
 	.modalHeader2G = {
 	/* ar9300_modal_eep_header  2g */
 		/* 4 idle,t1,t2,b(4 bits per setting) */
-		.antCtrlCommon = 0x110,
+		.antCtrlCommon = LE32(0x110),
 		/* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */
-		.antCtrlCommon2 = 0x22222,
+		.antCtrlCommon2 = LE32(0x22222),
 
 		/*
 		 * antCtrlChain[AR9300_MAX_CHAINS]; 6 idle, t, r,
 		 * rx1, rx12, b (2 bits each)
 		 */
-		.antCtrlChain = {0x150, 0x150, 0x150},
+		.antCtrlChain = { LE16(0x150), LE16(0x150), LE16(0x150) },
 
 		/*
 		 * xatten1DB[AR9300_MAX_CHAINS];  3 xatten1_db
@@ -287,12 +290,12 @@ static const struct ar9300_eeprom ar9300_default = {
 	 },
 	.modalHeader5G = {
 		/* 4 idle,t1,t2,b (4 bits per setting) */
-		.antCtrlCommon = 0x110,
+		.antCtrlCommon = LE32(0x110),
 		/* 4 ra1l1, ra2l1, ra1l2,ra2l2,ra12 */
-		.antCtrlCommon2 = 0x22222,
+		.antCtrlCommon2 = LE32(0x22222),
 		 /* antCtrlChain 6 idle, t,r,rx1,rx12,b (2 bits each) */
 		.antCtrlChain = {
-			0x000, 0x000, 0x000,
+			LE16(0x000), LE16(0x000), LE16(0x000),
 		},
 		 /* xatten1DB 3 xatten1_db for AR9280 (0xa20c/b20c 5:0) */
 		.xatten1DB = {0, 0, 0},
@@ -620,9 +623,9 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah,
 	case EEP_MAC_MSW:
 		return eep->macAddr[4] << 8 | eep->macAddr[5];
 	case EEP_REG_0:
-		return pBase->regDmn[0];
+		return le16_to_cpu(pBase->regDmn[0]);
 	case EEP_REG_1:
-		return pBase->regDmn[1];
+		return le16_to_cpu(pBase->regDmn[1]);
 	case EEP_OP_CAP:
 		return pBase->deviceCap;
 	case EEP_OP_MODE:
@@ -640,93 +643,80 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah,
 		/* Bit 4 is internal regulator flag */
 		return (pBase->featureEnable & 0x10) >> 4;
 	case EEP_SWREG:
-		return pBase->swreg;
+		return le32_to_cpu(pBase->swreg);
 	default:
 		return 0;
 	}
 }
 
-#ifdef __BIG_ENDIAN
-static void ar9300_swap_eeprom(struct ar9300_eeprom *eep)
+static bool ar9300_eeprom_read_byte(struct ath_common *common, int address,
+				    u8 *buffer)
 {
-	u32 dword;
-	u16 word;
-	int i;
-
-	word = swab16(eep->baseEepHeader.regDmn[0]);
-	eep->baseEepHeader.regDmn[0] = word;
-
-	word = swab16(eep->baseEepHeader.regDmn[1]);
-	eep->baseEepHeader.regDmn[1] = word;
-
-	dword = swab32(eep->baseEepHeader.swreg);
-	eep->baseEepHeader.swreg = dword;
+	u16 val;
 
-	dword = swab32(eep->modalHeader2G.antCtrlCommon);
-	eep->modalHeader2G.antCtrlCommon = dword;
+	if (unlikely(!ath9k_hw_nvram_read(common, address / 2, &val)))
+		return false;
 
-	dword = swab32(eep->modalHeader2G.antCtrlCommon2);
-	eep->modalHeader2G.antCtrlCommon2 = dword;
+	*buffer = (val >> (8 * (address % 2))) & 0xff;
+	return true;
+}
 
-	dword = swab32(eep->modalHeader5G.antCtrlCommon);
-	eep->modalHeader5G.antCtrlCommon = dword;
+static bool ar9300_eeprom_read_word(struct ath_common *common, int address,
+				    u8 *buffer)
+{
+	u16 val;
 
-	dword = swab32(eep->modalHeader5G.antCtrlCommon2);
-	eep->modalHeader5G.antCtrlCommon2 = dword;
+	if (unlikely(!ath9k_hw_nvram_read(common, address / 2, &val)))
+		return false;
 
-	for (i = 0; i < AR9300_MAX_CHAINS; i++) {
-		word = swab16(eep->modalHeader2G.antCtrlChain[i]);
-		eep->modalHeader2G.antCtrlChain[i] = word;
+	buffer[0] = val >> 8;
+	buffer[1] = val & 0xff;
 
-		word = swab16(eep->modalHeader5G.antCtrlChain[i]);
-		eep->modalHeader5G.antCtrlChain[i] = word;
-	}
+	return true;
 }
-#endif
 
-static bool ar9300_hw_read_eeprom(struct ath_hw *ah,
-				  long address, u8 *buffer, int many)
+static bool ar9300_read_eeprom(struct ath_hw *ah, int address, u8 *buffer,
+			       int count)
 {
-	int i;
-	u8 value[2];
-	unsigned long eepAddr;
-	unsigned long byteAddr;
-	u16 *svalue;
 	struct ath_common *common = ath9k_hw_common(ah);
+	int i;
 
-	if ((address < 0) || ((address + many) > AR9300_EEPROM_SIZE - 1)) {
+	if ((address < 0) || ((address + count) / 2 > AR9300_EEPROM_SIZE - 1)) {
 		ath_print(common, ATH_DBG_EEPROM,
 			  "eeprom address not in range\n");
 		return false;
 	}
 
-	for (i = 0; i < many; i++) {
-		eepAddr = (u16) (address + i) / 2;
-		byteAddr = (u16) (address + i) % 2;
-		svalue = (u16 *) value;
-		if (!ath9k_hw_nvram_read(common, eepAddr, svalue)) {
-			ath_print(common, ATH_DBG_EEPROM,
-				  "unable to read eeprom region\n");
-			return false;
-		}
-		*svalue = le16_to_cpu(*svalue);
-		buffer[i] = value[byteAddr];
+	/*
+	 * Since we're reading the bytes in reverse order from a little-endian
+	 * word stream, an even address means we only use the lower half of
+	 * the 16-bit word at that address
+	 */
+	if (address % 2 == 0) {
+		if (!ar9300_eeprom_read_byte(common, address--, buffer++))
+			goto error;
+
+		count--;
 	}
 
-	return true;
-}
+	for (i = 0; i < count / 2; i++) {
+		if (!ar9300_eeprom_read_word(common, address, buffer))
+			goto error;
 
-static bool ar9300_read_eeprom(struct ath_hw *ah,
-			       int address, u8 *buffer, int many)
-{
-	int it;
+		address -= 2;
+		buffer += 2;
+	}
+
+	if (count % 2)
+		if (!ar9300_eeprom_read_byte(common, address, buffer))
+			goto error;
 
-	for (it = 0; it < many; it++)
-		if (!ar9300_hw_read_eeprom(ah,
-					   (address - it),
-					   (buffer + it), 1))
-			return false;
 	return true;
+
+error:
+	ath_print(common, ATH_DBG_EEPROM,
+		  "unable to read eeprom region at offset %d\n", address);
+	return false;
 }
 
 static void ar9300_comp_hdr_unpack(u8 *best, int *code, int *reference,
@@ -927,30 +917,13 @@ fail:
  */
 static bool ath9k_hw_ar9300_fill_eeprom(struct ath_hw *ah)
 {
-	u8 *mptr = NULL;
-	int mdata_size;
+	u8 *mptr = (u8 *) &ah->eeprom.ar9300_eep;
 
-	mptr = (u8 *) &ah->eeprom.ar9300_eep;
-	mdata_size = sizeof(struct ar9300_eeprom);
+	if (ar9300_eeprom_restore_internal(ah, mptr,
+			sizeof(struct ar9300_eeprom)) < 0)
+		return false;
 
-	if (mptr && mdata_size > 0) {
-		/* At this point, mptr points to the eeprom data structure
-		 * in it's "default" state. If this is big endian, swap the
-		 * data structures back to "little endian"
-		 */
-		/* First swap, default to Little Endian */
-#ifdef __BIG_ENDIAN
-		ar9300_swap_eeprom((struct ar9300_eeprom *)mptr);
-#endif
-		if (ar9300_eeprom_restore_internal(ah, mptr, mdata_size) >= 0)
-			return true;
-
-		/* Second Swap, back to Big Endian */
-#ifdef __BIG_ENDIAN
-		ar9300_swap_eeprom((struct ar9300_eeprom *)mptr);
-#endif
-	}
-	return false;
+	return true;
 }
 
 /* XXX: review hardware docs */
@@ -998,21 +971,25 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz)
 static u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz)
 {
 	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+	__le32 val;
 
 	if (is2ghz)
-		return eep->modalHeader2G.antCtrlCommon;
+		val = eep->modalHeader2G.antCtrlCommon;
 	else
-		return eep->modalHeader5G.antCtrlCommon;
+		val = eep->modalHeader5G.antCtrlCommon;
+	return le32_to_cpu(val);
 }
 
 static u32 ar9003_hw_ant_ctrl_common_2_get(struct ath_hw *ah, bool is2ghz)
 {
 	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+	__le32 val;
 
 	if (is2ghz)
-		return eep->modalHeader2G.antCtrlCommon2;
+		val = eep->modalHeader2G.antCtrlCommon2;
 	else
-		return eep->modalHeader5G.antCtrlCommon2;
+		val = eep->modalHeader5G.antCtrlCommon2;
+	return le32_to_cpu(val);
 }
 
 static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah,
@@ -1020,15 +997,16 @@ static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah,
 					bool is2ghz)
 {
 	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+	__le16 val = 0;
 
 	if (chain >= 0 && chain < AR9300_MAX_CHAINS) {
 		if (is2ghz)
-			return eep->modalHeader2G.antCtrlChain[chain];
+			val = eep->modalHeader2G.antCtrlChain[chain];
 		else
-			return eep->modalHeader5G.antCtrlChain[chain];
+			val = eep->modalHeader5G.antCtrlChain[chain];
 	}
 
-	return 0;
+	return le16_to_cpu(val);
 }
 
 static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
index d8c0318..23fb353 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
@@ -169,7 +169,7 @@ enum CompressAlgorithm {
 };
 
 struct ar9300_base_eep_hdr {
-	u16 regDmn[2];
+	__le16 regDmn[2];
 	/* 4 bits tx and 4 bits rx */
 	u8 txrxMask;
 	struct eepFlags opCapFlags;
@@ -199,16 +199,16 @@ struct ar9300_base_eep_hdr {
 	u8 rxBandSelectGpio;
 	u8 txrxgain;
 	/* SW controlled internal regulator fields */
-	u32 swreg;
+	__le32 swreg;
 } __packed;
 
 struct ar9300_modal_eep_header {
 	/* 4 idle, t1, t2, b (4 bits per setting) */
-	u32 antCtrlCommon;
+	__le32 antCtrlCommon;
 	/* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */
-	u32 antCtrlCommon2;
+	__le32 antCtrlCommon2;
 	/* 6 idle, t, r, rx1, rx12, b (2 bits each) */
-	u16 antCtrlChain[AR9300_MAX_CHAINS];
+	__le16 antCtrlChain[AR9300_MAX_CHAINS];
 	/* 3 xatten1_db for AR9280 (0xa20c/b20c 5:0) */
 	u8 xatten1DB[AR9300_MAX_CHAINS];
 	/* 3  xatten1_margin for merlin (0xa20c/b20c 16:12 */
-- 
1.6.4.2


^ permalink raw reply related

* [PATCH 1/4] ath9k: use debugfs_remove_recursive() instead of keeping pointers to all entries
From: Felix Fietkau @ 2010-05-11 15:23 UTC (permalink / raw)
  To: linux-wireless; +Cc: lrodriguez, linville

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/debug.c |   55 +++++++++----------------------
 drivers/net/wireless/ath/ath9k/debug.h |    7 ----
 2 files changed, 16 insertions(+), 46 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 64e30cd..679257c 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -722,52 +722,36 @@ int ath9k_init_debug(struct ath_hw *ah)
 	sc->debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
 						      ath9k_debugfs_root);
 	if (!sc->debug.debugfs_phy)
-		goto err;
+		return -ENOMEM;
 
 #ifdef CONFIG_ATH_DEBUG
-	sc->debug.debugfs_debug = debugfs_create_file("debug",
-		S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug);
-	if (!sc->debug.debugfs_debug)
+	if (!debugfs_create_file("debug", S_IRUSR | S_IWUSR,
+			sc->debug.debugfs_phy, sc, &fops_debug))
 		goto err;
 #endif
 
-	sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUSR,
-				       sc->debug.debugfs_phy, sc, &fops_dma);
-	if (!sc->debug.debugfs_dma)
+	if (!debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy,
+			sc, &fops_dma))
 		goto err;
 
-	sc->debug.debugfs_interrupt = debugfs_create_file("interrupt",
-						     S_IRUSR,
-						     sc->debug.debugfs_phy,
-						     sc, &fops_interrupt);
-	if (!sc->debug.debugfs_interrupt)
+	if (!debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy,
+			sc, &fops_interrupt))
 		goto err;
 
-	sc->debug.debugfs_rcstat = debugfs_create_file("rcstat",
-						  S_IRUSR,
-						  sc->debug.debugfs_phy,
-						  sc, &fops_rcstat);
-	if (!sc->debug.debugfs_rcstat)
+	if (!debugfs_create_file("rcstat", S_IRUSR, sc->debug.debugfs_phy,
+			sc, &fops_rcstat))
 		goto err;
 
-	sc->debug.debugfs_wiphy = debugfs_create_file(
-		"wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc,
-		&fops_wiphy);
-	if (!sc->debug.debugfs_wiphy)
+	if (!debugfs_create_file("wiphy", S_IRUSR | S_IWUSR,
+			sc->debug.debugfs_phy, sc, &fops_wiphy))
 		goto err;
 
-	sc->debug.debugfs_xmit = debugfs_create_file("xmit",
-						     S_IRUSR,
-						     sc->debug.debugfs_phy,
-						     sc, &fops_xmit);
-	if (!sc->debug.debugfs_xmit)
+	if (!debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy,
+			sc, &fops_xmit))
 		goto err;
 
-	sc->debug.debugfs_recv = debugfs_create_file("recv",
-						     S_IRUSR,
-						     sc->debug.debugfs_phy,
-						     sc, &fops_recv);
-	if (!sc->debug.debugfs_recv)
+	if (!debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy,
+			sc, &fops_recv))
 		goto err;
 
 	return 0;
@@ -781,14 +765,7 @@ void ath9k_exit_debug(struct ath_hw *ah)
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath_softc *sc = (struct ath_softc *) common->priv;
 
-	debugfs_remove(sc->debug.debugfs_recv);
-	debugfs_remove(sc->debug.debugfs_xmit);
-	debugfs_remove(sc->debug.debugfs_wiphy);
-	debugfs_remove(sc->debug.debugfs_rcstat);
-	debugfs_remove(sc->debug.debugfs_interrupt);
-	debugfs_remove(sc->debug.debugfs_dma);
-	debugfs_remove(sc->debug.debugfs_debug);
-	debugfs_remove(sc->debug.debugfs_phy);
+	debugfs_remove_recursive(sc->debug.debugfs_phy);
 }
 
 int ath9k_debug_create_root(void)
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index c545960..7314360 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -153,13 +153,6 @@ struct ath_stats {
 
 struct ath9k_debug {
 	struct dentry *debugfs_phy;
-	struct dentry *debugfs_debug;
-	struct dentry *debugfs_dma;
-	struct dentry *debugfs_interrupt;
-	struct dentry *debugfs_rcstat;
-	struct dentry *debugfs_wiphy;
-	struct dentry *debugfs_xmit;
-	struct dentry *debugfs_recv;
 	struct ath_stats stats;
 };
 
-- 
1.6.4.2


^ permalink raw reply related

* [PATCH 3/4] ath9k: add debugfs files for reading/writing registers
From: Felix Fietkau @ 2010-05-11 15:23 UTC (permalink / raw)
  To: linux-wireless; +Cc: lrodriguez, linville
In-Reply-To: <1273591383-76696-2-git-send-email-nbd@openwrt.org>

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

diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 8d7c046..29898f8 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -795,6 +795,86 @@ static const struct file_operations fops_recv = {
 	.owner = THIS_MODULE
 };
 
+static ssize_t read_file_regidx(struct file *file, char __user *user_buf,
+                                size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	char buf[32];
+	unsigned int len;
+
+	len = snprintf(buf, sizeof(buf), "0x%08x\n", sc->debug.regidx);
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_regidx(struct file *file, const char __user *user_buf,
+			     size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	unsigned long regidx;
+	char buf[32];
+	ssize_t len;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EINVAL;
+
+	buf[len] = '\0';
+	if (strict_strtoul(buf, 0, &regidx))
+		return -EINVAL;
+
+	sc->debug.regidx = regidx;
+	return count;
+}
+
+static const struct file_operations fops_regidx = {
+	.read = read_file_regidx,
+	.write = write_file_regidx,
+	.open = ath9k_debugfs_open,
+	.owner = THIS_MODULE
+};
+
+static ssize_t read_file_regval(struct file *file, char __user *user_buf,
+			     size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	struct ath_hw *ah = sc->sc_ah;
+	char buf[32];
+	unsigned int len;
+	u32 regval;
+
+	regval = REG_READ_D(ah, sc->debug.regidx);
+	len = snprintf(buf, sizeof(buf), "0x%08x\n", regval);
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_regval(struct file *file, const char __user *user_buf,
+			     size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	struct ath_hw *ah = sc->sc_ah;
+	unsigned long regval;
+	char buf[32];
+	ssize_t len;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EINVAL;
+
+	buf[len] = '\0';
+	if (strict_strtoul(buf, 0, &regval))
+		return -EINVAL;
+
+	REG_WRITE_D(ah, sc->debug.regidx, regval);
+	return count;
+}
+
+static const struct file_operations fops_regval = {
+	.read = read_file_regval,
+	.write = write_file_regval,
+	.open = ath9k_debugfs_open,
+	.owner = THIS_MODULE
+};
+
 int ath9k_init_debug(struct ath_hw *ah)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
@@ -846,6 +926,15 @@ int ath9k_init_debug(struct ath_hw *ah)
 			sc->debug.debugfs_phy, sc, &fops_tx_chainmask))
 		goto err;
 
+	if (!debugfs_create_file("regidx", S_IRUSR | S_IWUSR,
+			sc->debug.debugfs_phy, sc, &fops_regidx))
+		goto err;
+
+	if (!debugfs_create_file("regval", S_IRUSR | S_IWUSR,
+			sc->debug.debugfs_phy, sc, &fops_regval))
+		goto err;
+
+	sc->debug.regidx = 0;
 	return 0;
 err:
 	ath9k_exit_debug(ah);
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 7314360..5147b87 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -153,6 +153,7 @@ struct ath_stats {
 
 struct ath9k_debug {
 	struct dentry *debugfs_phy;
+	u32 regidx;
 	struct ath_stats stats;
 };
 
-- 
1.6.4.2


^ permalink raw reply related

* Re: kernel BUG in iwl-agn-rs.c:2076, WAS: iwlagn + some accesspoint == hardlock
From: Christian Borntraeger @ 2010-05-11 15:50 UTC (permalink / raw)
  To: reinette chatre
  Cc: John W. Linville, NilsRadtkelkml@think-future.de,
	linux-kernel@vger.kernel.org, linux-wireless@vger.kernel.org
In-Reply-To: <1273163328.2226.2530.camel@rchatre-DESK>

Am Donnerstag 06 Mai 2010 18:28:48 schrieb reinette chatre:
> Below seven iwlwifi patches were added after rc4. If you are unable to
> bisect ... perhaps you can run a while by reverting more and more from
> this list?
> 
> f2fa1b015e9c199e45c836c769d94db595150731 iwlwifi: correct 6000 EEPROM regulatory address
> 88be026490ed89c2ffead81a52531fbac5507e01 iwlwifi: fix scan races
> 8b9fce77737ae9983f61ec56cd53f52fb738b2c7 iwlwifi: work around bogus active chains detection
> ece6444c2fe80dab679beb5f0d58b091f1933b00 iwlwifi: need check for valid qos packet before free
> de0f60ea94e132c858caa64a44b2012e1e8580b0 iwlwifi: avoid Tx queue memory allocation in interface down
> 04f2dec1c3d375c4072613880f28f43b66524876 iwlwifi: use consistent table for tx data collect
> dd48744964296b5713032ea1d66eb9e3d990e287 iwlwifi: fix DMA allocation warnings

Just to give you some feedback. Sometimes it takes a while until it crashes.
My hand made bisect is currently at two remaining patches:

de0f60ea94e132c858caa64a44b2012e1e8580b0
8b9fce77737ae9983f61ec56cd53f52fb738b2c7

reverting both solves my hard lockup. I will try to isolate the "bad" patch
but this takes some more days since I wont be in the "hazardous environment"
this week.

Christian

^ permalink raw reply

* Re: kernel BUG in iwl-agn-rs.c:2076, WAS: iwlagn + some accesspoint == hardlock
From: reinette chatre @ 2010-05-11 17:21 UTC (permalink / raw)
  To: Christian Borntraeger
  Cc: John W. Linville, NilsRadtkelkml@think-future.de,
	linux-kernel@vger.kernel.org, linux-wireless@vger.kernel.org
In-Reply-To: <201005111750.08533.borntraeger@de.ibm.com>

On Tue, 2010-05-11 at 08:50 -0700, Christian Borntraeger wrote:
> Am Donnerstag 06 Mai 2010 18:28:48 schrieb reinette chatre:
> > Below seven iwlwifi patches were added after rc4. If you are unable to
> > bisect ... perhaps you can run a while by reverting more and more from
> > this list?
> > 
> > f2fa1b015e9c199e45c836c769d94db595150731 iwlwifi: correct 6000 EEPROM regulatory address
> > 88be026490ed89c2ffead81a52531fbac5507e01 iwlwifi: fix scan races
> > 8b9fce77737ae9983f61ec56cd53f52fb738b2c7 iwlwifi: work around bogus active chains detection
> > ece6444c2fe80dab679beb5f0d58b091f1933b00 iwlwifi: need check for valid qos packet before free
> > de0f60ea94e132c858caa64a44b2012e1e8580b0 iwlwifi: avoid Tx queue memory allocation in interface down
> > 04f2dec1c3d375c4072613880f28f43b66524876 iwlwifi: use consistent table for tx data collect
> > dd48744964296b5713032ea1d66eb9e3d990e287 iwlwifi: fix DMA allocation warnings
> 
> Just to give you some feedback. Sometimes it takes a while until it crashes.
> My hand made bisect is currently at two remaining patches:
> 
> de0f60ea94e132c858caa64a44b2012e1e8580b0
> 8b9fce77737ae9983f61ec56cd53f52fb738b2c7
> 
> reverting both solves my hard lockup. I will try to isolate the "bad" patch
> but this takes some more days since I wont be in the "hazardous environment"
> this week.

Thank you for digging into this. It will be very helpful it you can get
us a trace of the crash - any chance that netconsole may work?

Reinette



^ permalink raw reply

* [PATCH V3] mac80211: fix paged defragmentation
From: Abhijeet Kolekar @ 2010-05-11 18:22 UTC (permalink / raw)
  To: linux-wireless; +Cc: yi.zhu, Abhijeet Kolekar

Paged RX skb patch broke the defragmentation. We need to read hdr again
after linearization.

It fixes following bug
http://bugzilla.intellinuxwireless.org/show_bug.cgi?id=2194

Signed-off-by: Zhu, Yi <yi.zhu@intel.com>
Signed-off-by: Abhijeet Kolekar <abhijeet.kolekar@intel.com>
---
v2: Changed hdr reading.
v3: Added more comments.
 net/mac80211/rx.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 9a08f2c..6e2a7bc 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1253,6 +1253,12 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
 	if (skb_linearize(rx->skb))
 		return RX_DROP_UNUSABLE;
 
+	/*
+	 *  skb_linearize() might change the skb->data and
+	 *  previously cached variables (in this case, hdr) need to
+	 *  be refreshed with the new data.
+	 */
+	hdr = (struct ieee80211_hdr *)rx->skb->data;
 	seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
 
 	if (frag == 0) {
-- 
1.6.3.3


^ permalink raw reply related

* Re: [RFC PATCH 1/2] mac80211: Add nl80211 antenna configuration
From: Luis R. Rodriguez @ 2010-05-11 18:14 UTC (permalink / raw)
  To: Bruno Randolf; +Cc: johannes, linville, linux-wireless, holgerschurig
In-Reply-To: <20100511083900.28289.43864.stgit@tt-desk>

On Tue, May 11, 2010 at 1:39 AM, Bruno Randolf <br1@einfach.org> wrote:

Subject should be for cfg80211, not mac80211. In fact can you submit
the mac80211 stuff in a separate secondary patch? Some more comments
below.

> Allow setting TX and RX antenna configuration via nl80211/cfg80211.

I think we should call this TX / RX chainmask given that with 802.11n
hardware this is what this is called.

> The antenna configuration is defined as a bitmap of allowed antennas. This
> bitmap is 8 bit at the moment, each bit representing one antenna.

If you use chainmask for this instead of 'antenna configuration' the
wording would be something like:

The chainmask is defined as a bitmap of chain configurations used for TX/RX. The
bitmap allows for configuring up to up to 4 chains for both TX and RX,
4 bits for each TX chain, 4 bits for each RX chain.

> If multiple
> antennas are selected, the driver may use diversity for receive and transmit.

For 802.11n this is called "selection diversity" but typically just
referred to as "diversity", for legacy this is called "antenna
diversity". It may be good to elaborate how selection diversity or
antenna diversity might be enabled, ie, will this be another command,
or what. I think for legacy another command makes sense, and it may be
possible for us to use the same command for enabling selection
diversity, I am not sure if we can fine tune the diversity algorithm
at this time, I will have to review this and get back to you.

> This allows for a simple, yet flexible configuration interface for antennas,
> while drivers may reject configurations they cannot support.

:) !

  Luis

^ permalink raw reply

* Re: [PATCH V3] mac80211: fix paged defragmentation
From: John W. Linville @ 2010-05-11 18:14 UTC (permalink / raw)
  To: Abhijeet Kolekar; +Cc: linux-wireless, yi.zhu
In-Reply-To: <1273602131-9188-1-git-send-email-abhijeet.kolekar@intel.com>

On Tue, May 11, 2010 at 11:22:11AM -0700, Abhijeet Kolekar wrote:
> Paged RX skb patch broke the defragmentation. We need to read hdr again
> after linearization.
> 
> It fixes following bug
> http://bugzilla.intellinuxwireless.org/show_bug.cgi?id=2194
> 
> Signed-off-by: Zhu, Yi <yi.zhu@intel.com>
> Signed-off-by: Abhijeet Kolekar <abhijeet.kolekar@intel.com>
> ---
> v2: Changed hdr reading.
> v3: Added more comments.
>  net/mac80211/rx.c |    6 ++++++
>  1 files changed, 6 insertions(+), 0 deletions(-)
> 
> diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
> index 9a08f2c..6e2a7bc 100644
> --- a/net/mac80211/rx.c
> +++ b/net/mac80211/rx.c
> @@ -1253,6 +1253,12 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
>  	if (skb_linearize(rx->skb))
>  		return RX_DROP_UNUSABLE;
>  
> +	/*
> +	 *  skb_linearize() might change the skb->data and
> +	 *  previously cached variables (in this case, hdr) need to
> +	 *  be refreshed with the new data.
> +	 */
> +	hdr = (struct ieee80211_hdr *)rx->skb->data;
>  	seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
>  
>  	if (frag == 0) {

And what about making sure the compiler doesn't optimize this away?

John
-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply

* Re: [PATCH 2/4] ath9k: add debugfs files for reading/writing the rx and tx chainmask
From: Luis R. Rodriguez @ 2010-05-11 18:15 UTC (permalink / raw)
  To: Felix Fietkau; +Cc: linux-wireless, linville
In-Reply-To: <1273591383-76696-2-git-send-email-nbd@openwrt.org>

On Tue, May 11, 2010 at 8:23 AM, Felix Fietkau <nbd@openwrt.org> wrote:
> Signed-off-by: Felix Fietkau <nbd@openwrt.org>

How about we use bruno's patch instead and we help review it for
802.11n? Then this would not be needed?

  Luis

^ permalink raw reply

* Re: [RFC PATCH 0/2] mac80211: antenna configuration
From: Luis R. Rodriguez @ 2010-05-11 18:17 UTC (permalink / raw)
  To: Bruno Randolf; +Cc: Johannes Berg, linville, linux-wireless, holgerschurig
In-Reply-To: <201005111834.36879.br1@einfach.org>

On Tue, May 11, 2010 at 2:34 AM, Bruno Randolf <br1@einfach.org> wrote:
> On Tuesday 11 May 2010 17:53:19 you wrote:
>> On Tue, 2010-05-11 at 17:38 +0900, Bruno Randolf wrote:
>> > i have followed holger schurig's suggestion to use a bitmap for allowed
>> > antennas. when multiple antennas are selected in the bitmap, the driver
>> > may use diversity. i think that this allows for the most flexible, yet
>> > simple configuration of antennas, and drivers can just reject
>> > configurations they cannot support. i hope that this will also be
>> > generic enough for 802.11n with multiple antennas
>>
>> Not sure ... 11n has antennas and chains, but people mix them up
>> frequently. Does this API even make sense for 11n? Use cases? Should it
>> be about *antennas*, or about *chains*?
>
> thanks for the review! i'll resend tomorrow.
>
> i personally don't know about 802.11n - and what i need is about *antennas* :)

I figured, let us help you with the 11n review.

  Luis

^ 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