Linux wireless drivers development
 help / color / mirror / Atom feed
* [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 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 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 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 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 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 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 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 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 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 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 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

* 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] 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 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

* 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 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 09/29] mwl8k: remove usage of deprecated radio_enabled
From: Johannes Berg @ 2009-08-18  7:28 UTC (permalink / raw)
  To: Lennert Buytenhek; +Cc: linville, linux-wireless
In-Reply-To: <20090818035220.GN18639@mail.wantstofly.org>

[-- Attachment #1: Type: text/plain, Size: 942 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) {
>  		mwl8k_cmd_802_11_radio_disable(hw);
>  		priv->current_channel = NULL;
>  		rc = 0;

So I think the return; a little below needs to be removed to allow doing
other things while the radio is off? I'm not sure which actually happen
but I never audited the code to make sure nothing happens.

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: Lennert Buytenhek @ 2009-08-18  8:13 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linville, linux-wireless
In-Reply-To: <1250580198.30538.0.camel@johannes.local>

On Tue, Aug 18, 2009 at 09:23:18AM +0200, Johannes Berg 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().

OK, if my patch set gets applied first, please use the mwl8k
->prepare_multicast() implementation that's below in your patch.

If your patch gets applied first, I'll fix it up in my set.



diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 2c7c85d..316a728 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -2654,26 +2654,33 @@ out:
 	mwl8k_fw_unlock(hw);
 }
 
-struct mwl8k_configure_filter_worker {
-	struct work_struct wt;
-	struct ieee80211_hw *hw;
-	unsigned int changed_flags;
-	unsigned int total_flags;
-	struct mwl8k_cmd_pkt *set_multicast_adr;
-};
+static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw,
+				   int mc_count, struct dev_addr_list *mclist)
+{
+	struct mwl8k_cmd_pkt *cmd;
+
+	cmd = __mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist);
 
-static void mwl8k_configure_filter_wt(struct work_struct *wt)
+	return (unsigned long)cmd;
+}
+
+static void mwl8k_configure_filter(struct ieee80211_hw *hw,
+				   unsigned int changed_flags,
+				   unsigned int *total_flags,
+				   u64 multicast)
 {
-	struct mwl8k_configure_filter_worker *worker =
-		(struct mwl8k_configure_filter_worker *)wt;
-	struct ieee80211_hw *hw = worker->hw;
 	struct mwl8k_priv *priv = hw->priv;
+	struct mwl8k_cmd_pkt *multicast_adr_cmd =
+		(void *)(unsigned long)multicast;
+
+	/* Clear unsupported feature flags */
+	*total_flags &= FIF_BCN_PRBRESP_PROMISC;
 
 	if (mwl8k_fw_lock(hw))
-		return;
+		goto out;
 
-	if (worker->changed_flags & FIF_BCN_PRBRESP_PROMISC) {
-		if (worker->total_flags & FIF_BCN_PRBRESP_PROMISC)
+	if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+		if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
 			mwl8k_cmd_set_pre_scan(hw);
 		else {
 			u8 *bssid;
@@ -2686,44 +2693,13 @@ static void mwl8k_configure_filter_wt(struct work_struct *wt)
 		}
 	}
 
-	if (worker->set_multicast_adr != NULL) {
-		mwl8k_post_cmd(hw, worker->set_multicast_adr);
-		kfree(worker->set_multicast_adr);
-	}
+	if (multicast_adr_cmd != NULL)
+		mwl8k_post_cmd(hw, multicast_adr_cmd);
 
 	mwl8k_fw_unlock(hw);
 
-	kfree(worker);
-}
-
-static void mwl8k_configure_filter(struct ieee80211_hw *hw,
-				   unsigned int changed_flags,
-				   unsigned int *total_flags,
-				   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 &= FIF_BCN_PRBRESP_PROMISC;
-
-	if (!(changed_flags & FIF_BCN_PRBRESP_PROMISC) && !mc_count)
-		return;
-
-	worker = kzalloc(sizeof(*worker), GFP_ATOMIC);
-	if (worker == NULL)
-		return;
-
-	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);
-
-	INIT_WORK(&worker->wt, mwl8k_configure_filter_wt);
-	queue_work(priv->config_wq, &worker->wt);
+out:
+	kfree(multicast_adr_cmd);
 }
 
 static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
@@ -2787,6 +2763,7 @@ static const struct ieee80211_ops mwl8k_ops = {
 	.remove_interface	= mwl8k_remove_interface,
 	.config			= mwl8k_config,
 	.bss_info_changed	= mwl8k_bss_info_changed,
+	.prepare_multicast	= mwl8k_prepare_multicast,
 	.configure_filter	= mwl8k_configure_filter,
 	.set_rts_threshold	= mwl8k_set_rts_threshold,
 	.conf_tx		= mwl8k_conf_tx,

^ permalink raw reply related

* Re: [PATCH 09/29] mwl8k: remove usage of deprecated radio_enabled
From: Lennert Buytenhek @ 2009-08-18  8:24 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linville, linux-wireless
In-Reply-To: <1250580466.30538.1.camel@johannes.local>

On Tue, Aug 18, 2009 at 09:27:46AM +0200, Johannes Berg 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?

The hardware would accept those commands, but they wouldn't have any
effect, since the radio is off.  If/when we then go out of idle later,
the channel set and power set and antenna config commands will be run,
so we'll end up with the right parameters.

^ permalink raw reply

* Re: [PATCH 09/29] mwl8k: remove usage of deprecated radio_enabled
From: Lennert Buytenhek @ 2009-08-18  8:25 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linville, linux-wireless
In-Reply-To: <1250580509.30538.2.camel@johannes.local>

On Tue, Aug 18, 2009 at 09:28:29AM +0200, Johannes Berg 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) {
> >  		mwl8k_cmd_802_11_radio_disable(hw);
> >  		priv->current_channel = NULL;
> >  		rc = 0;
> 
> So I think the return; a little below needs to be removed to allow doing
> other things while the radio is off? I'm not sure which actually happen
> but I never audited the code to make sure nothing happens.

The logic is just:

	if (idle) {
		issue "radio disable" command
	} else {
		issue "radio enable" command
		set channel
		set tx power
		set antenna config
	}

So if a channel change hapens while we are idle, that event won't get
lost -- it'll just happen later.

^ permalink raw reply

* Re: [PATCH 09/29] mwl8k: remove usage of deprecated radio_enabled
From: Johannes Berg @ 2009-08-18  8:26 UTC (permalink / raw)
  To: Lennert Buytenhek; +Cc: linville, linux-wireless
In-Reply-To: <20090818082537.GK18639@mail.wantstofly.org>

[-- Attachment #1: Type: text/plain, Size: 407 bytes --]

On Tue, 2009-08-18 at 10:25 +0200, Lennert Buytenhek wrote:

> The logic is just:
> 
> 	if (idle) {
> 		issue "radio disable" command
> 	} else {
> 		issue "radio enable" command
> 		set channel
> 		set tx power
> 		set antenna config
> 	}
> 
> So if a channel change hapens while we are idle, that event won't get
> lost -- it'll just happen later.

Ok, yeah, that looks fine.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply

* Re: [PATCH] mac80211: Decouple fail_avg stats used by mesh from rate control algorithm.
From: Johannes Berg @ 2009-08-18  8:45 UTC (permalink / raw)
  To: Javier Cardona; +Cc: linux-wireless, andrey, linville, devel
In-Reply-To: <1250554555-32259-1-git-send-email-javier@cozybit.com>

[-- Attachment #1: Type: text/plain, Size: 625 bytes --]

On Mon, 2009-08-17 at 17:15 -0700, Javier Cardona wrote:
> Mesh uses the tx failure average to compute the (m)path metric.  This used to
> be done inside the rate control module.  This patch breaks the dependency
> between the mesh stack and the rate control algorithm.  Mesh will now work
> independently of the chosen rate control algorithm.
> 
> The mesh stack keeps a moving average of the average transmission losses for
> each mesh peer station.  If the fail average exceeds a certain threshold, the
> peer link is marked as broken.

Looks good, means it can also work for ath9k etc. eventually.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply

* Re: [PATCH 09/29] mwl8k: remove usage of deprecated radio_enabled
From: Lennert Buytenhek @ 2009-08-18  9:52 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linville, linux-wireless
In-Reply-To: <1250583993.30538.3.camel@johannes.local>

On Tue, Aug 18, 2009 at 10:26:33AM +0200, Johannes Berg wrote:

> > The logic is just:
> > 
> > 	if (idle) {
> > 		issue "radio disable" command
> > 	} else {
> > 		issue "radio enable" command
> > 		set channel
> > 		set tx power
> > 		set antenna config
> > 	}
> > 
> > So if a channel change hapens while we are idle, that event won't get
> > lost -- it'll just happen later.
> 
> Ok, yeah, that looks fine.

OK, thanks.

Since your patch is already in, I've replaced this patch by:


>From 1af73ff8d1309b924f6f4accd61245b57374dd78 Mon Sep 17 00:00:00 2001
From: Lennert Buytenhek <buytenh@wantstofly.org>
Date: Mon, 17 Aug 2009 23:59:40 +0200
Subject: [PATCH 15/29] mwl8k: implement rfkill

By checking IEEE80211_CONF_CHANGE_IDLE in mwl8k_config().

Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
---
 drivers/net/wireless/mwl8k.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 177d92f..65eefe8 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -2854,6 +2854,12 @@ static int mwl8k_config_wt(struct work_struct *wt)
 	struct mwl8k_priv *priv = hw->priv;
 	int rc = 0;
 
+	if (conf->flags & IEEE80211_CONF_IDLE) {
+		mwl8k_cmd_802_11_radio_disable(hw);
+		priv->current_channel = NULL;
+		goto mwl8k_config_exit;
+	}
+
 	if (mwl8k_cmd_802_11_radio_enable(hw)) {
 		rc = -EINVAL;
 		goto mwl8k_config_exit;
-- 
1.5.6.4

^ permalink raw reply related

* Re: [PATCH 10/29] mwl8k: fix mwl8k_configure_filter() parameter lifetime issue
From: Lennert Buytenhek @ 2009-08-18  9:54 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linville, linux-wireless
In-Reply-To: <20090818081339.GI18639@mail.wantstofly.org>

On Tue, Aug 18, 2009 at 10:13:39AM +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().
> 
> OK, if my patch set gets applied first, please use the mwl8k
> ->prepare_multicast() implementation that's below in your patch.
> 
> If your patch gets applied first, I'll fix it up in my set.

OK, your patch is already in, as you noted on IRC, so I've replaced
this by:



>From 9145398d5822cf3ed963fb155a2771c4facd1d85 Mon Sep 17 00:00:00 2001
From: Lennert Buytenhek <buytenh@wantstofly.org>
Date: Tue, 18 Aug 2009 03:55:42 +0200
Subject: [PATCH 09/29] mwl8k: fix mwl8k_configure_filter() parameter lifetime issue

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().

Also, since ->configure_filter() can sleep now, wait synchronously
for the worker to finish.

Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
---
 drivers/net/wireless/mwl8k.c |  107 +++++++++++++++--------------------------
 1 files changed, 39 insertions(+), 68 deletions(-)

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index a40434b..a961b69 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;
+
+	size = sizeof(*cmd) + mc_count * ETH_ALEN;
 
-	cmd = kzalloc(size, GFP_KERNEL);
+	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;
 }
 
 /*
@@ -3091,12 +3092,21 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw,
 		printk(KERN_ERR "%s() timed out\n", __func__);
 }
 
+static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw,
+				   int mc_count, struct dev_addr_list *mclist)
+{
+	struct mwl8k_cmd_pkt *cmd;
+
+	cmd = __mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist);
+
+	return (unsigned long)cmd;
+}
+
 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 *multicast_adr_cmd;
 };
 
 #define MWL8K_SUPPORTED_IF_FLAGS	FIF_BCN_PRBRESP_PROMISC
@@ -3105,18 +3115,12 @@ 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;
-
 	struct mwl8k_priv *priv = hw->priv;
 	int rc = 0;
 
-	if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
-		if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+	if (worker->changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+		if (worker->total_flags & FIF_BCN_PRBRESP_PROMISC)
 			rc = mwl8k_cmd_set_pre_scan(hw);
 		else {
 			u8 *bssid;
@@ -3129,54 +3133,20 @@ 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 (!rc && worker->multicast_adr_cmd != NULL)
+		rc = mwl8k_post_cmd(hw, worker->multicast_adr_cmd);
+	kfree(worker->multicast_adr_cmd);
 
-mwl8k_configure_filter_exit:
 	return rc;
 }
 
-static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw,
-				   int mc_count, struct dev_addr_list *mclist)
-{
-	struct mwl8k_configure_filter_worker *worker;
-
-	worker = kzalloc(sizeof(*worker), GFP_ATOMIC);
-
-	if (!worker)
-		return 0;
-
-	/*
-	 * XXX: This is _HORRIBLY_ broken!!
-	 *
-	 *	No locking, the mclist pointer might be invalid as soon as this
-	 *	function returns, something in the list might be invalidated
-	 *	once we get to the worker, etc...
-	 */
-	worker->mc_count = mc_count;
-	worker->mclist = mclist;
-
-	return (u64)worker;
-}
-
 static void mwl8k_configure_filter(struct ieee80211_hw *hw,
 				   unsigned int changed_flags,
 				   unsigned int *total_flags,
 				   u64 multicast)
 {
-
-	struct mwl8k_configure_filter_worker *worker = (void *)multicast;
 	struct mwl8k_priv *priv = hw->priv;
+	struct mwl8k_configure_filter_worker *worker;
 
 	/* Clear unsupported feature flags */
 	*total_flags &= MWL8K_SUPPORTED_IF_FLAGS;
@@ -3184,12 +3154,13 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw,
 	if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS))
 		return;
 
+	worker = kzalloc(sizeof(*worker), GFP_ATOMIC);
 	if (worker == NULL)
 		return;
 
-	worker->header.options = MWL8K_WQ_QUEUE_ONLY | MWL8K_WQ_TX_WAIT_EMPTY;
 	worker->changed_flags = changed_flags;
-	worker->total_flags = total_flags;
+	worker->total_flags = *total_flags;
+	worker->multicast_adr_cmd = (void *)(unsigned long)multicast;
 
 	mwl8k_queue_work(hw, &worker->header, priv->config_wq,
 			 mwl8k_configure_filter_wt);
-- 
1.5.6.4

^ permalink raw reply related


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