* Re: [PATCH 09/29] mwl8k: remove usage of deprecated radio_enabled
From: Johannes Berg @ 2009-08-18 7:27 UTC (permalink / raw)
To: Lennert Buytenhek; +Cc: linville, linux-wireless
In-Reply-To: <20090818035220.GN18639@mail.wantstofly.org>
[-- Attachment #1: Type: text/plain, Size: 895 bytes --]
On Tue, 2009-08-18 at 05:52 +0200, Lennert Buytenhek wrote:
> Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
> ---
> drivers/net/wireless/mwl8k.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
> index 9f54204..3a201a2 100644
> --- a/drivers/net/wireless/mwl8k.c
> +++ b/drivers/net/wireless/mwl8k.c
> @@ -2935,7 +2935,7 @@ static int mwl8k_config_wt(struct work_struct *wt)
> struct mwl8k_priv *priv = hw->priv;
> int rc = 0;
>
> - if (!conf->radio_enabled) {
> + if (conf->flags & IEEE80211_CONF_IDLE) {
Ok, I thought about doing this but wasn't sure it would work -- you can
still accept channel changing commands while the radio is off, for
instance?
Anyway, this clashes with the removal of this chunk of code, which
should then just not happen.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [PATCH 10/29] mwl8k: fix mwl8k_configure_filter() parameter lifetime issue
From: Johannes Berg @ 2009-08-18 7:23 UTC (permalink / raw)
To: Lennert Buytenhek; +Cc: linville, linux-wireless
In-Reply-To: <20090818040039.GA4116@mail.wantstofly.org>
[-- Attachment #1: Type: text/plain, Size: 527 bytes --]
On Tue, 2009-08-18 at 06:00 +0200, Lennert Buytenhek wrote:
> This will clash with:
>
> http://article.gmane.org/gmane.linux.kernel.wireless.general/38141
>
> But that is easy to fix up. (The easiest would probably be to not
> apply the mwl8k part of that patch, and I'll send a followup patch
> to implement ->prepare_multicast() for mwl8k.)
It's not quite that easy because that patch changes the arguments to the
functions so the multicast list is no longer available in
->configure_filter().
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [PATCH v4 32/34] wireless: make mac80211 select cfg80211
From: Johannes Berg @ 2009-08-18 7:15 UTC (permalink / raw)
To: Luis R. Rodriguez
Cc: Luis Rodriguez, linville@tuxdriver.com,
linux-wireless@vger.kernel.org, Larry.Finger@lwfinger.net
In-Reply-To: <20090818003550.GG15363@mosca>
[-- Attachment #1: Type: text/plain, Size: 599 bytes --]
On Mon, 2009-08-17 at 17:35 -0700, Luis R. Rodriguez wrote:
> From: Luis R. Rodriguez <lrodriguez@atheros.com>
> Subject: [PATCH] wireless: make mac80211 select cfg80211
>
> This lets us keep mac80211 on the menu map even if cfg80211
> is not enabled. We now remove that pesky comment about this.
> menuconfig RFKILL
> tristate "RF switch subsystem support"
> + depends on CFG80211 || !CFG80211
That's backwards.
Now you can still have CFG80211=y and RFKILL=m. And RFKILL really
shouldn't depend on one of its users anyway.
Just leave it the way it is please.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* [PATCH] ath9k: Fix TX poll cancelling
From: Sujith @ 2009-08-18 5:21 UTC (permalink / raw)
To: linville; +Cc: linux-wireless
In ath9k_stop(), tx_complete_work was being cancelled twice.
This patch fixes it. Also, locking sc->mutex should be done
at the beginning.
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
drivers/net/wireless/ath/ath9k/main.c | 7 +++----
1 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 3e09b9a..c454d19 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -2105,6 +2105,8 @@ static void ath9k_stop(struct ieee80211_hw *hw)
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ mutex_lock(&sc->mutex);
+
aphy->state = ATH_WIPHY_INACTIVE;
cancel_delayed_work_sync(&sc->ath_led_blink_work);
@@ -2117,13 +2119,10 @@ static void ath9k_stop(struct ieee80211_hw *hw)
if (sc->sc_flags & SC_OP_INVALID) {
DPRINTF(sc, ATH_DBG_ANY, "Device not present\n");
+ mutex_unlock(&sc->mutex);
return;
}
- mutex_lock(&sc->mutex);
-
- cancel_delayed_work_sync(&sc->tx_complete_work);
-
if (ath9k_wiphy_started(sc)) {
mutex_unlock(&sc->mutex);
return; /* another wiphy still in use */
--
1.6.4
^ permalink raw reply related
* Re: [PATCH 10/29] mwl8k: fix mwl8k_configure_filter() parameter lifetime issue
From: Lennert Buytenhek @ 2009-08-18 4:00 UTC (permalink / raw)
To: linville, linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20090818035233.GO18639@mail.wantstofly.org>
On Tue, Aug 18, 2009 at 05:52:33AM +0200, Lennert Buytenhek wrote:
> mwl8k_configure_filter() passes pointers to total_flags and the
> multicast address list to a workqueue function, while there is no
> guarantee that those pointers will still be valid by the time the
> workqueue function runs.
>
> Solve this by passing total_flags by value, and by passing an
> already built multicast address setup command packet to the workqueue
> function so that we don't have to look at the multicast address list
> itself outside of mwl8k_configure_filter().
>
> Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
This will clash with:
http://article.gmane.org/gmane.linux.kernel.wireless.general/38141
But that is easy to fix up. (The easiest would probably be to not
apply the mwl8k part of that patch, and I'll send a followup patch
to implement ->prepare_multicast() for mwl8k.)
^ permalink raw reply
* [PATCH 29/29] MAINTAINERS: add information for mwl8k wireless driver
From: Lennert Buytenhek @ 2009-08-18 3:56 UTC (permalink / raw)
To: linville, linux-wireless
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
---
MAINTAINERS | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index cc9ce9e..8d8d495 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3272,6 +3272,12 @@ S: Supported
F: drivers/net/mv643xx_eth.*
F: include/linux/mv643xx.h
+MARVELL MWL8K WIRELESS DRIVER
+M: Lennert Buytenhek <buytenh@marvell.com>
+L: linux-wireless@vger.kernel.org
+S: Supported
+F: drivers/net/wireless/mwl8k.c
+
MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER
M: Nicolas Pitre <nico@cam.org>
S: Maintained
--
1.5.6.4
^ permalink raw reply related
* [PATCH 28/29] mwl8k: update copyright and version number
From: Lennert Buytenhek @ 2009-08-18 3:55 UTC (permalink / raw)
To: linville, linux-wireless
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
---
drivers/net/wireless/mwl8k.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index c8aa552..2150c32 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -2,7 +2,7 @@
* drivers/net/wireless/mwl8k.c
* Driver for Marvell TOPDOG 802.11 Wireless cards
*
- * Copyright (C) 2008 Marvell Semiconductor Inc.
+ * Copyright (C) 2008-2009 Marvell Semiconductor Inc.
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
@@ -25,7 +25,7 @@
#define MWL8K_DESC "Marvell TOPDOG(R) 802.11 Wireless Network Driver"
#define MWL8K_NAME KBUILD_MODNAME
-#define MWL8K_VERSION "0.9.1"
+#define MWL8K_VERSION "0.10"
MODULE_DESCRIPTION(MWL8K_DESC);
MODULE_VERSION(MWL8K_VERSION);
--
1.5.6.4
^ permalink raw reply related
* [PATCH 27/29] mwl8k: remove mwl8k_queue_work()
From: Lennert Buytenhek @ 2009-08-18 3:55 UTC (permalink / raw)
To: linville, linux-wireless
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
---
drivers/net/wireless/mwl8k.c | 75 ------------------------------------------
1 files changed, 0 insertions(+), 75 deletions(-)
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index dea1440..c8aa552 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -2425,81 +2425,6 @@ static int mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
return rc;
}
-struct mwl8k_work_struct {
- /* Initialized by mwl8k_queue_work(). */
- struct work_struct wt;
-
- /* Required field passed in to mwl8k_queue_work(). */
- struct ieee80211_hw *hw;
-
- /* Required field passed in to mwl8k_queue_work(). */
- int (*wfunc)(struct work_struct *w);
-
- /* Initialized by mwl8k_queue_work(). */
- struct completion *cmd_wait;
-
- /* Result code. */
- int rc;
-
- /*
- * Whether to sleep for request completion.
- */
- bool sleep;
-};
-
-static void mwl8k_config_thread(struct work_struct *wt)
-{
- struct mwl8k_work_struct *worker = (struct mwl8k_work_struct *)wt;
- struct ieee80211_hw *hw = worker->hw;
- int rc = 0;
-
- rc = mwl8k_fw_lock(hw);
- if (!rc) {
- rc = worker->wfunc(wt);
- mwl8k_fw_unlock(hw);
- }
-
- if (worker->sleep) {
- worker->rc = rc;
- complete(worker->cmd_wait);
- } else {
- kfree(wt);
- }
-}
-
-static int mwl8k_queue_work(struct ieee80211_hw *hw,
- struct mwl8k_work_struct *worker,
- int (*wfunc)(struct work_struct *w))
-{
- struct mwl8k_priv *priv = hw->priv;
- unsigned long timeout = 0;
- int rc = 0;
-
- DECLARE_COMPLETION_ONSTACK(cmd_wait);
-
- worker->hw = hw;
- worker->cmd_wait = &cmd_wait;
- worker->rc = 1;
- worker->wfunc = wfunc;
-
- INIT_WORK(&worker->wt, mwl8k_config_thread);
- queue_work(priv->config_wq, &worker->wt);
-
- if (worker->sleep) {
- timeout = wait_for_completion_timeout(&cmd_wait,
- msecs_to_jiffies(10000));
-
- if (timeout)
- rc = worker->rc;
- else {
- cancel_work_sync(&worker->wt);
- rc = -ETIMEDOUT;
- }
- }
-
- return rc;
-}
-
static int mwl8k_start(struct ieee80211_hw *hw)
{
struct mwl8k_priv *priv = hw->priv;
--
1.5.6.4
^ permalink raw reply related
* [PATCH 26/29] mwl8k: make mwl8k_configure_filter() use queue_work() directly
From: Lennert Buytenhek @ 2009-08-18 3:55 UTC (permalink / raw)
To: linville, linux-wireless
mwl8k_configure_filter() was the last remaining user of
mwl8k_queue_work(), which can now be removed in favor of just using
queue_work() on priv->config_wq directly.
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
---
drivers/net/wireless/mwl8k.c | 40 +++++++++++++++++++++-------------------
1 files changed, 21 insertions(+), 19 deletions(-)
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index b863b74..dea1440 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -2747,27 +2747,26 @@ out:
}
struct mwl8k_configure_filter_worker {
- struct mwl8k_work_struct header;
+ struct work_struct wt;
+ struct ieee80211_hw *hw;
unsigned int changed_flags;
unsigned int total_flags;
struct mwl8k_cmd_pkt *set_multicast_adr;
};
-#define MWL8K_SUPPORTED_IF_FLAGS FIF_BCN_PRBRESP_PROMISC
-
-static int mwl8k_configure_filter_wt(struct work_struct *wt)
+static void mwl8k_configure_filter_wt(struct work_struct *wt)
{
struct mwl8k_configure_filter_worker *worker =
(struct mwl8k_configure_filter_worker *)wt;
- struct ieee80211_hw *hw = worker->header.hw;
- unsigned int changed_flags = worker->changed_flags;
- unsigned int total_flags = worker->total_flags;
+ struct ieee80211_hw *hw = worker->hw;
struct mwl8k_priv *priv = hw->priv;
- int rc = 0;
- if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
- if (total_flags & FIF_BCN_PRBRESP_PROMISC)
- rc = mwl8k_cmd_set_pre_scan(hw);
+ if (mwl8k_fw_lock(hw))
+ return;
+
+ if (worker->changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+ if (worker->total_flags & FIF_BCN_PRBRESP_PROMISC)
+ mwl8k_cmd_set_pre_scan(hw);
else {
u8 *bssid;
@@ -2775,17 +2774,18 @@ static int mwl8k_configure_filter_wt(struct work_struct *wt)
if (priv->vif != NULL)
bssid = MWL8K_VIF(priv->vif)->bssid;
- rc = mwl8k_cmd_set_post_scan(hw, bssid);
+ mwl8k_cmd_set_post_scan(hw, bssid);
}
}
if (worker->set_multicast_adr != NULL) {
- if (!rc)
- rc = mwl8k_post_cmd(hw, worker->set_multicast_adr);
+ mwl8k_post_cmd(hw, worker->set_multicast_adr);
kfree(worker->set_multicast_adr);
}
- return rc;
+ mwl8k_fw_unlock(hw);
+
+ kfree(worker);
}
static void mwl8k_configure_filter(struct ieee80211_hw *hw,
@@ -2794,26 +2794,28 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw,
int mc_count,
struct dev_addr_list *mclist)
{
+ struct mwl8k_priv *priv = hw->priv;
struct mwl8k_configure_filter_worker *worker;
/* Clear unsupported feature flags */
- *total_flags &= MWL8K_SUPPORTED_IF_FLAGS;
+ *total_flags &= FIF_BCN_PRBRESP_PROMISC;
- if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS) && !mc_count)
+ if (!(changed_flags & FIF_BCN_PRBRESP_PROMISC) && !mc_count)
return;
worker = kzalloc(sizeof(*worker), GFP_ATOMIC);
if (worker == NULL)
return;
- worker->header.sleep = 0;
+ worker->hw = hw;
worker->changed_flags = changed_flags;
worker->total_flags = *total_flags;
if (mc_count)
worker->set_multicast_adr =
__mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist);
- mwl8k_queue_work(hw, &worker->header, mwl8k_configure_filter_wt);
+ INIT_WORK(&worker->wt, mwl8k_configure_filter_wt);
+ queue_work(priv->config_wq, &worker->wt);
}
static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
--
1.5.6.4
^ permalink raw reply related
* [PATCH 25/29] mwl8k: get rid of mwl8k_get_stats() workqueue use
From: Lennert Buytenhek @ 2009-08-18 3:55 UTC (permalink / raw)
To: linville, linux-wireless
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
---
drivers/net/wireless/mwl8k.c | 33 ++-------------------------------
1 files changed, 2 insertions(+), 31 deletions(-)
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index d16ba1b..b863b74 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -2859,43 +2859,14 @@ static int mwl8k_get_tx_stats(struct ieee80211_hw *hw,
sizeof(struct ieee80211_tx_queue_stats));
}
spin_unlock_bh(&priv->tx_lock);
- return 0;
-}
-
-struct mwl8k_get_stats_worker {
- struct mwl8k_work_struct header;
- struct ieee80211_low_level_stats *stats;
-};
-static int mwl8k_get_stats_wt(struct work_struct *wt)
-{
- struct mwl8k_get_stats_worker *worker =
- (struct mwl8k_get_stats_worker *)wt;
-
- return mwl8k_cmd_802_11_get_stat(worker->header.hw, worker->stats);
+ return 0;
}
static int mwl8k_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats)
{
- int rc;
- struct mwl8k_get_stats_worker *worker;
-
- worker = kzalloc(sizeof(*worker), GFP_KERNEL);
- if (worker == NULL)
- return -ENOMEM;
-
- worker->header.sleep = 1;
- worker->stats = stats;
- rc = mwl8k_queue_work(hw, &worker->header, mwl8k_get_stats_wt);
-
- kfree(worker);
- if (rc == -ETIMEDOUT) {
- printk(KERN_ERR "%s() timed out\n", __func__);
- rc = -EINVAL;
- }
-
- return rc;
+ return mwl8k_cmd_802_11_get_stat(hw, stats);
}
static const struct ieee80211_ops mwl8k_ops = {
--
1.5.6.4
^ permalink raw reply related
* [PATCH 24/29] mwl8k: get rid of mwl8k_conf_tx() workqueue use
From: Lennert Buytenhek @ 2009-08-18 3:55 UTC (permalink / raw)
To: linville, linux-wireless
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
---
drivers/net/wireless/mwl8k.c | 58 ++++++++++-------------------------------
1 files changed, 14 insertions(+), 44 deletions(-)
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index c8e65c6..d16ba1b 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -2821,57 +2821,27 @@ static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
return mwl8k_rts_threshold(hw, MWL8K_CMD_SET, value);
}
-struct mwl8k_conf_tx_worker {
- struct mwl8k_work_struct header;
- u16 queue;
- const struct ieee80211_tx_queue_params *params;
-};
-
-static int mwl8k_conf_tx_wt(struct work_struct *wt)
-{
- struct mwl8k_conf_tx_worker *worker =
- (struct mwl8k_conf_tx_worker *)wt;
-
- struct ieee80211_hw *hw = worker->header.hw;
- u16 queue = worker->queue;
- const struct ieee80211_tx_queue_params *params = worker->params;
-
- struct mwl8k_priv *priv = hw->priv;
- int rc = 0;
-
- if (!priv->wmm_enabled) {
- if (mwl8k_set_wmm(hw, 1)) {
- rc = -EINVAL;
- goto mwl8k_conf_tx_exit;
- }
- }
-
- if (mwl8k_set_edca_params(hw, GET_TXQ(queue), params->cw_min,
- params->cw_max, params->aifs, params->txop))
- rc = -EINVAL;
-mwl8k_conf_tx_exit:
- return rc;
-}
-
static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
+ struct mwl8k_priv *priv = hw->priv;
int rc;
- struct mwl8k_conf_tx_worker *worker;
- worker = kzalloc(sizeof(*worker), GFP_KERNEL);
- if (worker == NULL)
- return -ENOMEM;
+ rc = mwl8k_fw_lock(hw);
+ if (!rc) {
+ if (!priv->wmm_enabled)
+ rc = mwl8k_set_wmm(hw, 1);
- worker->header.sleep = 1;
- worker->queue = queue;
- worker->params = params;
- rc = mwl8k_queue_work(hw, &worker->header, mwl8k_conf_tx_wt);
- kfree(worker);
- if (rc == -ETIMEDOUT) {
- printk(KERN_ERR "%s() timed out\n", __func__);
- rc = -EINVAL;
+ if (!rc)
+ rc = mwl8k_set_edca_params(hw, queue,
+ params->cw_min,
+ params->cw_max,
+ params->aifs,
+ params->txop);
+
+ mwl8k_fw_unlock(hw);
}
+
return rc;
}
--
1.5.6.4
^ permalink raw reply related
* [PATCH 23/29] mwl8k: get rid of mwl8k_set_rts_threshold() workqueue use
From: Lennert Buytenhek @ 2009-08-18 3:54 UTC (permalink / raw)
To: linville, linux-wireless
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
---
drivers/net/wireless/mwl8k.c | 43 ++---------------------------------------
1 files changed, 3 insertions(+), 40 deletions(-)
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 927f987..c8e65c6 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -1970,7 +1970,7 @@ struct mwl8k_cmd_rts_threshold {
} __attribute__((packed));
static int mwl8k_rts_threshold(struct ieee80211_hw *hw,
- u16 action, u16 *threshold)
+ u16 action, u16 threshold)
{
struct mwl8k_cmd_rts_threshold *cmd;
int rc;
@@ -1982,7 +1982,7 @@ static int mwl8k_rts_threshold(struct ieee80211_hw *hw,
cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD);
cmd->header.length = cpu_to_le16(sizeof(*cmd));
cmd->action = cpu_to_le16(action);
- cmd->threshold = cpu_to_le16(*threshold);
+ cmd->threshold = cpu_to_le16(threshold);
rc = mwl8k_post_cmd(hw, &cmd->header);
kfree(cmd);
@@ -2816,46 +2816,9 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw,
mwl8k_queue_work(hw, &worker->header, mwl8k_configure_filter_wt);
}
-struct mwl8k_set_rts_threshold_worker {
- struct mwl8k_work_struct header;
- u32 value;
-};
-
-static int mwl8k_set_rts_threshold_wt(struct work_struct *wt)
-{
- struct mwl8k_set_rts_threshold_worker *worker =
- (struct mwl8k_set_rts_threshold_worker *)wt;
-
- struct ieee80211_hw *hw = worker->header.hw;
- u16 threshold = (u16)(worker->value);
- int rc;
-
- rc = mwl8k_rts_threshold(hw, MWL8K_CMD_SET, &threshold);
-
- return rc;
-}
-
static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{
- int rc;
- struct mwl8k_set_rts_threshold_worker *worker;
-
- worker = kzalloc(sizeof(*worker), GFP_KERNEL);
- if (worker == NULL)
- return -ENOMEM;
-
- worker->header.sleep = 1;
- worker->value = value;
-
- rc = mwl8k_queue_work(hw, &worker->header, mwl8k_set_rts_threshold_wt);
- kfree(worker);
-
- if (rc == -ETIMEDOUT) {
- printk(KERN_ERR "%s() timed out\n", __func__);
- rc = -EINVAL;
- }
-
- return rc;
+ return mwl8k_rts_threshold(hw, MWL8K_CMD_SET, value);
}
struct mwl8k_conf_tx_worker {
--
1.5.6.4
^ permalink raw reply related
* [PATCH 22/29] mwl8k: get rid of mwl8k_bss_info_changed() workqueue use
From: Lennert Buytenhek @ 2009-08-18 3:54 UTC (permalink / raw)
To: linville, linux-wireless
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
---
drivers/net/wireless/mwl8k.c | 102 ++++++++++++++++--------------------------
1 files changed, 38 insertions(+), 64 deletions(-)
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index d03e55b..927f987 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -2672,58 +2672,62 @@ out:
return rc;
}
-struct mwl8k_bss_info_changed_worker {
- struct mwl8k_work_struct header;
- struct ieee80211_vif *vif;
- struct ieee80211_bss_conf *info;
- u32 changed;
-};
-
-static int mwl8k_bss_info_changed_wt(struct work_struct *wt)
+static void mwl8k_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info,
+ u32 changed)
{
- struct mwl8k_bss_info_changed_worker *worker =
- (struct mwl8k_bss_info_changed_worker *)wt;
- struct ieee80211_hw *hw = worker->header.hw;
- struct ieee80211_vif *vif = worker->vif;
- struct ieee80211_bss_conf *info = worker->info;
- u32 changed;
- int rc;
-
struct mwl8k_priv *priv = hw->priv;
struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
+ int rc;
+
+ if (changed & BSS_CHANGED_BSSID)
+ memcpy(mwl8k_vif->bssid, info->bssid, ETH_ALEN);
+
+ if ((changed & BSS_CHANGED_ASSOC) == 0)
+ return;
- changed = worker->changed;
priv->capture_beacon = false;
+ rc = mwl8k_fw_lock(hw);
+ if (!rc)
+ return;
+
if (info->assoc) {
memcpy(&mwl8k_vif->bss_info, info,
sizeof(struct ieee80211_bss_conf));
/* Install rates */
- if (mwl8k_update_rateset(hw, vif))
- goto mwl8k_bss_info_changed_exit;
+ rc = mwl8k_update_rateset(hw, vif);
+ if (rc)
+ goto out;
/* Turn on rate adaptation */
- if (mwl8k_cmd_use_fixed_rate(hw, MWL8K_USE_AUTO_RATE,
- MWL8K_UCAST_RATE, NULL))
- goto mwl8k_bss_info_changed_exit;
+ rc = mwl8k_cmd_use_fixed_rate(hw, MWL8K_USE_AUTO_RATE,
+ MWL8K_UCAST_RATE, NULL);
+ if (rc)
+ goto out;
/* Set radio preamble */
- if (mwl8k_set_radio_preamble(hw, info->use_short_preamble))
- goto mwl8k_bss_info_changed_exit;
+ rc = mwl8k_set_radio_preamble(hw, info->use_short_preamble);
+ if (rc)
+ goto out;
/* Set slot time */
- if (mwl8k_cmd_set_slot(hw, info->use_short_slot))
- goto mwl8k_bss_info_changed_exit;
+ rc = mwl8k_cmd_set_slot(hw, info->use_short_slot);
+ if (rc)
+ goto out;
/* Update peer rate info */
- if (mwl8k_cmd_update_sta_db(hw, vif,
- MWL8K_STA_DB_MODIFY_ENTRY))
- goto mwl8k_bss_info_changed_exit;
+ rc = mwl8k_cmd_update_sta_db(hw, vif,
+ MWL8K_STA_DB_MODIFY_ENTRY);
+ if (rc)
+ goto out;
/* Set AID */
- if (mwl8k_cmd_set_aid(hw, vif))
- goto mwl8k_bss_info_changed_exit;
+ rc = mwl8k_cmd_set_aid(hw, vif);
+ if (rc)
+ goto out;
/*
* Finalize the join. Tell rx handler to process
@@ -2732,44 +2736,14 @@ static int mwl8k_bss_info_changed_wt(struct work_struct *wt)
memcpy(priv->capture_bssid, mwl8k_vif->bssid, ETH_ALEN);
priv->capture_beacon = true;
} else {
- mwl8k_cmd_update_sta_db(hw, vif, MWL8K_STA_DB_DEL_ENTRY);
+ rc = mwl8k_cmd_update_sta_db(hw, vif, MWL8K_STA_DB_DEL_ENTRY);
memset(&mwl8k_vif->bss_info, 0,
sizeof(struct ieee80211_bss_conf));
memset(mwl8k_vif->bssid, 0, ETH_ALEN);
}
-mwl8k_bss_info_changed_exit:
- rc = 0;
- return rc;
-}
-
-static void mwl8k_bss_info_changed(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *info,
- u32 changed)
-{
- struct mwl8k_bss_info_changed_worker *worker;
- struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
- int rc;
-
- if (changed & BSS_CHANGED_BSSID)
- memcpy(mv_vif->bssid, info->bssid, ETH_ALEN);
-
- if ((changed & BSS_CHANGED_ASSOC) == 0)
- return;
-
- worker = kzalloc(sizeof(*worker), GFP_KERNEL);
- if (worker == NULL)
- return;
-
- worker->header.sleep = 1;
- worker->vif = vif;
- worker->info = info;
- worker->changed = changed;
- rc = mwl8k_queue_work(hw, &worker->header, mwl8k_bss_info_changed_wt);
- kfree(worker);
- if (rc == -ETIMEDOUT)
- printk(KERN_ERR "%s() timed out\n", __func__);
+out:
+ mwl8k_fw_unlock(hw);
}
struct mwl8k_configure_filter_worker {
--
1.5.6.4
^ permalink raw reply related
* [PATCH 21/29] mwl8k: get rid of mwl8k_config() workqueue use
From: Lennert Buytenhek @ 2009-08-18 3:54 UTC (permalink / raw)
To: linville, linux-wireless
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
---
drivers/net/wireless/mwl8k.c | 78 +++++++++++------------------------------
1 files changed, 21 insertions(+), 57 deletions(-)
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 6b16542..d03e55b 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -2633,79 +2633,43 @@ static void mwl8k_remove_interface(struct ieee80211_hw *hw,
priv->vif = NULL;
}
-struct mwl8k_config_worker {
- struct mwl8k_work_struct header;
- u32 changed;
-};
-
-static int mwl8k_config_wt(struct work_struct *wt)
+static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
{
- struct mwl8k_config_worker *worker =
- (struct mwl8k_config_worker *)wt;
- struct ieee80211_hw *hw = worker->header.hw;
struct ieee80211_conf *conf = &hw->conf;
struct mwl8k_priv *priv = hw->priv;
- int rc = 0;
+ int rc;
if (conf->flags & IEEE80211_CONF_IDLE) {
- mwl8k_cmd_802_11_radio_disable(hw);
priv->current_channel = NULL;
- rc = 0;
- goto mwl8k_config_exit;
+ return mwl8k_cmd_802_11_radio_disable(hw);
}
- if (mwl8k_cmd_802_11_radio_enable(hw)) {
- rc = -EINVAL;
- goto mwl8k_config_exit;
- }
+ rc = mwl8k_fw_lock(hw);
+ if (rc)
+ return rc;
- priv->current_channel = conf->channel;
+ rc = mwl8k_cmd_802_11_radio_enable(hw);
+ if (rc)
+ goto out;
- if (mwl8k_cmd_set_rf_channel(hw, conf->channel)) {
- rc = -EINVAL;
- goto mwl8k_config_exit;
- }
+ rc = mwl8k_cmd_set_rf_channel(hw, conf->channel);
+ if (rc)
+ goto out;
+
+ priv->current_channel = conf->channel;
if (conf->power_level > 18)
conf->power_level = 18;
- if (mwl8k_cmd_802_11_rf_tx_power(hw, conf->power_level)) {
- rc = -EINVAL;
- goto mwl8k_config_exit;
- }
-
- if (mwl8k_cmd_mimo_config(hw, 0x7, 0x7))
- rc = -EINVAL;
-
-mwl8k_config_exit:
- return rc;
-}
-
-static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
-{
- int rc = 0;
- struct mwl8k_config_worker *worker;
-
- worker = kzalloc(sizeof(*worker), GFP_KERNEL);
- if (worker == NULL)
- return -ENOMEM;
-
- worker->header.sleep = 1;
- worker->changed = changed;
+ rc = mwl8k_cmd_802_11_rf_tx_power(hw, conf->power_level);
+ if (rc)
+ goto out;
- rc = mwl8k_queue_work(hw, &worker->header, mwl8k_config_wt);
- if (rc == -ETIMEDOUT) {
- printk(KERN_ERR "%s() timed out.\n", __func__);
- rc = -EINVAL;
- }
+ rc = mwl8k_cmd_mimo_config(hw, 0x7, 0x7);
- kfree(worker);
+out:
+ mwl8k_fw_unlock(hw);
- /*
- * mac80211 will crash on anything other than -EINVAL on
- * error. Looks like wireless extensions which calls mac80211
- * may be the actual culprit...
- */
- return rc ? -EINVAL : 0;
+ return rc;
}
struct mwl8k_bss_info_changed_worker {
--
1.5.6.4
^ permalink raw reply related
* [PATCH 20/29] mwl8k: get rid of mwl8k_stop() workqueue use
From: Lennert Buytenhek @ 2009-08-18 3:54 UTC (permalink / raw)
To: linville, linux-wireless
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
---
drivers/net/wireless/mwl8k.c | 28 +---------------------------
1 files changed, 1 insertions(+), 27 deletions(-)
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 69e6879..6b16542 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -2551,41 +2551,15 @@ static int mwl8k_start(struct ieee80211_hw *hw)
return rc;
}
-struct mwl8k_stop_worker {
- struct mwl8k_work_struct header;
-};
-
-static int mwl8k_stop_wt(struct work_struct *wt)
-{
- struct mwl8k_stop_worker *worker = (struct mwl8k_stop_worker *)wt;
- struct ieee80211_hw *hw = worker->header.hw;
-
- return mwl8k_cmd_802_11_radio_disable(hw);
-}
-
static void mwl8k_stop(struct ieee80211_hw *hw)
{
- int rc;
- struct mwl8k_stop_worker *worker;
struct mwl8k_priv *priv = hw->priv;
int i;
- if (priv->vif != NULL)
- return;
+ mwl8k_cmd_802_11_radio_disable(hw);
ieee80211_stop_queues(hw);
- worker = kzalloc(sizeof(*worker), GFP_KERNEL);
- if (worker == NULL)
- return;
-
- worker->header.sleep = 1;
-
- rc = mwl8k_queue_work(hw, &worker->header, mwl8k_stop_wt);
- kfree(worker);
- if (rc == -ETIMEDOUT)
- printk(KERN_ERR "%s() timed out\n", __func__);
-
/* Disable interrupts */
iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
free_irq(priv->pdev->irq, hw);
--
1.5.6.4
^ permalink raw reply related
* [PATCH 19/29] mwl8k: get rid of mwl8k_start() workqueue use
From: Lennert Buytenhek @ 2009-08-18 3:54 UTC (permalink / raw)
To: linville, linux-wireless
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
---
drivers/net/wireless/mwl8k.c | 105 ++++++++++-------------------------------
1 files changed, 26 insertions(+), 79 deletions(-)
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 5516058..69e6879 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -2500,106 +2500,53 @@ static int mwl8k_queue_work(struct ieee80211_hw *hw,
return rc;
}
-struct mwl8k_start_worker {
- struct mwl8k_work_struct header;
-};
-
-static int mwl8k_start_wt(struct work_struct *wt)
-{
- struct mwl8k_start_worker *worker = (struct mwl8k_start_worker *)wt;
- struct ieee80211_hw *hw = worker->header.hw;
- struct mwl8k_priv *priv = hw->priv;
- int rc = 0;
-
- if (priv->vif != NULL) {
- rc = -EIO;
- goto mwl8k_start_exit;
- }
-
- /* Turn on radio */
- if (mwl8k_cmd_802_11_radio_enable(hw)) {
- rc = -EIO;
- goto mwl8k_start_exit;
- }
-
- /* Purge TX/RX HW queues */
- if (mwl8k_cmd_set_pre_scan(hw)) {
- rc = -EIO;
- goto mwl8k_start_exit;
- }
-
- if (mwl8k_cmd_set_post_scan(hw, "\x00\x00\x00\x00\x00\x00")) {
- rc = -EIO;
- goto mwl8k_start_exit;
- }
-
- /* Enable firmware rate adaptation */
- if (mwl8k_cmd_setrateadaptmode(hw, 0)) {
- rc = -EIO;
- goto mwl8k_start_exit;
- }
-
- /* Disable WMM. WMM gets enabled when stack sends WMM parms */
- if (mwl8k_set_wmm(hw, 0)) {
- rc = -EIO;
- goto mwl8k_start_exit;
- }
-
- /* Disable sniffer mode */
- if (mwl8k_enable_sniffer(hw, 0))
- rc = -EIO;
-
-mwl8k_start_exit:
- return rc;
-}
-
static int mwl8k_start(struct ieee80211_hw *hw)
{
- struct mwl8k_start_worker *worker;
struct mwl8k_priv *priv = hw->priv;
int rc;
- /* Enable tx reclaim tasklet */
- tasklet_enable(&priv->tx_reclaim_task);
-
rc = request_irq(priv->pdev->irq, &mwl8k_interrupt,
IRQF_SHARED, MWL8K_NAME, hw);
if (rc) {
printk(KERN_ERR "%s: failed to register IRQ handler\n",
priv->name);
- rc = -EIO;
- goto mwl8k_start_disable_tasklet;
+ return -EIO;
}
+ /* Enable tx reclaim tasklet */
+ tasklet_enable(&priv->tx_reclaim_task);
+
/* Enable interrupts */
iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
- worker = kzalloc(sizeof(*worker), GFP_KERNEL);
- if (worker == NULL) {
- rc = -ENOMEM;
- goto mwl8k_start_disable_irq;
- }
+ rc = mwl8k_fw_lock(hw);
+ if (!rc) {
+ rc = mwl8k_cmd_802_11_radio_enable(hw);
- worker->header.sleep = 1;
+ if (!rc)
+ rc = mwl8k_cmd_set_pre_scan(hw);
- rc = mwl8k_queue_work(hw, &worker->header, mwl8k_start_wt);
- kfree(worker);
- if (!rc)
- return rc;
+ if (!rc)
+ rc = mwl8k_cmd_set_post_scan(hw,
+ "\x00\x00\x00\x00\x00\x00");
- if (rc == -ETIMEDOUT)
- printk(KERN_ERR "%s() timed out\n", __func__);
+ if (!rc)
+ rc = mwl8k_cmd_setrateadaptmode(hw, 0);
- rc = -EIO;
+ if (!rc)
+ rc = mwl8k_set_wmm(hw, 0);
-mwl8k_start_disable_irq:
- spin_lock_irq(&priv->tx_lock);
- iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
- spin_unlock_irq(&priv->tx_lock);
- free_irq(priv->pdev->irq, hw);
+ if (!rc)
+ rc = mwl8k_enable_sniffer(hw, 0);
-mwl8k_start_disable_tasklet:
- tasklet_disable(&priv->tx_reclaim_task);
+ mwl8k_fw_unlock(hw);
+ }
+
+ if (rc) {
+ iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
+ free_irq(priv->pdev->irq, hw);
+ tasklet_disable(&priv->tx_reclaim_task);
+ }
return rc;
}
--
1.5.6.4
^ permalink raw reply related
* [PATCH 18/29] mwl8k: fix firmware command serialisation
From: Lennert Buytenhek @ 2009-08-18 3:53 UTC (permalink / raw)
To: linville, linux-wireless
The current mwl8k_priv->fw_lock spinlock doesn't actually protect
against multiple commands being submitted at once, as it is not kept
held over the entire firmware command submission. And since waiting
for command completion sleeps, we can't use a spinlock anyway.
To fix mwl8k firmware command serialisation properly, we have the
following requirements:
- Some commands require that the packet transmit path is idle when
the command is issued. (For simplicity, we'll just quiesce the
transmit path for every command.)
- There are certain sequences of commands that need to be issued to
the hardware sequentially, with no other intervening commands.
This leads to an implementation of a "firmware lock" as a mutex that
can be taken recursively, and which is taken by both the low-level
command submission function (mwl8k_post_cmd) as well as any users of
that function that require issuing of an atomic sequence of commands,
and quiesces the transmit path whenever it's taken.
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
---
drivers/net/wireless/mwl8k.c | 154 ++++++++++++++++++++++++------------------
1 files changed, 89 insertions(+), 65 deletions(-)
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 905f750..5516058 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -139,13 +139,18 @@ struct mwl8k_priv {
struct pci_dev *pdev;
u8 name[16];
- /* firmware access lock */
- spinlock_t fw_lock;
/* firmware files and meta data */
struct mwl8k_firmware fw;
u32 part_num;
+ /* firmware access */
+ struct mutex fw_mutex;
+ struct task_struct *fw_mutex_owner;
+ int fw_mutex_depth;
+ struct completion *tx_wait;
+ struct completion *hostcmd_wait;
+
/* lock held over TX and TX reap */
spinlock_t tx_lock;
@@ -179,9 +184,6 @@ struct mwl8k_priv {
bool radio_short_preamble;
bool wmm_enabled;
- /* Set if PHY config is in progress */
- bool inconfig;
-
/* XXX need to convert this to handle multiple interfaces */
bool capture_beacon;
u8 capture_bssid[ETH_ALEN];
@@ -200,8 +202,6 @@ struct mwl8k_priv {
/* Work thread to serialize configuration requests */
struct workqueue_struct *config_wq;
- struct completion *hostcmd_wait;
- struct completion *tx_wait;
};
/* Per interface specific private data */
@@ -1113,6 +1113,9 @@ static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv,
return ndescs;
}
+/*
+ * Must be called with hw->fw_mutex held and tx queues stopped.
+ */
static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
{
struct mwl8k_priv *priv = hw->priv;
@@ -1122,9 +1125,6 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
might_sleep();
- if (priv->tx_wait != NULL)
- printk(KERN_ERR "WARNING Previous TXWaitEmpty instance\n");
-
spin_lock_bh(&priv->tx_lock);
count = mwl8k_txq_busy(priv);
if (count) {
@@ -1140,7 +1140,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
int newcount;
timeout = wait_for_completion_timeout(&cmd_wait,
- msecs_to_jiffies(1000));
+ msecs_to_jiffies(5000));
if (timeout)
return 0;
@@ -1149,7 +1149,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
newcount = mwl8k_txq_busy(priv);
spin_unlock_bh(&priv->tx_lock);
- printk(KERN_ERR "%s(%u) TIMEDOUT:1000ms Pend:%u-->%u\n",
+ printk(KERN_ERR "%s(%u) TIMEDOUT:5000ms Pend:%u-->%u\n",
__func__, __LINE__, count, newcount);
mwl8k_scan_tx_ring(priv, txinfo);
@@ -1228,10 +1228,10 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
ieee80211_tx_status_irqsafe(hw, skb);
- wake = !priv->inconfig && priv->radio_on;
+ wake = 1;
}
- if (wake)
+ if (wake && priv->radio_on && !mutex_is_locked(&priv->fw_mutex))
ieee80211_wake_queue(hw, index);
}
@@ -1360,6 +1360,60 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
/*
+ * Firmware access.
+ *
+ * We have the following requirements for issuing firmware commands:
+ * - Some commands require that the packet transmit path is idle when
+ * the command is issued. (For simplicity, we'll just quiesce the
+ * transmit path for every command.)
+ * - There are certain sequences of commands that need to be issued to
+ * the hardware sequentially, with no other intervening commands.
+ *
+ * This leads to an implementation of a "firmware lock" as a mutex that
+ * can be taken recursively, and which is taken by both the low-level
+ * command submission function (mwl8k_post_cmd) as well as any users of
+ * that function that require issuing of an atomic sequence of commands,
+ * and quiesces the transmit path whenever it's taken.
+ */
+static int mwl8k_fw_lock(struct ieee80211_hw *hw)
+{
+ struct mwl8k_priv *priv = hw->priv;
+
+ if (priv->fw_mutex_owner != current) {
+ int rc;
+
+ mutex_lock(&priv->fw_mutex);
+ ieee80211_stop_queues(hw);
+
+ rc = mwl8k_tx_wait_empty(hw);
+ if (rc) {
+ ieee80211_wake_queues(hw);
+ mutex_unlock(&priv->fw_mutex);
+
+ return rc;
+ }
+
+ priv->fw_mutex_owner = current;
+ }
+
+ priv->fw_mutex_depth++;
+
+ return 0;
+}
+
+static void mwl8k_fw_unlock(struct ieee80211_hw *hw)
+{
+ struct mwl8k_priv *priv = hw->priv;
+
+ if (!--priv->fw_mutex_depth) {
+ ieee80211_wake_queues(hw);
+ priv->fw_mutex_owner = NULL;
+ mutex_unlock(&priv->fw_mutex);
+ }
+}
+
+
+/*
* Command processing.
*/
@@ -1384,28 +1438,28 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
if (pci_dma_mapping_error(priv->pdev, dma_addr))
return -ENOMEM;
- if (priv->hostcmd_wait != NULL)
- printk(KERN_ERR "WARNING host command in progress\n");
+ rc = mwl8k_fw_lock(hw);
+ if (rc)
+ return rc;
- spin_lock_irq(&priv->fw_lock);
priv->hostcmd_wait = &cmd_wait;
iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR);
iowrite32(MWL8K_H2A_INT_DOORBELL,
regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
iowrite32(MWL8K_H2A_INT_DUMMY,
regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
- spin_unlock_irq(&priv->fw_lock);
timeout = wait_for_completion_timeout(&cmd_wait,
msecs_to_jiffies(MWL8K_CMD_TIMEOUT_MS));
+ priv->hostcmd_wait = NULL;
+
+ mwl8k_fw_unlock(hw);
+
pci_unmap_single(priv->pdev, dma_addr, dma_size,
PCI_DMA_BIDIRECTIONAL);
if (!timeout) {
- spin_lock_irq(&priv->fw_lock);
- priv->hostcmd_wait = NULL;
- spin_unlock_irq(&priv->fw_lock);
printk(KERN_ERR "%s: Command %s timeout after %u ms\n",
priv->name,
mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
@@ -2336,17 +2390,14 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id)
}
if (status & MWL8K_A2H_INT_OPC_DONE) {
- if (priv->hostcmd_wait != NULL) {
+ if (priv->hostcmd_wait != NULL)
complete(priv->hostcmd_wait);
- priv->hostcmd_wait = NULL;
- }
}
if (status & MWL8K_A2H_INT_QUEUE_EMPTY) {
- if (!priv->inconfig &&
- priv->radio_on &&
- mwl8k_txq_busy(priv))
- mwl8k_tx_start(priv);
+ if (!mutex_is_locked(&priv->fw_mutex) &&
+ priv->radio_on && mwl8k_txq_busy(priv))
+ mwl8k_tx_start(priv);
}
return IRQ_HANDLED;
@@ -2400,41 +2451,13 @@ static void mwl8k_config_thread(struct work_struct *wt)
{
struct mwl8k_work_struct *worker = (struct mwl8k_work_struct *)wt;
struct ieee80211_hw *hw = worker->hw;
- struct mwl8k_priv *priv = hw->priv;
int rc = 0;
- int iter;
- spin_lock_irq(&priv->tx_lock);
- priv->inconfig = true;
- spin_unlock_irq(&priv->tx_lock);
-
- ieee80211_stop_queues(hw);
-
- /*
- * Wait for host queues to drain before doing PHY
- * reconfiguration. This avoids interrupting any in-flight
- * DMA transfers to the hardware.
- */
- iter = 4;
- do {
- rc = mwl8k_tx_wait_empty(hw);
- if (rc)
- printk(KERN_ERR "%s() txwait timeout=1000ms "
- "Retry:%u/%u\n", __func__, 4 - iter + 1, 4);
- } while (rc && --iter);
-
- rc = iter ? 0 : -ETIMEDOUT;
-
- if (!rc)
+ rc = mwl8k_fw_lock(hw);
+ if (!rc) {
rc = worker->wfunc(wt);
-
- spin_lock_irq(&priv->tx_lock);
- priv->inconfig = false;
- if (priv->pending_tx_pkts && priv->radio_on)
- mwl8k_tx_start(priv);
- spin_unlock_irq(&priv->tx_lock);
-
- ieee80211_wake_queues(hw);
+ mwl8k_fw_unlock(hw);
+ }
if (worker->sleep) {
worker->rc = rc;
@@ -3163,15 +3186,10 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
priv = hw->priv;
priv->hw = hw;
priv->pdev = pdev;
- priv->hostcmd_wait = NULL;
- priv->tx_wait = NULL;
- priv->inconfig = false;
priv->wmm_enabled = false;
priv->pending_tx_pkts = 0;
strncpy(priv->name, MWL8K_NAME, sizeof(priv->name));
- spin_lock_init(&priv->fw_lock);
-
SET_IEEE80211_DEV(hw, &pdev->dev);
pci_set_drvdata(pdev, hw);
@@ -3237,6 +3255,12 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
goto err_iounmap;
rxq_refill(hw, 0, INT_MAX);
+ mutex_init(&priv->fw_mutex);
+ priv->fw_mutex_owner = NULL;
+ priv->fw_mutex_depth = 0;
+ priv->tx_wait = NULL;
+ priv->hostcmd_wait = NULL;
+
spin_lock_init(&priv->tx_lock);
for (i = 0; i < MWL8K_TX_QUEUES; i++) {
--
1.5.6.4
^ permalink raw reply related
* [PATCH 17/29] mwl8k: mwl8k_queue_work() cleanup
From: Lennert Buytenhek @ 2009-08-18 3:53 UTC (permalink / raw)
To: linville, linux-wireless
Delete most of the mwl8k_work_struct fields and options, since most
of them are unused or never changed from their defaults:
- We always use priv->config_wq, so delete the wqueue argument from
mwl8k_queue_work().
- MWL8K_WQ_SPIN is never used.
- MWL8K_WQ_TX_WAIT_EMPTY is always set, so assume it unconditionally.
- MWL8K_WQ_FREE_WORKSTRUCT is implied by MWL8K_WQ_POST_REQUEST, so
delete it and assume it whenever the latter is set.
- One of MWL8K_WQ_{POST_REQUEST,SLEEP} is always set, so change this
into a bool flag.
- timeout_ms/txwait_attempts/tx_timeout_ms are never changed from
their defaults, so just hardcode these in the workqueue worker.
- step is never used.
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
---
drivers/net/wireless/mwl8k.c | 210 +++++++++--------------------------------
1 files changed, 46 insertions(+), 164 deletions(-)
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index f0d1fa7..905f750 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -1113,7 +1113,7 @@ static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv,
return ndescs;
}
-static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms)
+static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
{
struct mwl8k_priv *priv = hw->priv;
DECLARE_COMPLETION_ONSTACK(cmd_wait);
@@ -1140,7 +1140,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms)
int newcount;
timeout = wait_for_completion_timeout(&cmd_wait,
- msecs_to_jiffies(delay_ms));
+ msecs_to_jiffies(1000));
if (timeout)
return 0;
@@ -1149,8 +1149,8 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms)
newcount = mwl8k_txq_busy(priv);
spin_unlock_bh(&priv->tx_lock);
- printk(KERN_ERR "%s(%u) TIMEDOUT:%ums Pend:%u-->%u\n",
- __func__, __LINE__, delay_ms, count, newcount);
+ printk(KERN_ERR "%s(%u) TIMEDOUT:1000ms Pend:%u-->%u\n",
+ __func__, __LINE__, count, newcount);
mwl8k_scan_tx_ring(priv, txinfo);
for (index = 0; index < MWL8K_TX_QUEUES; index++)
@@ -2391,82 +2391,18 @@ struct mwl8k_work_struct {
int rc;
/*
- * Optional field. Refer to explanation of MWL8K_WQ_XXX_XXX
- * flags for explanation. Defaults to MWL8K_WQ_DEFAULT_OPTIONS.
+ * Whether to sleep for request completion.
*/
- u32 options;
-
- /* Optional field. Defaults to MWL8K_CONFIG_TIMEOUT_MS. */
- unsigned long timeout_ms;
-
- /* Optional field. Defaults to MWL8K_WQ_TXWAIT_ATTEMPTS. */
- u32 txwait_attempts;
-
- /* Optional field. Defaults to MWL8K_TXWAIT_MS. */
- u32 tx_timeout_ms;
- u32 step;
+ bool sleep;
};
-/* Flags controlling behavior of config queue requests */
-
-/* Caller spins while waiting for completion. */
-#define MWL8K_WQ_SPIN 0x00000001
-
-/* Wait for TX queues to empty before proceeding with configuration. */
-#define MWL8K_WQ_TX_WAIT_EMPTY 0x00000002
-
-/* Queue request and return immediately. */
-#define MWL8K_WQ_POST_REQUEST 0x00000004
-
-/*
- * Caller sleeps and waits for task complete notification.
- * Do not use in atomic context.
- */
-#define MWL8K_WQ_SLEEP 0x00000008
-
-/* Free work struct when task is done. */
-#define MWL8K_WQ_FREE_WORKSTRUCT 0x00000010
-
-/*
- * Config request is queued and returns to caller imediately. Use
- * this in atomic context. Work struct is freed by mwl8k_queue_work()
- * when this flag is set.
- */
-#define MWL8K_WQ_QUEUE_ONLY (MWL8K_WQ_POST_REQUEST | \
- MWL8K_WQ_FREE_WORKSTRUCT)
-
-/* Default work queue behavior is to sleep and wait for tx completion. */
-#define MWL8K_WQ_DEFAULT_OPTIONS (MWL8K_WQ_SLEEP | MWL8K_WQ_TX_WAIT_EMPTY)
-
-/*
- * Default config request timeout. Add adjustments to make sure the
- * config thread waits long enough for both tx wait and cmd wait before
- * timing out.
- */
-
-/* Time to wait for all TXQs to drain. TX Doorbell is pressed each time. */
-#define MWL8K_TXWAIT_TIMEOUT_MS 1000
-
-/* Default number of TX wait attempts. */
-#define MWL8K_WQ_TXWAIT_ATTEMPTS 4
-
-/* Total time to wait for TXQ to drain. */
-#define MWL8K_TXWAIT_MS (MWL8K_TXWAIT_TIMEOUT_MS * \
- MWL8K_WQ_TXWAIT_ATTEMPTS)
-
-/* Scheduling slop. */
-#define MWL8K_OS_SCHEDULE_OVERHEAD_MS 200
-
-#define MWL8K_CONFIG_TIMEOUT_MS (MWL8K_CMD_TIMEOUT_MS + \
- MWL8K_TXWAIT_MS + \
- MWL8K_OS_SCHEDULE_OVERHEAD_MS)
-
static void mwl8k_config_thread(struct work_struct *wt)
{
struct mwl8k_work_struct *worker = (struct mwl8k_work_struct *)wt;
struct ieee80211_hw *hw = worker->hw;
struct mwl8k_priv *priv = hw->priv;
int rc = 0;
+ int iter;
spin_lock_irq(&priv->tx_lock);
priv->inconfig = true;
@@ -2479,44 +2415,16 @@ static void mwl8k_config_thread(struct work_struct *wt)
* reconfiguration. This avoids interrupting any in-flight
* DMA transfers to the hardware.
*/
- if (worker->options & MWL8K_WQ_TX_WAIT_EMPTY) {
- u32 timeout;
- u32 time_remaining;
- u32 iter;
- u32 tx_wait_attempts = worker->txwait_attempts;
-
- time_remaining = worker->tx_timeout_ms;
- if (!tx_wait_attempts)
- tx_wait_attempts = 1;
-
- timeout = worker->tx_timeout_ms/tx_wait_attempts;
- if (!timeout)
- timeout = 1;
-
- iter = tx_wait_attempts;
- do {
- int wait_time;
-
- if (time_remaining > timeout) {
- time_remaining -= timeout;
- wait_time = timeout;
- } else
- wait_time = time_remaining;
-
- if (!wait_time)
- wait_time = 1;
-
- rc = mwl8k_tx_wait_empty(hw, wait_time);
- if (rc)
- printk(KERN_ERR "%s() txwait timeout=%ums "
- "Retry:%u/%u\n", __func__, timeout,
- tx_wait_attempts - iter + 1,
- tx_wait_attempts);
+ iter = 4;
+ do {
+ rc = mwl8k_tx_wait_empty(hw);
+ if (rc)
+ printk(KERN_ERR "%s() txwait timeout=1000ms "
+ "Retry:%u/%u\n", __func__, 4 - iter + 1, 4);
+ } while (rc && --iter);
- } while (rc && --iter);
+ rc = iter ? 0 : -ETIMEDOUT;
- rc = iter ? 0 : -ETIMEDOUT;
- }
if (!rc)
rc = worker->wfunc(wt);
@@ -2525,58 +2433,38 @@ static void mwl8k_config_thread(struct work_struct *wt)
if (priv->pending_tx_pkts && priv->radio_on)
mwl8k_tx_start(priv);
spin_unlock_irq(&priv->tx_lock);
+
ieee80211_wake_queues(hw);
- worker->rc = rc;
- if (worker->options & MWL8K_WQ_SLEEP)
+ if (worker->sleep) {
+ worker->rc = rc;
complete(worker->cmd_wait);
-
- if (worker->options & MWL8K_WQ_FREE_WORKSTRUCT)
+ } else {
kfree(wt);
+ }
}
static int mwl8k_queue_work(struct ieee80211_hw *hw,
struct mwl8k_work_struct *worker,
- struct workqueue_struct *wqueue,
int (*wfunc)(struct work_struct *w))
{
+ struct mwl8k_priv *priv = hw->priv;
unsigned long timeout = 0;
int rc = 0;
DECLARE_COMPLETION_ONSTACK(cmd_wait);
- if (!worker->timeout_ms)
- worker->timeout_ms = MWL8K_CONFIG_TIMEOUT_MS;
-
- if (!worker->options)
- worker->options = MWL8K_WQ_DEFAULT_OPTIONS;
-
- if (!worker->txwait_attempts)
- worker->txwait_attempts = MWL8K_WQ_TXWAIT_ATTEMPTS;
-
- if (!worker->tx_timeout_ms)
- worker->tx_timeout_ms = MWL8K_TXWAIT_MS;
-
worker->hw = hw;
worker->cmd_wait = &cmd_wait;
worker->rc = 1;
worker->wfunc = wfunc;
INIT_WORK(&worker->wt, mwl8k_config_thread);
- queue_work(wqueue, &worker->wt);
+ queue_work(priv->config_wq, &worker->wt);
- if (worker->options & MWL8K_WQ_POST_REQUEST) {
- rc = 0;
- } else {
- if (worker->options & MWL8K_WQ_SPIN) {
- timeout = worker->timeout_ms;
- while (timeout && (worker->rc > 0)) {
- mdelay(1);
- timeout--;
- }
- } else if (worker->options & MWL8K_WQ_SLEEP)
- timeout = wait_for_completion_timeout(&cmd_wait,
- msecs_to_jiffies(worker->timeout_ms));
+ if (worker->sleep) {
+ timeout = wait_for_completion_timeout(&cmd_wait,
+ msecs_to_jiffies(10000));
if (timeout)
rc = worker->rc;
@@ -2669,8 +2557,9 @@ static int mwl8k_start(struct ieee80211_hw *hw)
goto mwl8k_start_disable_irq;
}
- rc = mwl8k_queue_work(hw, &worker->header,
- priv->config_wq, mwl8k_start_wt);
+ worker->header.sleep = 1;
+
+ rc = mwl8k_queue_work(hw, &worker->header, mwl8k_start_wt);
kfree(worker);
if (!rc)
return rc;
@@ -2720,8 +2609,9 @@ static void mwl8k_stop(struct ieee80211_hw *hw)
if (worker == NULL)
return;
- rc = mwl8k_queue_work(hw, &worker->header,
- priv->config_wq, mwl8k_stop_wt);
+ worker->header.sleep = 1;
+
+ rc = mwl8k_queue_work(hw, &worker->header, mwl8k_stop_wt);
kfree(worker);
if (rc == -ETIMEDOUT)
printk(KERN_ERR "%s() timed out\n", __func__);
@@ -2850,15 +2740,15 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
{
int rc = 0;
struct mwl8k_config_worker *worker;
- struct mwl8k_priv *priv = hw->priv;
worker = kzalloc(sizeof(*worker), GFP_KERNEL);
if (worker == NULL)
return -ENOMEM;
+ worker->header.sleep = 1;
worker->changed = changed;
- rc = mwl8k_queue_work(hw, &worker->header,
- priv->config_wq, mwl8k_config_wt);
+
+ rc = mwl8k_queue_work(hw, &worker->header, mwl8k_config_wt);
if (rc == -ETIMEDOUT) {
printk(KERN_ERR "%s() timed out.\n", __func__);
rc = -EINVAL;
@@ -2951,7 +2841,6 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw,
u32 changed)
{
struct mwl8k_bss_info_changed_worker *worker;
- struct mwl8k_priv *priv = hw->priv;
struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
int rc;
@@ -2965,12 +2854,11 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw,
if (worker == NULL)
return;
+ worker->header.sleep = 1;
worker->vif = vif;
worker->info = info;
worker->changed = changed;
- rc = mwl8k_queue_work(hw, &worker->header,
- priv->config_wq,
- mwl8k_bss_info_changed_wt);
+ rc = mwl8k_queue_work(hw, &worker->header, mwl8k_bss_info_changed_wt);
kfree(worker);
if (rc == -ETIMEDOUT)
printk(KERN_ERR "%s() timed out\n", __func__);
@@ -3025,7 +2913,6 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw,
struct dev_addr_list *mclist)
{
struct mwl8k_configure_filter_worker *worker;
- struct mwl8k_priv *priv = hw->priv;
/* Clear unsupported feature flags */
*total_flags &= MWL8K_SUPPORTED_IF_FLAGS;
@@ -3037,15 +2924,14 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw,
if (worker == NULL)
return;
- worker->header.options = MWL8K_WQ_QUEUE_ONLY | MWL8K_WQ_TX_WAIT_EMPTY;
+ worker->header.sleep = 0;
worker->changed_flags = changed_flags;
worker->total_flags = *total_flags;
if (mc_count)
worker->set_multicast_adr =
__mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist);
- mwl8k_queue_work(hw, &worker->header, priv->config_wq,
- mwl8k_configure_filter_wt);
+ mwl8k_queue_work(hw, &worker->header, mwl8k_configure_filter_wt);
}
struct mwl8k_set_rts_threshold_worker {
@@ -3071,17 +2957,15 @@ static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{
int rc;
struct mwl8k_set_rts_threshold_worker *worker;
- struct mwl8k_priv *priv = hw->priv;
worker = kzalloc(sizeof(*worker), GFP_KERNEL);
if (worker == NULL)
return -ENOMEM;
+ worker->header.sleep = 1;
worker->value = value;
- rc = mwl8k_queue_work(hw, &worker->header,
- priv->config_wq,
- mwl8k_set_rts_threshold_wt);
+ rc = mwl8k_queue_work(hw, &worker->header, mwl8k_set_rts_threshold_wt);
kfree(worker);
if (rc == -ETIMEDOUT) {
@@ -3129,16 +3013,15 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue,
{
int rc;
struct mwl8k_conf_tx_worker *worker;
- struct mwl8k_priv *priv = hw->priv;
worker = kzalloc(sizeof(*worker), GFP_KERNEL);
if (worker == NULL)
return -ENOMEM;
+ worker->header.sleep = 1;
worker->queue = queue;
worker->params = params;
- rc = mwl8k_queue_work(hw, &worker->header,
- priv->config_wq, mwl8k_conf_tx_wt);
+ rc = mwl8k_queue_work(hw, &worker->header, mwl8k_conf_tx_wt);
kfree(worker);
if (rc == -ETIMEDOUT) {
printk(KERN_ERR "%s() timed out\n", __func__);
@@ -3182,15 +3065,14 @@ static int mwl8k_get_stats(struct ieee80211_hw *hw,
{
int rc;
struct mwl8k_get_stats_worker *worker;
- struct mwl8k_priv *priv = hw->priv;
worker = kzalloc(sizeof(*worker), GFP_KERNEL);
if (worker == NULL)
return -ENOMEM;
+ worker->header.sleep = 1;
worker->stats = stats;
- rc = mwl8k_queue_work(hw, &worker->header,
- priv->config_wq, mwl8k_get_stats_wt);
+ rc = mwl8k_queue_work(hw, &worker->header, mwl8k_get_stats_wt);
kfree(worker);
if (rc == -ETIMEDOUT) {
--
1.5.6.4
^ permalink raw reply related
* [PATCH 16/29] mwl8k: mwl8k_txq_xmit() rework
From: Lennert Buytenhek @ 2009-08-18 3:53 UTC (permalink / raw)
To: linville, linux-wireless
Various mwl8k_txq_xmit changes:
- Extract the QoS field before adding the DMA header.
- Only write to tx->status once, and only after all the other
descriptor fields have been set.
- Do all tx state manipulation under the tx spinlock.
- Remove the priv->inconfig check, as all transmit queues will
be frozen during config cycles, so we won't ever be asked to
transmit if a config cycle is running.
- Remove some more dead code.
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
---
drivers/net/wireless/mwl8k.c | 145 +++++++++++++++---------------------------
1 files changed, 52 insertions(+), 93 deletions(-)
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index e46cf3c..f0d1fa7 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -1257,46 +1257,60 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
{
struct mwl8k_priv *priv = hw->priv;
struct ieee80211_tx_info *tx_info;
+ struct mwl8k_vif *mwl8k_vif;
struct ieee80211_hdr *wh;
struct mwl8k_tx_queue *txq;
struct mwl8k_tx_desc *tx;
- struct mwl8k_dma_data *tr;
- struct mwl8k_vif *mwl8k_vif;
dma_addr_t dma;
- u16 qos = 0;
- bool qosframe = false, ampduframe = false;
- bool mcframe = false, eapolframe = false;
- bool amsduframe = false;
- __le16 fc;
+ u32 txstatus;
+ u8 txdatarate;
+ u16 qos;
- txq = priv->txq + index;
- tx = txq->tx_desc_area + txq->tx_tail;
-
- BUG_ON(txq->tx_skb[txq->tx_tail] != NULL);
+ wh = (struct ieee80211_hdr *)skb->data;
+ if (ieee80211_is_data_qos(wh->frame_control))
+ qos = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(wh)));
+ else
+ qos = 0;
- /*
- * Append HW DMA header to start of packet.
- */
mwl8k_add_dma_header(skb);
+ wh = &((struct mwl8k_dma_data *)skb->data)->wh;
tx_info = IEEE80211_SKB_CB(skb);
mwl8k_vif = MWL8K_VIF(tx_info->control.vif);
- tr = (struct mwl8k_dma_data *)skb->data;
- wh = &tr->wh;
- fc = wh->frame_control;
- qosframe = ieee80211_is_data_qos(fc);
- mcframe = is_multicast_ether_addr(wh->addr1);
- ampduframe = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
u16 seqno = mwl8k_vif->seqno;
+
wh->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
wh->seq_ctrl |= cpu_to_le16(seqno << 4);
mwl8k_vif->seqno = seqno++ % 4096;
}
- if (qosframe)
- qos = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(wh)));
+ /* Setup firmware control bit fields for each frame type. */
+ txstatus = 0;
+ txdatarate = 0;
+ if (ieee80211_is_mgmt(wh->frame_control) ||
+ ieee80211_is_ctl(wh->frame_control)) {
+ txdatarate = 0;
+ qos = mwl8k_qos_setbit_eosp(qos);
+ /* Set Queue size to unspecified */
+ qos = mwl8k_qos_setbit_qlen(qos, 0xff);
+ } else if (ieee80211_is_data(wh->frame_control)) {
+ txdatarate = 1;
+ if (is_multicast_ether_addr(wh->addr1))
+ txstatus |= MWL8K_TXD_STATUS_MULTICAST_TX;
+
+ /* Send pkt in an aggregate if AMPDU frame. */
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
+ qos = mwl8k_qos_setbit_ack(qos,
+ MWL8K_TXD_ACK_POLICY_BLOCKACK);
+ else
+ qos = mwl8k_qos_setbit_ack(qos,
+ MWL8K_TXD_ACK_POLICY_NORMAL);
+
+ if (qos & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
+ qos = mwl8k_qos_setbit_amsdu(qos);
+ }
dma = pci_map_single(priv->pdev, skb->data,
skb->len, PCI_DMA_TODEVICE);
@@ -1304,95 +1318,40 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
if (pci_dma_mapping_error(priv->pdev, dma)) {
printk(KERN_DEBUG "%s: failed to dma map skb, "
"dropping TX frame.\n", priv->name);
-
- if (skb != NULL)
- dev_kfree_skb(skb);
+ dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
- /* Set desc header, cpu bit order. */
- tx->status = 0;
- tx->data_rate = 0;
- tx->tx_priority = index;
- tx->qos_control = 0;
- tx->rate_info = 0;
- tx->peer_id = mwl8k_vif->peer_id;
-
- amsduframe = !!(qos & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT);
-
- /* Setup firmware control bit fields for each frame type. */
- if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) {
- tx->data_rate = 0;
- qos = mwl8k_qos_setbit_eosp(qos);
- /* Set Queue size to unspecified */
- qos = mwl8k_qos_setbit_qlen(qos, 0xff);
- } else if (ieee80211_is_data(fc)) {
- tx->data_rate = 1;
- if (mcframe)
- tx->status |= MWL8K_TXD_STATUS_MULTICAST_TX;
+ spin_lock_bh(&priv->tx_lock);
- /*
- * Tell firmware to not send EAPOL pkts in an
- * aggregate. Verify against mac80211 tx path. If
- * stack turns off AMPDU for an EAPOL frame this
- * check will be removed.
- */
- if (eapolframe) {
- qos = mwl8k_qos_setbit_ack(qos,
- MWL8K_TXD_ACK_POLICY_NORMAL);
- } else {
- /* Send pkt in an aggregate if AMPDU frame. */
- if (ampduframe)
- qos = mwl8k_qos_setbit_ack(qos,
- MWL8K_TXD_ACK_POLICY_BLOCKACK);
- else
- qos = mwl8k_qos_setbit_ack(qos,
- MWL8K_TXD_ACK_POLICY_NORMAL);
+ txq = priv->txq + index;
- if (amsduframe)
- qos = mwl8k_qos_setbit_amsdu(qos);
- }
- }
+ BUG_ON(txq->tx_skb[txq->tx_tail] != NULL);
+ txq->tx_skb[txq->tx_tail] = skb;
- /* Convert to little endian */
+ tx = txq->tx_desc_area + txq->tx_tail;
+ tx->data_rate = txdatarate;
+ tx->tx_priority = index;
tx->qos_control = cpu_to_le16(qos);
- tx->status = cpu_to_le32(tx->status);
tx->pkt_phys_addr = cpu_to_le32(dma);
tx->pkt_len = cpu_to_le16(skb->len);
-
- txq->tx_skb[txq->tx_tail] = skb;
-
- spin_lock_bh(&priv->tx_lock);
-
- tx->status = cpu_to_le32(MWL8K_TXD_STATUS_OK |
- MWL8K_TXD_STATUS_FW_OWNED);
+ tx->rate_info = 0;
+ tx->peer_id = mwl8k_vif->peer_id;
wmb();
+ tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus);
+
+ txq->tx_stats.count++;
txq->tx_stats.len++;
priv->pending_tx_pkts++;
- txq->tx_stats.count++;
- txq->tx_tail++;
+ txq->tx_tail++;
if (txq->tx_tail == MWL8K_TX_DESCS)
txq->tx_tail = 0;
+
if (txq->tx_head == txq->tx_tail)
ieee80211_stop_queue(hw, index);
- if (priv->inconfig) {
- /*
- * Silently queue packet when we are in the middle of
- * a config cycle. Notify firmware only if we are
- * waiting for TXQs to empty. If a packet is sent
- * before .config() is complete, perhaps it is better
- * to drop the packet, as the channel is being changed
- * and the packet will end up on the wrong channel.
- */
- printk(KERN_ERR "%s(): WARNING TX activity while "
- "in config\n", __func__);
-
- if (priv->tx_wait != NULL)
- mwl8k_tx_start(priv);
- } else
- mwl8k_tx_start(priv);
+ mwl8k_tx_start(priv);
spin_unlock_bh(&priv->tx_lock);
--
1.5.6.4
^ permalink raw reply related
* [PATCH 15/29] mwl8k: no need to hold ->tx_lock while setting the hardware interrupt mask
From: Lennert Buytenhek @ 2009-08-18 3:53 UTC (permalink / raw)
To: linville, linux-wireless
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
---
drivers/net/wireless/mwl8k.c | 6 ------
1 files changed, 0 insertions(+), 6 deletions(-)
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index f482922..e46cf3c 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -2768,9 +2768,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw)
printk(KERN_ERR "%s() timed out\n", __func__);
/* Disable interrupts */
- spin_lock_irq(&priv->tx_lock);
iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
- spin_unlock_irq(&priv->tx_lock);
free_irq(priv->pdev->irq, hw);
/* Stop finalize join worker */
@@ -3461,9 +3459,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
}
/* Disable interrupts */
- spin_lock_irq(&priv->tx_lock);
iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
- spin_unlock_irq(&priv->tx_lock);
free_irq(priv->pdev->irq, hw);
rc = ieee80211_register_hw(hw);
@@ -3487,9 +3483,7 @@ err_stop_firmware:
mwl8k_release_firmware(priv);
err_free_irq:
- spin_lock_irq(&priv->tx_lock);
iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
- spin_unlock_irq(&priv->tx_lock);
free_irq(priv->pdev->irq, hw);
err_free_queues:
--
1.5.6.4
^ permalink raw reply related
* [PATCH 14/29] mwl8k: don't hardcode the number of transmit queues
From: Lennert Buytenhek @ 2009-08-18 3:53 UTC (permalink / raw)
To: linville, linux-wireless
Use MWL8K_TX_QUEUES instead of a hardcoded "4" in a couple of places.
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
---
drivers/net/wireless/mwl8k.c | 14 +++++++-------
1 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 86b6b5d..f482922 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -1080,17 +1080,17 @@ struct mwl8k_txq_info {
};
static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv,
- struct mwl8k_txq_info txinfo[],
- u32 num_queues)
+ struct mwl8k_txq_info *txinfo)
{
int count, desc, status;
struct mwl8k_tx_queue *txq;
struct mwl8k_tx_desc *tx_desc;
int ndescs = 0;
- memset(txinfo, 0, num_queues * sizeof(struct mwl8k_txq_info));
+ memset(txinfo, 0, MWL8K_TX_QUEUES * sizeof(struct mwl8k_txq_info));
+
spin_lock_bh(&priv->tx_lock);
- for (count = 0; count < num_queues; count++) {
+ for (count = 0; count < MWL8K_TX_QUEUES; count++) {
txq = priv->txq + count;
txinfo[count].len = txq->tx_stats.len;
txinfo[count].head = txq->tx_head;
@@ -1135,7 +1135,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms)
spin_unlock_bh(&priv->tx_lock);
if (count) {
- struct mwl8k_txq_info txinfo[4];
+ struct mwl8k_txq_info txinfo[MWL8K_TX_QUEUES];
int index;
int newcount;
@@ -1152,8 +1152,8 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms)
printk(KERN_ERR "%s(%u) TIMEDOUT:%ums Pend:%u-->%u\n",
__func__, __LINE__, delay_ms, count, newcount);
- mwl8k_scan_tx_ring(priv, txinfo, 4);
- for (index = 0; index < 4; index++)
+ mwl8k_scan_tx_ring(priv, txinfo);
+ for (index = 0; index < MWL8K_TX_QUEUES; index++)
printk(KERN_ERR
"TXQ:%u L:%u H:%u T:%u FW:%u DRV:%u U:%u\n",
index,
--
1.5.6.4
^ permalink raw reply related
* [PATCH 13/29] mwl8k: don't touch 'command done' interrupt during firmware load
From: Lennert Buytenhek @ 2009-08-18 3:53 UTC (permalink / raw)
To: linville, linux-wireless
Since firmware load commands don't generate 'command done' interrupts
like normal commands do, polling for command done interrupts just
unnecessarily slows down the firmware load process. Removing this bit
of code speeds up loading a typical firmware image from 840 msec to
180 msec.
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
---
drivers/net/wireless/mwl8k.c | 24 +-----------------------
1 files changed, 1 insertions(+), 23 deletions(-)
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index f4b197b..86b6b5d 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -411,7 +411,6 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length)
{
void __iomem *regs = priv->regs;
dma_addr_t dma_addr;
- int rc;
int loops;
dma_addr = pci_map_single(priv->pdev, data, length, PCI_DMA_TODEVICE);
@@ -425,7 +424,6 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length)
iowrite32(MWL8K_H2A_INT_DUMMY,
regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
- rc = -ETIMEDOUT;
loops = 1000;
do {
u32 int_code;
@@ -433,7 +431,6 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length)
int_code = ioread32(regs + MWL8K_HIU_INT_CODE);
if (int_code == MWL8K_INT_CODE_CMD_FINISHED) {
iowrite32(0, regs + MWL8K_HIU_INT_CODE);
- rc = 0;
break;
}
@@ -442,26 +439,7 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length)
pci_unmap_single(priv->pdev, dma_addr, length, PCI_DMA_TODEVICE);
- /*
- * Clear 'command done' interrupt bit.
- */
- loops = 1000;
- do {
- u32 status;
-
- status = ioread32(priv->regs +
- MWL8K_HIU_A2H_INTERRUPT_STATUS);
- if (status & MWL8K_A2H_INT_OPC_DONE) {
- iowrite32(~MWL8K_A2H_INT_OPC_DONE,
- priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
- ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
- break;
- }
-
- udelay(1);
- } while (--loops);
-
- return rc;
+ return loops ? 0 : -ETIMEDOUT;
}
static int mwl8k_load_fw_image(struct mwl8k_priv *priv,
--
1.5.6.4
^ permalink raw reply related
* [PATCH 12/29] mwl8k: dma header manipulations can't fail
From: Lennert Buytenhek @ 2009-08-18 3:52 UTC (permalink / raw)
To: linville, linux-wireless
Adding and removing the DMA header that the mwl8k hardware requires
on tx and provides on rx can never fail, since we are guaranteed to
have enough headroom on the tx path to expand the packet, and we only
ever shrink the packet on the rx path. (And on both paths we are
guaranteed to be the only user of the skb we are handling.)
This allows removing all of the skb clone handling in the tx and tx
reclaim paths, and eliminates error checks in both the tx and rx
paths, simplifying the code a bit more.
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
---
drivers/net/wireless/mwl8k.c | 83 +++++++-----------------------------------
1 files changed, 13 insertions(+), 70 deletions(-)
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 4580b1d..f4b197b 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -111,17 +111,6 @@ struct mwl8k_rx_queue {
struct sk_buff **rx_skb;
};
-struct mwl8k_skb {
- /*
- * The DMA engine requires a modification to the payload.
- * If the skbuff is shared/cloned, it needs to be unshared.
- * This method is used to ensure the stack always gets back
- * the skbuff it sent for transmission.
- */
- struct sk_buff *clone;
- struct sk_buff *skb;
-};
-
struct mwl8k_tx_queue {
/* hw transmits here */
int tx_head;
@@ -132,7 +121,7 @@ struct mwl8k_tx_queue {
struct ieee80211_tx_queue_stats tx_stats;
struct mwl8k_tx_desc *tx_desc_area;
dma_addr_t tx_desc_dma;
- struct mwl8k_skb *tx_skb;
+ struct sk_buff **tx_skb;
};
/* Pointers to the firmware data and meta information about it. */
@@ -714,12 +703,11 @@ struct mwl8k_dma_data {
} __attribute__((packed));
/* Routines to add/remove DMA header from skb. */
-static inline int mwl8k_remove_dma_header(struct sk_buff *skb)
+static inline void mwl8k_remove_dma_header(struct sk_buff *skb)
{
- struct mwl8k_dma_data *tr = (struct mwl8k_dma_data *)(skb->data);
+ struct mwl8k_dma_data *tr = (struct mwl8k_dma_data *)skb->data;
void *dst, *src = &tr->wh;
- __le16 fc = tr->wh.frame_control;
- int hdrlen = ieee80211_hdrlen(fc);
+ int hdrlen = ieee80211_hdrlen(tr->wh.frame_control);
u16 space = sizeof(struct mwl8k_dma_data) - hdrlen;
dst = (void *)tr + space;
@@ -727,11 +715,9 @@ static inline int mwl8k_remove_dma_header(struct sk_buff *skb)
memmove(dst, src, hdrlen);
skb_pull(skb, space);
}
-
- return 0;
}
-static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb)
+static inline void mwl8k_add_dma_header(struct sk_buff *skb)
{
struct ieee80211_hdr *wh;
u32 hdrlen, pktlen;
@@ -763,8 +749,6 @@ static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb)
* This includes all crypto material including the MIC.
*/
tr->fwlen = cpu_to_le16(pktlen - hdrlen);
-
- return skb;
}
@@ -967,10 +951,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE);
skb_put(skb, le16_to_cpu(rx_desc->pkt_len));
- if (mwl8k_remove_dma_header(skb)) {
- dev_kfree_skb(skb);
- continue;
- }
+ mwl8k_remove_dma_header(skb);
wh = (struct ieee80211_hdr *)skb->data;
@@ -1224,7 +1205,6 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
while (txq->tx_stats.len > 0) {
int tx;
- int rc;
struct mwl8k_tx_desc *tx_desc;
unsigned long addr;
int size;
@@ -1232,7 +1212,6 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
struct ieee80211_tx_info *info;
u32 status;
- rc = 0;
tx = txq->tx_head;
tx_desc = txq->tx_desc_area + tx;
@@ -1252,40 +1231,18 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
addr = le32_to_cpu(tx_desc->pkt_phys_addr);
size = le16_to_cpu(tx_desc->pkt_len);
- skb = txq->tx_skb[tx].skb;
- txq->tx_skb[tx].skb = NULL;
+ skb = txq->tx_skb[tx];
+ txq->tx_skb[tx] = NULL;
BUG_ON(skb == NULL);
pci_unmap_single(priv->pdev, addr, size, PCI_DMA_TODEVICE);
- rc = mwl8k_remove_dma_header(skb);
+ mwl8k_remove_dma_header(skb);
/* Mark descriptor as unused */
tx_desc->pkt_phys_addr = 0;
tx_desc->pkt_len = 0;
- if (txq->tx_skb[tx].clone) {
- /* Replace with original skb
- * before returning to stack
- * as buffer has been cloned
- */
- dev_kfree_skb(skb);
- skb = txq->tx_skb[tx].clone;
- txq->tx_skb[tx].clone = NULL;
- }
-
- if (rc) {
- /* Something has gone wrong here.
- * Failed to remove DMA header.
- * Print error message and drop packet.
- */
- printk(KERN_ERR "%s: Error removing DMA header from "
- "tx skb 0x%p.\n", priv->name, skb);
-
- dev_kfree_skb(skb);
- continue;
- }
-
info = IEEE80211_SKB_CB(skb);
ieee80211_tx_info_clear_status(info);
if (MWL8K_TXD_SUCCESS(status))
@@ -1327,7 +1284,6 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
struct mwl8k_tx_desc *tx;
struct mwl8k_dma_data *tr;
struct mwl8k_vif *mwl8k_vif;
- struct sk_buff *org_skb = skb;
dma_addr_t dma;
u16 qos = 0;
bool qosframe = false, ampduframe = false;
@@ -1338,21 +1294,12 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
txq = priv->txq + index;
tx = txq->tx_desc_area + txq->tx_tail;
- BUG_ON(txq->tx_skb[txq->tx_tail].skb != NULL);
+ BUG_ON(txq->tx_skb[txq->tx_tail] != NULL);
/*
- * Append HW DMA header to start of packet. Drop packet if
- * there is not enough space or a failure to unshare/unclone
- * the skb.
+ * Append HW DMA header to start of packet.
*/
- skb = mwl8k_add_dma_header(skb);
-
- if (skb == NULL) {
- printk(KERN_DEBUG "%s: failed to prepend HW DMA "
- "header, dropping TX frame.\n", priv->name);
- dev_kfree_skb(org_skb);
- return NETDEV_TX_OK;
- }
+ mwl8k_add_dma_header(skb);
tx_info = IEEE80211_SKB_CB(skb);
mwl8k_vif = MWL8K_VIF(tx_info->control.vif);
@@ -1380,8 +1327,6 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
printk(KERN_DEBUG "%s: failed to dma map skb, "
"dropping TX frame.\n", priv->name);
- if (org_skb != NULL)
- dev_kfree_skb(org_skb);
if (skb != NULL)
dev_kfree_skb(skb);
return NETDEV_TX_OK;
@@ -1437,9 +1382,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
tx->pkt_phys_addr = cpu_to_le32(dma);
tx->pkt_len = cpu_to_le16(skb->len);
- txq->tx_skb[txq->tx_tail].skb = skb;
- txq->tx_skb[txq->tx_tail].clone =
- skb == org_skb ? NULL : org_skb;
+ txq->tx_skb[txq->tx_tail] = skb;
spin_lock_bh(&priv->tx_lock);
--
1.5.6.4
^ permalink raw reply related
* [PATCH 11/29] mwl8k: ->add_interface() is not called for monitor interfaces
From: Lennert Buytenhek @ 2009-08-18 3:52 UTC (permalink / raw)
To: linville, linux-wireless
There is no need to check for NL80211_IFTYPE_MONITOR in
->add_interface(), as this function is never called for monitor
interfaces. Also, there is no need to advertise this bit in our
wiphy's ->interface_modes.
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
---
drivers/net/wireless/mwl8k.c | 6 ++----
1 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index e266bc1..4580b1d 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -2883,8 +2883,7 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
/*
* We only support managed interfaces for now.
*/
- if (conf->type != NL80211_IFTYPE_STATION &&
- conf->type != NL80211_IFTYPE_MONITOR)
+ if (conf->type != NL80211_IFTYPE_STATION)
return -EINVAL;
/* Clean out driver private area */
@@ -3444,8 +3443,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
hw->queues = MWL8K_TX_QUEUES;
- hw->wiphy->interface_modes =
- BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_MONITOR);
+ hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
/* Set rssi and noise values to dBm */
hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM;
--
1.5.6.4
^ permalink raw reply related
* [PATCH 10/29] mwl8k: fix mwl8k_configure_filter() parameter lifetime issue
From: Lennert Buytenhek @ 2009-08-18 3:52 UTC (permalink / raw)
To: linville, linux-wireless
mwl8k_configure_filter() passes pointers to total_flags and the
multicast address list to a workqueue function, while there is no
guarantee that those pointers will still be valid by the time the
workqueue function runs.
Solve this by passing total_flags by value, and by passing an
already built multicast address setup command packet to the workqueue
function so that we don't have to look at the multicast address list
itself outside of mwl8k_configure_filter().
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
---
drivers/net/wireless/mwl8k.c | 72 +++++++++++++++++------------------------
1 files changed, 30 insertions(+), 42 deletions(-)
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 3a201a2..e266bc1 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -1613,38 +1613,39 @@ struct mwl8k_cmd_mac_multicast_adr {
#define MWL8K_ENABLE_RX_MULTICAST 0x000F
-static int mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw,
- int mc_count,
- struct dev_addr_list *mclist)
+static struct mwl8k_cmd_pkt *
+__mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw,
+ int mc_count, struct dev_addr_list *mclist)
{
+ struct mwl8k_priv *priv = hw->priv;
struct mwl8k_cmd_mac_multicast_adr *cmd;
- int index = 0;
- int rc;
- int size = sizeof(*cmd) + mc_count * ETH_ALEN;
+ int size;
+ int i;
+
+ if (mc_count > priv->num_mcaddrs)
+ mc_count = priv->num_mcaddrs;
- cmd = kzalloc(size, GFP_KERNEL);
+ size = sizeof(*cmd) + mc_count * ETH_ALEN;
+
+ cmd = kzalloc(size, GFP_ATOMIC);
if (cmd == NULL)
- return -ENOMEM;
+ return NULL;
cmd->header.code = cpu_to_le16(MWL8K_CMD_MAC_MULTICAST_ADR);
cmd->header.length = cpu_to_le16(size);
cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST);
cmd->numaddr = cpu_to_le16(mc_count);
- while (index < mc_count && mclist) {
+ for (i = 0; i < mc_count && mclist; i++) {
if (mclist->da_addrlen != ETH_ALEN) {
- rc = -EINVAL;
- goto mwl8k_cmd_mac_multicast_adr_exit;
+ kfree(cmd);
+ return NULL;
}
- memcpy(cmd->addr[index++], mclist->da_addr, ETH_ALEN);
+ memcpy(cmd->addr[i], mclist->da_addr, ETH_ALEN);
mclist = mclist->next;
}
- rc = mwl8k_post_cmd(hw, &cmd->header);
-
-mwl8k_cmd_mac_multicast_adr_exit:
- kfree(cmd);
- return rc;
+ return &cmd->header;
}
/*
@@ -3101,9 +3102,8 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw,
struct mwl8k_configure_filter_worker {
struct mwl8k_work_struct header;
unsigned int changed_flags;
- unsigned int *total_flags;
- int mc_count;
- struct dev_addr_list *mclist;
+ unsigned int total_flags;
+ struct mwl8k_cmd_pkt *set_multicast_adr;
};
#define MWL8K_SUPPORTED_IF_FLAGS FIF_BCN_PRBRESP_PROMISC
@@ -3112,18 +3112,14 @@ static int mwl8k_configure_filter_wt(struct work_struct *wt)
{
struct mwl8k_configure_filter_worker *worker =
(struct mwl8k_configure_filter_worker *)wt;
-
struct ieee80211_hw *hw = worker->header.hw;
unsigned int changed_flags = worker->changed_flags;
- unsigned int *total_flags = worker->total_flags;
- int mc_count = worker->mc_count;
- struct dev_addr_list *mclist = worker->mclist;
-
+ unsigned int total_flags = worker->total_flags;
struct mwl8k_priv *priv = hw->priv;
int rc = 0;
if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
- if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+ if (total_flags & FIF_BCN_PRBRESP_PROMISC)
rc = mwl8k_cmd_set_pre_scan(hw);
else {
u8 *bssid;
@@ -3136,20 +3132,12 @@ static int mwl8k_configure_filter_wt(struct work_struct *wt)
}
}
- if (rc)
- goto mwl8k_configure_filter_exit;
- if (mc_count) {
- if (mc_count > priv->num_mcaddrs)
- mc_count = priv->num_mcaddrs;
-
- rc = mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist);
- if (rc)
- printk(KERN_ERR
- "%s()Error setting multicast addresses\n",
- __func__);
+ if (worker->set_multicast_adr != NULL) {
+ if (!rc)
+ rc = mwl8k_post_cmd(hw, worker->set_multicast_adr);
+ kfree(worker->set_multicast_adr);
}
-mwl8k_configure_filter_exit:
return rc;
}
@@ -3159,7 +3147,6 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw,
int mc_count,
struct dev_addr_list *mclist)
{
-
struct mwl8k_configure_filter_worker *worker;
struct mwl8k_priv *priv = hw->priv;
@@ -3175,9 +3162,10 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw,
worker->header.options = MWL8K_WQ_QUEUE_ONLY | MWL8K_WQ_TX_WAIT_EMPTY;
worker->changed_flags = changed_flags;
- worker->total_flags = total_flags;
- worker->mc_count = mc_count;
- worker->mclist = mclist;
+ worker->total_flags = *total_flags;
+ if (mc_count)
+ worker->set_multicast_adr =
+ __mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist);
mwl8k_queue_work(hw, &worker->header, priv->config_wq,
mwl8k_configure_filter_wt);
--
1.5.6.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox