Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH 22/28] mwl8k: add the commands used for AP firmware initialisation
From: Lennert Buytenhek @ 2009-10-22 18:21 UTC (permalink / raw)
  To: linux-wireless

Add the AP version of the GET_HW_SPEC command, as well as the
SET_HW_SPEC command, for initialising AP firmware.

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 5ccea17..4a70ce1 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -274,6 +274,7 @@ static const struct ieee80211_rate mwl8k_rates[] = {
 /* Firmware command codes */
 #define MWL8K_CMD_CODE_DNLD		0x0001
 #define MWL8K_CMD_GET_HW_SPEC		0x0003
+#define MWL8K_CMD_SET_HW_SPEC		0x0004
 #define MWL8K_CMD_MAC_MULTICAST_ADR	0x0010
 #define MWL8K_CMD_GET_STAT		0x0014
 #define MWL8K_CMD_RADIO_CONTROL		0x001c
@@ -304,6 +305,7 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize)
 	switch (cmd & ~0x8000) {
 		MWL8K_CMDNAME(CODE_DNLD);
 		MWL8K_CMDNAME(GET_HW_SPEC);
+		MWL8K_CMDNAME(SET_HW_SPEC);
 		MWL8K_CMDNAME(MAC_MULTICAST_ADR);
 		MWL8K_CMDNAME(GET_STAT);
 		MWL8K_CMDNAME(RADIO_CONTROL);
@@ -1595,6 +1597,129 @@ static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw)
 }
 
 /*
+ * CMD_GET_HW_SPEC (AP version).
+ */
+struct mwl8k_cmd_get_hw_spec_ap {
+	struct mwl8k_cmd_pkt header;
+	__u8 hw_rev;
+	__u8 host_interface;
+	__le16 num_wcb;
+	__le16 num_mcaddrs;
+	__u8 perm_addr[ETH_ALEN];
+	__le16 region_code;
+	__le16 num_antenna;
+	__le32 fw_rev;
+	__le32 wcbbase0;
+	__le32 rxwrptr;
+	__le32 rxrdptr;
+	__le32 ps_cookie;
+	__le32 wcbbase1;
+	__le32 wcbbase2;
+	__le32 wcbbase3;
+} __attribute__((packed));
+
+static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw)
+{
+	struct mwl8k_priv *priv = hw->priv;
+	struct mwl8k_cmd_get_hw_spec_ap *cmd;
+	int rc;
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (cmd == NULL)
+		return -ENOMEM;
+
+	cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_HW_SPEC);
+	cmd->header.length = cpu_to_le16(sizeof(*cmd));
+
+	memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr));
+	cmd->ps_cookie = cpu_to_le32(priv->cookie_dma);
+
+	rc = mwl8k_post_cmd(hw, &cmd->header);
+
+	if (!rc) {
+		int off;
+
+		SET_IEEE80211_PERM_ADDR(hw, cmd->perm_addr);
+		priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs);
+		priv->fw_rev = le32_to_cpu(cmd->fw_rev);
+		priv->hw_rev = cmd->hw_rev;
+
+		off = le32_to_cpu(cmd->wcbbase0) & 0xffff;
+		iowrite32(cpu_to_le32(priv->txq[0].txd_dma), priv->sram + off);
+
+		off = le32_to_cpu(cmd->rxwrptr) & 0xffff;
+		iowrite32(cpu_to_le32(priv->rxq[0].rxd_dma), priv->sram + off);
+
+		off = le32_to_cpu(cmd->rxrdptr) & 0xffff;
+		iowrite32(cpu_to_le32(priv->rxq[0].rxd_dma), priv->sram + off);
+
+		off = le32_to_cpu(cmd->wcbbase1) & 0xffff;
+		iowrite32(cpu_to_le32(priv->txq[1].txd_dma), priv->sram + off);
+
+		off = le32_to_cpu(cmd->wcbbase2) & 0xffff;
+		iowrite32(cpu_to_le32(priv->txq[2].txd_dma), priv->sram + off);
+
+		off = le32_to_cpu(cmd->wcbbase3) & 0xffff;
+		iowrite32(cpu_to_le32(priv->txq[3].txd_dma), priv->sram + off);
+	}
+
+	kfree(cmd);
+	return rc;
+}
+
+/*
+ * CMD_SET_HW_SPEC.
+ */
+struct mwl8k_cmd_set_hw_spec {
+	struct mwl8k_cmd_pkt header;
+	__u8 hw_rev;
+	__u8 host_interface;
+	__le16 num_mcaddrs;
+	__u8 perm_addr[ETH_ALEN];
+	__le16 region_code;
+	__le32 fw_rev;
+	__le32 ps_cookie;
+	__le32 caps;
+	__le32 rx_queue_ptr;
+	__le32 num_tx_queues;
+	__le32 tx_queue_ptrs[MWL8K_TX_QUEUES];
+	__le32 flags;
+	__le32 num_tx_desc_per_queue;
+	__le32 total_rxd;
+} __attribute__((packed));
+
+#define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT	0x00000080
+
+static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw)
+{
+	struct mwl8k_priv *priv = hw->priv;
+	struct mwl8k_cmd_set_hw_spec *cmd;
+	int rc;
+	int i;
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (cmd == NULL)
+		return -ENOMEM;
+
+	cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_HW_SPEC);
+	cmd->header.length = cpu_to_le16(sizeof(*cmd));
+
+	cmd->ps_cookie = cpu_to_le32(priv->cookie_dma);
+	cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma);
+	cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES);
+	for (i = 0; i < MWL8K_TX_QUEUES; i++)
+		cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma);
+	cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT);
+	cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS);
+	cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS);
+
+	rc = mwl8k_post_cmd(hw, &cmd->header);
+	kfree(cmd);
+
+	return rc;
+}
+
+/*
  * CMD_MAC_MULTICAST_ADR.
  */
 struct mwl8k_cmd_mac_multicast_adr {
@@ -3210,7 +3335,13 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 	iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
 
 	/* Get config data, mac addrs etc */
-	rc = mwl8k_cmd_get_hw_spec_sta(hw);
+	if (priv->ap_fw) {
+		rc = mwl8k_cmd_get_hw_spec_ap(hw);
+		if (!rc)
+			rc = mwl8k_cmd_set_hw_spec(hw);
+	} else {
+		rc = mwl8k_cmd_get_hw_spec_sta(hw);
+	}
 	if (rc) {
 		printk(KERN_ERR "%s: Cannot initialise firmware\n",
 		       wiphy_name(hw->wiphy));
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 21/28] mwl8k: rename mwl8k_cmd_get_hw_spec() to mwl8k_cmd_get_hw_spec_sta()
From: Lennert Buytenhek @ 2009-10-22 18:21 UTC (permalink / raw)
  To: linux-wireless

As the AP version of the command uses a different format.

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 38d34ae..5ccea17 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -1537,9 +1537,9 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
 }
 
 /*
- * GET_HW_SPEC.
+ * CMD_GET_HW_SPEC (STA version).
  */
-struct mwl8k_cmd_get_hw_spec {
+struct mwl8k_cmd_get_hw_spec_sta {
 	struct mwl8k_cmd_pkt header;
 	__u8 hw_rev;
 	__u8 host_interface;
@@ -1558,10 +1558,10 @@ struct mwl8k_cmd_get_hw_spec {
 	__le32 total_rxd;
 } __attribute__((packed));
 
-static int mwl8k_cmd_get_hw_spec(struct ieee80211_hw *hw)
+static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw)
 {
 	struct mwl8k_priv *priv = hw->priv;
-	struct mwl8k_cmd_get_hw_spec *cmd;
+	struct mwl8k_cmd_get_hw_spec_sta *cmd;
 	int rc;
 	int i;
 
@@ -3210,7 +3210,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 	iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
 
 	/* Get config data, mac addrs etc */
-	rc = mwl8k_cmd_get_hw_spec(hw);
+	rc = mwl8k_cmd_get_hw_spec_sta(hw);
 	if (rc) {
 		printk(KERN_ERR "%s: Cannot initialise firmware\n",
 		       wiphy_name(hw->wiphy));
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 26/28] mwl8k: add AP firmware (mbss) handling to mwl8k_set_mac_addr()
From: Lennert Buytenhek @ 2009-10-22 18:21 UTC (permalink / raw)
  To: linux-wireless

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index b2c68b2..4eda6f9 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -2134,11 +2134,18 @@ static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable)
  */
 struct mwl8k_cmd_set_mac_addr {
 	struct mwl8k_cmd_pkt header;
-	__u8 mac_addr[ETH_ALEN];
+	union {
+		struct {
+			__le16 mac_type;
+			__u8 mac_addr[ETH_ALEN];
+		} mbss;
+		__u8 mac_addr[ETH_ALEN];
+	};
 } __attribute__((packed));
 
 static int mwl8k_set_mac_addr(struct ieee80211_hw *hw, u8 *mac)
 {
+	struct mwl8k_priv *priv = hw->priv;
 	struct mwl8k_cmd_set_mac_addr *cmd;
 	int rc;
 
@@ -2148,7 +2155,12 @@ static int mwl8k_set_mac_addr(struct ieee80211_hw *hw, u8 *mac)
 
 	cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR);
 	cmd->header.length = cpu_to_le16(sizeof(*cmd));
-	memcpy(cmd->mac_addr, mac, ETH_ALEN);
+	if (priv->ap_fw) {
+		cmd->mbss.mac_type = 0;
+		memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN);
+	} else {
+		memcpy(cmd->mac_addr, mac, ETH_ALEN);
+	}
 
 	rc = mwl8k_post_cmd(hw, &cmd->header);
 	kfree(cmd);
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 16/28] mwl8k: spell out the names of firmware images in the pci driver data
From: Lennert Buytenhek @ 2009-10-22 18:20 UTC (permalink / raw)
  To: linux-wireless

To allow use of a more flexible firmware file naming scheme.

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 49edd0c..37b3f31 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -80,7 +80,9 @@
 #define MWL8K_TX_QUEUES		4
 
 struct mwl8k_device_info {
-	int part_num;
+	char *part_name;
+	char *helper_image;
+	char *fw_image;
 };
 
 struct mwl8k_rx_queue {
@@ -112,11 +114,11 @@ struct mwl8k_tx_queue {
 
 /* Pointers to the firmware data and meta information about it.  */
 struct mwl8k_firmware {
-	/* Microcode */
-	struct firmware *ucode;
-
 	/* Boot helper code */
 	struct firmware *helper;
+
+	/* Microcode */
+	struct firmware *ucode;
 };
 
 struct mwl8k_priv {
@@ -355,26 +357,23 @@ static int mwl8k_request_fw(struct mwl8k_priv *priv,
 
 static int mwl8k_request_firmware(struct mwl8k_priv *priv)
 {
-	u8 filename[64];
+	struct mwl8k_device_info *di = priv->device_info;
 	int rc;
 
-	snprintf(filename, sizeof(filename),
-		 "mwl8k/helper_%u.fw", priv->device_info->part_num);
-
-	rc = mwl8k_request_fw(priv, filename, &priv->fw.helper);
-	if (rc) {
-		printk(KERN_ERR "%s: Error requesting helper firmware "
-		       "file %s\n", pci_name(priv->pdev), filename);
-		return rc;
+	if (di->helper_image != NULL) {
+		rc = mwl8k_request_fw(priv, di->helper_image, &priv->fw.helper);
+		if (rc) {
+			printk(KERN_ERR "%s: Error requesting helper "
+			       "firmware file %s\n", pci_name(priv->pdev),
+			       di->helper_image);
+			return rc;
+		}
 	}
 
-	snprintf(filename, sizeof(filename),
-		 "mwl8k/fmimage_%u.fw", priv->device_info->part_num);
-
-	rc = mwl8k_request_fw(priv, filename, &priv->fw.ucode);
+	rc = mwl8k_request_fw(priv, di->fw_image, &priv->fw.ucode);
 	if (rc) {
 		printk(KERN_ERR "%s: Error requesting firmware file %s\n",
-		       pci_name(priv->pdev), filename);
+		       pci_name(priv->pdev), di->fw_image);
 		mwl8k_release_fw(&priv->fw.helper);
 		return rc;
 	}
@@ -2937,7 +2936,9 @@ static void mwl8k_finalize_join_worker(struct work_struct *work)
 }
 
 static struct mwl8k_device_info di_8687 = {
-	.part_num	= 8687,
+	.part_name	= "88w8687",
+	.helper_image	= "mwl8k/helper_8687.fw",
+	.fw_image	= "mwl8k/fmimage_8687.fw",
 };
 
 static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
@@ -3163,8 +3164,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 		goto err_stop_firmware;
 	}
 
-	printk(KERN_INFO "%s: 88w%u v%d, %pM, firmware version %u.%u.%u.%u\n",
-	       wiphy_name(hw->wiphy), priv->device_info->part_num,
+	printk(KERN_INFO "%s: %s v%d, %pM, firmware version %u.%u.%u.%u\n",
+	       wiphy_name(hw->wiphy), priv->device_info->part_name,
 	       priv->hw_rev, hw->wiphy->perm_addr,
 	       (priv->fw_rev >> 24) & 0xff, (priv->fw_rev >> 16) & 0xff,
 	       (priv->fw_rev >> 8) & 0xff, priv->fw_rev & 0xff);
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 13/28] mwl8k: shorten receive/transmit state variable names
From: Lennert Buytenhek @ 2009-10-22 18:20 UTC (permalink / raw)
  To: linux-wireless

To conserve horizontal space.

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 60b0076..f282550 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -87,30 +87,30 @@ MODULE_DEVICE_TABLE(pci, mwl8k_table);
 #define MWL8K_TX_QUEUES		4
 
 struct mwl8k_rx_queue {
-	int rx_desc_count;
+	int rxd_count;
 
 	/* hw receives here */
-	int rx_head;
+	int head;
 
 	/* refill descs here */
-	int rx_tail;
+	int tail;
 
-	struct mwl8k_rx_desc *rx_desc_area;
-	dma_addr_t rx_desc_dma;
-	struct sk_buff **rx_skb;
+	struct mwl8k_rx_desc *rxd;
+	dma_addr_t rxd_dma;
+	struct sk_buff **skb;
 };
 
 struct mwl8k_tx_queue {
 	/* hw transmits here */
-	int tx_head;
+	int head;
 
 	/* sw appends here */
-	int tx_tail;
+	int tail;
 
-	struct ieee80211_tx_queue_stats tx_stats;
-	struct mwl8k_tx_desc *tx_desc_area;
-	dma_addr_t tx_desc_dma;
-	struct sk_buff **tx_skb;
+	struct ieee80211_tx_queue_stats stats;
+	struct mwl8k_tx_desc *txd;
+	dma_addr_t txd_dma;
+	struct sk_buff **skb;
 };
 
 /* Pointers to the firmware data and meta information about it.  */
@@ -737,7 +737,7 @@ struct mwl8k_rx_desc {
 	__u8 link_quality;
 	__u8 noise_level;
 	__le32 pkt_phys_addr;
-	__le32 next_rx_desc_phys_addr;
+	__le32 next_rxd_phys_addr;
 	__le16 qos_control;
 	__le16 rate_info;
 	__le32 pad0[4];
@@ -766,42 +766,38 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index)
 	int size;
 	int i;
 
-	rxq->rx_desc_count = 0;
-	rxq->rx_head = 0;
-	rxq->rx_tail = 0;
+	rxq->rxd_count = 0;
+	rxq->head = 0;
+	rxq->tail = 0;
 
 	size = MWL8K_RX_DESCS * sizeof(struct mwl8k_rx_desc);
 
-	rxq->rx_desc_area =
-		pci_alloc_consistent(priv->pdev, size, &rxq->rx_desc_dma);
-	if (rxq->rx_desc_area == NULL) {
+	rxq->rxd = pci_alloc_consistent(priv->pdev, size, &rxq->rxd_dma);
+	if (rxq->rxd == NULL) {
 		printk(KERN_ERR "%s: failed to alloc RX descriptors\n",
 		       wiphy_name(hw->wiphy));
 		return -ENOMEM;
 	}
-	memset(rxq->rx_desc_area, 0, size);
+	memset(rxq->rxd, 0, size);
 
-	rxq->rx_skb = kmalloc(MWL8K_RX_DESCS *
-				sizeof(*rxq->rx_skb), GFP_KERNEL);
-	if (rxq->rx_skb == NULL) {
+	rxq->skb = kmalloc(MWL8K_RX_DESCS * sizeof(*rxq->skb), GFP_KERNEL);
+	if (rxq->skb == NULL) {
 		printk(KERN_ERR "%s: failed to alloc RX skbuff list\n",
 		       wiphy_name(hw->wiphy));
-		pci_free_consistent(priv->pdev, size,
-				    rxq->rx_desc_area, rxq->rx_desc_dma);
+		pci_free_consistent(priv->pdev, size, rxq->rxd, rxq->rxd_dma);
 		return -ENOMEM;
 	}
-	memset(rxq->rx_skb, 0, MWL8K_RX_DESCS * sizeof(*rxq->rx_skb));
+	memset(rxq->skb, 0, MWL8K_RX_DESCS * sizeof(*rxq->skb));
 
 	for (i = 0; i < MWL8K_RX_DESCS; i++) {
 		struct mwl8k_rx_desc *rx_desc;
 		int nexti;
 
-		rx_desc = rxq->rx_desc_area + i;
+		rx_desc = rxq->rxd + i;
 		nexti = (i + 1) % MWL8K_RX_DESCS;
 
-		rx_desc->next_rx_desc_phys_addr =
-			cpu_to_le32(rxq->rx_desc_dma
-						+ nexti * sizeof(*rx_desc));
+		rx_desc->next_rxd_phys_addr =
+			cpu_to_le32(rxq->rxd_dma + nexti * sizeof(*rx_desc));
 		rx_desc->rx_ctrl = MWL8K_RX_CTRL_OWNED_BY_HOST;
 	}
 
@@ -815,7 +811,7 @@ static int rxq_refill(struct ieee80211_hw *hw, int index, int limit)
 	int refilled;
 
 	refilled = 0;
-	while (rxq->rx_desc_count < MWL8K_RX_DESCS && limit--) {
+	while (rxq->rxd_count < MWL8K_RX_DESCS && limit--) {
 		struct sk_buff *skb;
 		int rx;
 
@@ -823,19 +819,19 @@ static int rxq_refill(struct ieee80211_hw *hw, int index, int limit)
 		if (skb == NULL)
 			break;
 
-		rxq->rx_desc_count++;
+		rxq->rxd_count++;
 
-		rx = rxq->rx_tail;
-		rxq->rx_tail = (rx + 1) % MWL8K_RX_DESCS;
+		rx = rxq->tail;
+		rxq->tail = (rx + 1) % MWL8K_RX_DESCS;
 
-		rxq->rx_desc_area[rx].pkt_phys_addr =
+		rxq->rxd[rx].pkt_phys_addr =
 			cpu_to_le32(pci_map_single(priv->pdev, skb->data,
 					MWL8K_RX_MAXSZ, DMA_FROM_DEVICE));
 
-		rxq->rx_desc_area[rx].pkt_len = cpu_to_le16(MWL8K_RX_MAXSZ);
-		rxq->rx_skb[rx] = skb;
+		rxq->rxd[rx].pkt_len = cpu_to_le16(MWL8K_RX_MAXSZ);
+		rxq->skb[rx] = skb;
 		wmb();
-		rxq->rx_desc_area[rx].rx_ctrl = 0;
+		rxq->rxd[rx].rx_ctrl = 0;
 
 		refilled++;
 	}
@@ -851,24 +847,24 @@ static void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index)
 	int i;
 
 	for (i = 0; i < MWL8K_RX_DESCS; i++) {
-		if (rxq->rx_skb[i] != NULL) {
+		if (rxq->skb[i] != NULL) {
 			unsigned long addr;
 
-			addr = le32_to_cpu(rxq->rx_desc_area[i].pkt_phys_addr);
+			addr = le32_to_cpu(rxq->rxd[i].pkt_phys_addr);
 			pci_unmap_single(priv->pdev, addr, MWL8K_RX_MAXSZ,
 					 PCI_DMA_FROMDEVICE);
-			kfree_skb(rxq->rx_skb[i]);
-			rxq->rx_skb[i] = NULL;
+			kfree_skb(rxq->skb[i]);
+			rxq->skb[i] = NULL;
 		}
 	}
 
-	kfree(rxq->rx_skb);
-	rxq->rx_skb = NULL;
+	kfree(rxq->skb);
+	rxq->skb = NULL;
 
 	pci_free_consistent(priv->pdev,
 			    MWL8K_RX_DESCS * sizeof(struct mwl8k_rx_desc),
-			    rxq->rx_desc_area, rxq->rx_desc_dma);
-	rxq->rx_desc_area = NULL;
+			    rxq->rxd, rxq->rxd_dma);
+	rxq->rxd = NULL;
 }
 
 
@@ -909,7 +905,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
 	int processed;
 
 	processed = 0;
-	while (rxq->rx_desc_count && limit--) {
+	while (rxq->rxd_count && limit--) {
 		struct mwl8k_rx_desc *rx_desc;
 		struct sk_buff *skb;
 		struct ieee80211_rx_status status;
@@ -917,18 +913,18 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
 		struct ieee80211_hdr *wh;
 		u16 rate_info;
 
-		rx_desc = rxq->rx_desc_area + rxq->rx_head;
+		rx_desc = rxq->rxd + rxq->head;
 		if (!(rx_desc->rx_ctrl & MWL8K_RX_CTRL_OWNED_BY_HOST))
 			break;
 		rmb();
 
-		skb = rxq->rx_skb[rxq->rx_head];
+		skb = rxq->skb[rxq->head];
 		if (skb == NULL)
 			break;
-		rxq->rx_skb[rxq->rx_head] = NULL;
+		rxq->skb[rxq->head] = NULL;
 
-		rxq->rx_head = (rxq->rx_head + 1) % MWL8K_RX_DESCS;
-		rxq->rx_desc_count--;
+		rxq->head = (rxq->head + 1) % MWL8K_RX_DESCS;
+		rxq->rxd_count--;
 
 		addr = le32_to_cpu(rx_desc->pkt_phys_addr);
 		pci_unmap_single(priv->pdev, addr,
@@ -999,7 +995,7 @@ struct mwl8k_tx_desc {
 	__le32 pkt_phys_addr;
 	__le16 pkt_len;
 	__u8 dest_MAC_addr[ETH_ALEN];
-	__le32 next_tx_desc_phys_addr;
+	__le32 next_txd_phys_addr;
 	__le32 reserved;
 	__le16 rate_info;
 	__u8 peer_id;
@@ -1015,44 +1011,40 @@ static int mwl8k_txq_init(struct ieee80211_hw *hw, int index)
 	int size;
 	int i;
 
-	memset(&txq->tx_stats, 0, sizeof(struct ieee80211_tx_queue_stats));
-	txq->tx_stats.limit = MWL8K_TX_DESCS;
-	txq->tx_head = 0;
-	txq->tx_tail = 0;
+	memset(&txq->stats, 0, sizeof(struct ieee80211_tx_queue_stats));
+	txq->stats.limit = MWL8K_TX_DESCS;
+	txq->head = 0;
+	txq->tail = 0;
 
 	size = MWL8K_TX_DESCS * sizeof(struct mwl8k_tx_desc);
 
-	txq->tx_desc_area =
-		pci_alloc_consistent(priv->pdev, size, &txq->tx_desc_dma);
-	if (txq->tx_desc_area == NULL) {
+	txq->txd = pci_alloc_consistent(priv->pdev, size, &txq->txd_dma);
+	if (txq->txd == NULL) {
 		printk(KERN_ERR "%s: failed to alloc TX descriptors\n",
 		       wiphy_name(hw->wiphy));
 		return -ENOMEM;
 	}
-	memset(txq->tx_desc_area, 0, size);
+	memset(txq->txd, 0, size);
 
-	txq->tx_skb = kmalloc(MWL8K_TX_DESCS * sizeof(*txq->tx_skb),
-								GFP_KERNEL);
-	if (txq->tx_skb == NULL) {
+	txq->skb = kmalloc(MWL8K_TX_DESCS * sizeof(*txq->skb), GFP_KERNEL);
+	if (txq->skb == NULL) {
 		printk(KERN_ERR "%s: failed to alloc TX skbuff list\n",
 		       wiphy_name(hw->wiphy));
-		pci_free_consistent(priv->pdev, size,
-				    txq->tx_desc_area, txq->tx_desc_dma);
+		pci_free_consistent(priv->pdev, size, txq->txd, txq->txd_dma);
 		return -ENOMEM;
 	}
-	memset(txq->tx_skb, 0, MWL8K_TX_DESCS * sizeof(*txq->tx_skb));
+	memset(txq->skb, 0, MWL8K_TX_DESCS * sizeof(*txq->skb));
 
 	for (i = 0; i < MWL8K_TX_DESCS; i++) {
 		struct mwl8k_tx_desc *tx_desc;
 		int nexti;
 
-		tx_desc = txq->tx_desc_area + i;
+		tx_desc = txq->txd + i;
 		nexti = (i + 1) % MWL8K_TX_DESCS;
 
 		tx_desc->status = 0;
-		tx_desc->next_tx_desc_phys_addr =
-			cpu_to_le32(txq->tx_desc_dma +
-						nexti * sizeof(*tx_desc));
+		tx_desc->next_txd_phys_addr =
+			cpu_to_le32(txq->txd_dma + nexti * sizeof(*tx_desc));
 	}
 
 	return 0;
@@ -1088,11 +1080,11 @@ static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv,
 
 	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;
-		txinfo[count].tail = txq->tx_tail;
+		txinfo[count].len = txq->stats.len;
+		txinfo[count].head = txq->head;
+		txinfo[count].tail = txq->tail;
 		for (desc = 0; desc < MWL8K_TX_DESCS; desc++) {
-			tx_desc = txq->tx_desc_area + desc;
+			tx_desc = txq->txd + desc;
 			status = le32_to_cpu(tx_desc->status);
 
 			if (status & MWL8K_TXD_STATUS_FW_OWNED)
@@ -1173,7 +1165,7 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
 	struct mwl8k_tx_queue *txq = priv->txq + index;
 	int wake = 0;
 
-	while (txq->tx_stats.len > 0) {
+	while (txq->stats.len > 0) {
 		int tx;
 		struct mwl8k_tx_desc *tx_desc;
 		unsigned long addr;
@@ -1182,8 +1174,8 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
 		struct ieee80211_tx_info *info;
 		u32 status;
 
-		tx = txq->tx_head;
-		tx_desc = txq->tx_desc_area + tx;
+		tx = txq->head;
+		tx_desc = txq->txd + tx;
 
 		status = le32_to_cpu(tx_desc->status);
 
@@ -1194,15 +1186,15 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
 				~cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED);
 		}
 
-		txq->tx_head = (tx + 1) % MWL8K_TX_DESCS;
-		BUG_ON(txq->tx_stats.len == 0);
-		txq->tx_stats.len--;
+		txq->head = (tx + 1) % MWL8K_TX_DESCS;
+		BUG_ON(txq->stats.len == 0);
+		txq->stats.len--;
 		priv->pending_tx_pkts--;
 
 		addr = le32_to_cpu(tx_desc->pkt_phys_addr);
 		size = le16_to_cpu(tx_desc->pkt_len);
-		skb = txq->tx_skb[tx];
-		txq->tx_skb[tx] = NULL;
+		skb = txq->skb[tx];
+		txq->skb[tx] = NULL;
 
 		BUG_ON(skb == NULL);
 		pci_unmap_single(priv->pdev, addr, size, PCI_DMA_TODEVICE);
@@ -1235,13 +1227,13 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index)
 
 	mwl8k_txq_reclaim(hw, index, 1);
 
-	kfree(txq->tx_skb);
-	txq->tx_skb = NULL;
+	kfree(txq->skb);
+	txq->skb = NULL;
 
 	pci_free_consistent(priv->pdev,
 			    MWL8K_TX_DESCS * sizeof(struct mwl8k_tx_desc),
-			    txq->tx_desc_area, txq->tx_desc_dma);
-	txq->tx_desc_area = NULL;
+			    txq->txd, txq->txd_dma);
+	txq->txd = NULL;
 }
 
 static int
@@ -1318,10 +1310,10 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
 
 	txq = priv->txq + index;
 
-	BUG_ON(txq->tx_skb[txq->tx_tail] != NULL);
-	txq->tx_skb[txq->tx_tail] = skb;
+	BUG_ON(txq->skb[txq->tail] != NULL);
+	txq->skb[txq->tail] = skb;
 
-	tx = txq->tx_desc_area + txq->tx_tail;
+	tx = txq->txd + txq->tail;
 	tx->data_rate = txdatarate;
 	tx->tx_priority = index;
 	tx->qos_control = cpu_to_le16(qos);
@@ -1332,15 +1324,15 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
 	wmb();
 	tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus);
 
-	txq->tx_stats.count++;
-	txq->tx_stats.len++;
+	txq->stats.count++;
+	txq->stats.len++;
 	priv->pending_tx_pkts++;
 
-	txq->tx_tail++;
-	if (txq->tx_tail == MWL8K_TX_DESCS)
-		txq->tx_tail = 0;
+	txq->tail++;
+	if (txq->tail == MWL8K_TX_DESCS)
+		txq->tail = 0;
 
-	if (txq->tx_head == txq->tx_tail)
+	if (txq->head == txq->tail)
 		ieee80211_stop_queue(hw, index);
 
 	mwl8k_tx_start(priv);
@@ -1491,7 +1483,7 @@ struct mwl8k_cmd_get_hw_spec {
 	__le32 tx_queue_ptrs[MWL8K_TX_QUEUES];
 	__le32 caps2;
 	__le32 num_tx_desc_per_queue;
-	__le32 total_rx_desc;
+	__le32 total_rxd;
 } __attribute__((packed));
 
 static int mwl8k_cmd_get_hw_spec(struct ieee80211_hw *hw)
@@ -1510,12 +1502,12 @@ static int mwl8k_cmd_get_hw_spec(struct ieee80211_hw *hw)
 
 	memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr));
 	cmd->ps_cookie = cpu_to_le32(priv->cookie_dma);
-	cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rx_desc_dma);
+	cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma);
 	cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES);
 	for (i = 0; i < MWL8K_TX_QUEUES; i++)
-		cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].tx_desc_dma);
+		cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma);
 	cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS);
-	cmd->total_rx_desc = cpu_to_le32(MWL8K_RX_DESCS);
+	cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS);
 
 	rc = mwl8k_post_cmd(hw, &cmd->header);
 
@@ -2887,7 +2879,7 @@ static int mwl8k_get_tx_stats(struct ieee80211_hw *hw,
 	spin_lock_bh(&priv->tx_lock);
 	for (index = 0; index < MWL8K_TX_QUEUES; index++) {
 		txq = priv->txq + index;
-		memcpy(&stats[index], &txq->tx_stats,
+		memcpy(&stats[index], &txq->stats,
 			sizeof(struct ieee80211_tx_queue_stats));
 	}
 	spin_unlock_bh(&priv->tx_lock);
-- 
1.5.6.4


^ permalink raw reply related

* [PATCH 20/28] mwl8k: set ->interface_modes from the driver data
From: Lennert Buytenhek @ 2009-10-22 18:21 UTC (permalink / raw)
  To: linux-wireless

As different chip/firmware combinations support different
interface types.

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 9c10c88..38d34ae 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -91,6 +91,7 @@ struct mwl8k_device_info {
 	char *helper_image;
 	char *fw_image;
 	struct rxd_ops *rxd_ops;
+	u16 modes;
 };
 
 struct mwl8k_rx_queue {
@@ -3015,6 +3016,7 @@ static struct mwl8k_device_info di_8687 = {
 	.helper_image	= "mwl8k/helper_8687.fw",
 	.fw_image	= "mwl8k/fmimage_8687.fw",
 	.rxd_ops	= &rxd_8687_ops,
+	.modes		= BIT(NL80211_IFTYPE_STATION),
 };
 
 static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
@@ -3121,7 +3123,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 
 	hw->queues = MWL8K_TX_QUEUES;
 
-	hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+	hw->wiphy->interface_modes = priv->device_info->modes;
 
 	/* 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 14/28] mwl8k: pci BAR mapping changes
From: Lennert Buytenhek @ 2009-10-22 18:20 UTC (permalink / raw)
  To: linux-wireless

Map BAR0 as well, as we need to write to it during init on some chips.

Also, if BAR0 is a 64bit BAR, the register BAR becomes BAR2, so try
mapping BAR2 if mapping BAR1 fails.

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index f282550..7aea8eb 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -123,6 +123,7 @@ struct mwl8k_firmware {
 };
 
 struct mwl8k_priv {
+	void __iomem *sram;
 	void __iomem *regs;
 	struct ieee80211_hw *hw;
 
@@ -2986,13 +2987,27 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 	SET_IEEE80211_DEV(hw, &pdev->dev);
 	pci_set_drvdata(pdev, hw);
 
-	priv->regs = pci_iomap(pdev, 1, 0x10000);
-	if (priv->regs == NULL) {
-		printk(KERN_ERR "%s: Cannot map device memory\n",
+	priv->sram = pci_iomap(pdev, 0, 0x10000);
+	if (priv->sram == NULL) {
+		printk(KERN_ERR "%s: Cannot map device SRAM\n",
 		       wiphy_name(hw->wiphy));
 		goto err_iounmap;
 	}
 
+	/*
+	 * If BAR0 is a 32 bit BAR, the register BAR will be BAR1.
+	 * If BAR0 is a 64 bit BAR, the register BAR will be BAR2.
+	 */
+	priv->regs = pci_iomap(pdev, 1, 0x10000);
+	if (priv->regs == NULL) {
+		priv->regs = pci_iomap(pdev, 2, 0x10000);
+		if (priv->regs == NULL) {
+			printk(KERN_ERR "%s: Cannot map device registers\n",
+			       wiphy_name(hw->wiphy));
+			goto err_iounmap;
+		}
+	}
+
 	memcpy(priv->channels, mwl8k_channels, sizeof(mwl8k_channels));
 	priv->band.band = IEEE80211_BAND_2GHZ;
 	priv->band.channels = priv->channels;
@@ -3164,6 +3179,9 @@ err_iounmap:
 	if (priv->regs != NULL)
 		pci_iounmap(pdev, priv->regs);
 
+	if (priv->sram != NULL)
+		pci_iounmap(pdev, priv->sram);
+
 	pci_set_drvdata(pdev, NULL);
 	ieee80211_free_hw(hw);
 
@@ -3211,6 +3229,7 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev)
 	pci_free_consistent(priv->pdev, 4, priv->cookie, priv->cookie_dma);
 
 	pci_iounmap(pdev, priv->regs);
+	pci_iounmap(pdev, priv->sram);
 	pci_set_drvdata(pdev, NULL);
 	ieee80211_free_hw(hw);
 	pci_release_regions(pdev);
-- 
1.5.6.4


^ permalink raw reply related

* [PATCH 24/28] mwl8k: add AP firmware handling to ->configure_filter()
From: Lennert Buytenhek @ 2009-10-22 18:21 UTC (permalink / raw)
  To: linux-wireless

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 0e26a96..815f73f 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -3013,6 +3013,16 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw,
 	struct mwl8k_cmd_pkt *cmd = (void *)(unsigned long)multicast;
 
 	/*
+	 * AP firmware doesn't allow fine-grained control over
+	 * the receive filter.
+	 */
+	if (priv->ap_fw) {
+		*total_flags &= FIF_ALLMULTI | FIF_BCN_PRBRESP_PROMISC;
+		kfree(cmd);
+		return;
+	}
+
+	/*
 	 * Enable hardware sniffer mode if FIF_CONTROL or
 	 * FIF_OTHER_BSS is requested.
 	 */
-- 
1.5.6.4


^ permalink raw reply related

* [PATCH 15/28] mwl8k: change pci id table driver data to a structure pointer
From: Lennert Buytenhek @ 2009-10-22 18:20 UTC (permalink / raw)
  To: linux-wireless

To prepare for adding support for more device types, introduce a
new structure, mwl8k_device_info, where per-device information can
be stored, and change the pci id table driver data from an integer
indicating only the part number to a pointer to a mwl8k_device_info
structure.

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 7aea8eb..49edd0c 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -27,13 +27,6 @@
 #define MWL8K_NAME	KBUILD_MODNAME
 #define MWL8K_VERSION	"0.10"
 
-static DEFINE_PCI_DEVICE_TABLE(mwl8k_table) = {
-	{ PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = 8687, },
-	{ PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = 8687, },
-	{ }
-};
-MODULE_DEVICE_TABLE(pci, mwl8k_table);
-
 /* Register definitions */
 #define MWL8K_HIU_GEN_PTR			0x00000c10
 #define  MWL8K_MODE_STA				 0x0000005a
@@ -86,6 +79,10 @@ MODULE_DEVICE_TABLE(pci, mwl8k_table);
 #define MWL8K_RX_QUEUES		1
 #define MWL8K_TX_QUEUES		4
 
+struct mwl8k_device_info {
+	int part_num;
+};
+
 struct mwl8k_rx_queue {
 	int rxd_count;
 
@@ -129,9 +126,10 @@ struct mwl8k_priv {
 
 	struct pci_dev *pdev;
 
+	struct mwl8k_device_info *device_info;
+
 	/* firmware files and meta data */
 	struct mwl8k_firmware fw;
-	u32 part_num;
 
 	/* firmware access */
 	struct mutex fw_mutex;
@@ -355,15 +353,13 @@ static int mwl8k_request_fw(struct mwl8k_priv *priv,
 				fname, &priv->pdev->dev);
 }
 
-static int mwl8k_request_firmware(struct mwl8k_priv *priv, u32 part_num)
+static int mwl8k_request_firmware(struct mwl8k_priv *priv)
 {
 	u8 filename[64];
 	int rc;
 
-	priv->part_num = part_num;
-
 	snprintf(filename, sizeof(filename),
-		 "mwl8k/helper_%u.fw", priv->part_num);
+		 "mwl8k/helper_%u.fw", priv->device_info->part_num);
 
 	rc = mwl8k_request_fw(priv, filename, &priv->fw.helper);
 	if (rc) {
@@ -373,7 +369,7 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv, u32 part_num)
 	}
 
 	snprintf(filename, sizeof(filename),
-		 "mwl8k/fmimage_%u.fw", priv->part_num);
+		 "mwl8k/fmimage_%u.fw", priv->device_info->part_num);
 
 	rc = mwl8k_request_fw(priv, filename, &priv->fw.ucode);
 	if (rc) {
@@ -2940,6 +2936,22 @@ static void mwl8k_finalize_join_worker(struct work_struct *work)
 	priv->beacon_skb = NULL;
 }
 
+static struct mwl8k_device_info di_8687 = {
+	.part_num	= 8687,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
+	{
+		PCI_VDEVICE(MARVELL, 0x2a2b),
+		.driver_data = (unsigned long)&di_8687,
+	}, {
+		PCI_VDEVICE(MARVELL, 0x2a30),
+		.driver_data = (unsigned long)&di_8687,
+	}, {
+	},
+};
+MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table);
+
 static int __devinit mwl8k_probe(struct pci_dev *pdev,
 				 const struct pci_device_id *id)
 {
@@ -2980,6 +2992,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 	priv = hw->priv;
 	priv->hw = hw;
 	priv->pdev = pdev;
+	priv->device_info = (void *)id->driver_data;
 	priv->sniffer_enabled = false;
 	priv->wmm_enabled = false;
 	priv->pending_tx_pkts = 0;
@@ -3091,7 +3104,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 	mwl8k_hw_reset(priv);
 
 	/* Ask userland hotplug daemon for the device firmware */
-	rc = mwl8k_request_firmware(priv, (u32)id->driver_data);
+	rc = mwl8k_request_firmware(priv);
 	if (rc) {
 		printk(KERN_ERR "%s: Firmware files not found\n",
 		       wiphy_name(hw->wiphy));
@@ -3151,8 +3164,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 	}
 
 	printk(KERN_INFO "%s: 88w%u v%d, %pM, firmware version %u.%u.%u.%u\n",
-	       wiphy_name(hw->wiphy), priv->part_num, priv->hw_rev,
-	       hw->wiphy->perm_addr,
+	       wiphy_name(hw->wiphy), priv->device_info->part_num,
+	       priv->hw_rev, hw->wiphy->perm_addr,
 	       (priv->fw_rev >> 24) & 0xff, (priv->fw_rev >> 16) & 0xff,
 	       (priv->fw_rev >> 8) & 0xff, priv->fw_rev & 0xff);
 
@@ -3238,7 +3251,7 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev)
 
 static struct pci_driver mwl8k_driver = {
 	.name		= MWL8K_NAME,
-	.id_table	= mwl8k_table,
+	.id_table	= mwl8k_pci_id_table,
 	.probe		= mwl8k_probe,
 	.remove		= __devexit_p(mwl8k_remove),
 	.shutdown	= __devexit_p(mwl8k_shutdown),
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 18/28] mwl8k: use pci_unmap_addr{,set}() to keep track of unmap addresses on rx
From: Lennert Buytenhek @ 2009-10-22 18:20 UTC (permalink / raw)
  To: linux-wireless

Instead of reading back the unmap address from the receive
descriptor when doing receive processing, use DECLARE_PCI_UNMAP_ADDR
and pci_unmap_addr{,set}() to keep track of these addresses.

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 703c306..96faec6 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -96,7 +96,10 @@ struct mwl8k_rx_queue {
 
 	struct mwl8k_rx_desc *rxd;
 	dma_addr_t rxd_dma;
-	struct sk_buff **skb;
+	struct {
+		struct sk_buff *skb;
+		DECLARE_PCI_UNMAP_ADDR(dma)
+	} *buf;
 };
 
 struct mwl8k_tx_queue {
@@ -790,14 +793,14 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index)
 	}
 	memset(rxq->rxd, 0, size);
 
-	rxq->skb = kmalloc(MWL8K_RX_DESCS * sizeof(*rxq->skb), GFP_KERNEL);
-	if (rxq->skb == NULL) {
+	rxq->buf = kmalloc(MWL8K_RX_DESCS * sizeof(*rxq->buf), GFP_KERNEL);
+	if (rxq->buf == NULL) {
 		printk(KERN_ERR "%s: failed to alloc RX skbuff list\n",
 		       wiphy_name(hw->wiphy));
 		pci_free_consistent(priv->pdev, size, rxq->rxd, rxq->rxd_dma);
 		return -ENOMEM;
 	}
-	memset(rxq->skb, 0, MWL8K_RX_DESCS * sizeof(*rxq->skb));
+	memset(rxq->buf, 0, MWL8K_RX_DESCS * sizeof(*rxq->buf));
 
 	for (i = 0; i < MWL8K_RX_DESCS; i++) {
 		struct mwl8k_rx_desc *rx_desc;
@@ -823,6 +826,7 @@ static int rxq_refill(struct ieee80211_hw *hw, int index, int limit)
 	refilled = 0;
 	while (rxq->rxd_count < MWL8K_RX_DESCS && limit--) {
 		struct sk_buff *skb;
+		dma_addr_t addr;
 		int rx;
 
 		skb = dev_alloc_skb(MWL8K_RX_MAXSZ);
@@ -834,12 +838,13 @@ static int rxq_refill(struct ieee80211_hw *hw, int index, int limit)
 		rx = rxq->tail;
 		rxq->tail = (rx + 1) % MWL8K_RX_DESCS;
 
-		rxq->rxd[rx].pkt_phys_addr =
-			cpu_to_le32(pci_map_single(priv->pdev, skb->data,
-					MWL8K_RX_MAXSZ, DMA_FROM_DEVICE));
+		addr = pci_map_single(priv->pdev, skb->data,
+				      MWL8K_RX_MAXSZ, DMA_FROM_DEVICE);
 
 		rxq->rxd[rx].pkt_len = cpu_to_le16(MWL8K_RX_MAXSZ);
-		rxq->skb[rx] = skb;
+		rxq->rxd[rx].pkt_phys_addr = cpu_to_le32(addr);
+		rxq->buf[rx].skb = skb;
+		pci_unmap_addr_set(&rxq->buf[rx], dma, addr);
 		wmb();
 		rxq->rxd[rx].rx_ctrl = 0;
 
@@ -857,19 +862,19 @@ static void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index)
 	int i;
 
 	for (i = 0; i < MWL8K_RX_DESCS; i++) {
-		if (rxq->skb[i] != NULL) {
-			unsigned long addr;
-
-			addr = le32_to_cpu(rxq->rxd[i].pkt_phys_addr);
-			pci_unmap_single(priv->pdev, addr, MWL8K_RX_MAXSZ,
-					 PCI_DMA_FROMDEVICE);
-			kfree_skb(rxq->skb[i]);
-			rxq->skb[i] = NULL;
+		if (rxq->buf[i].skb != NULL) {
+			pci_unmap_single(priv->pdev,
+					 pci_unmap_addr(&rxq->buf[i], dma),
+					 MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE);
+			pci_unmap_addr_set(&rxq->buf[i], dma, 0);
+
+			kfree_skb(rxq->buf[i].skb);
+			rxq->buf[i].skb = NULL;
 		}
 	}
 
-	kfree(rxq->skb);
-	rxq->skb = NULL;
+	kfree(rxq->buf);
+	rxq->buf = NULL;
 
 	pci_free_consistent(priv->pdev,
 			    MWL8K_RX_DESCS * sizeof(struct mwl8k_rx_desc),
@@ -919,7 +924,6 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
 		struct mwl8k_rx_desc *rx_desc;
 		struct sk_buff *skb;
 		struct ieee80211_rx_status status;
-		unsigned long addr;
 		struct ieee80211_hdr *wh;
 		u16 rate_info;
 
@@ -928,18 +932,19 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
 			break;
 		rmb();
 
-		skb = rxq->skb[rxq->head];
+		skb = rxq->buf[rxq->head].skb;
 		if (skb == NULL)
 			break;
-		rxq->skb[rxq->head] = NULL;
+		rxq->buf[rxq->head].skb = NULL;
+
+		pci_unmap_single(priv->pdev,
+				 pci_unmap_addr(&rxq->buf[rxq->head], dma),
+				 MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE);
+		pci_unmap_addr_set(&rxq->buf[rxq->head], dma, 0);
 
 		rxq->head = (rxq->head + 1) % MWL8K_RX_DESCS;
 		rxq->rxd_count--;
 
-		addr = le32_to_cpu(rx_desc->pkt_phys_addr);
-		pci_unmap_single(priv->pdev, addr,
-					MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE);
-
 		skb_put(skb, le16_to_cpu(rx_desc->pkt_len));
 		mwl8k_remove_dma_header(skb);
 
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 23/28] mwl8k: implement AP firmware antenna configuration
From: Lennert Buytenhek @ 2009-10-22 18:21 UTC (permalink / raw)
  To: linux-wireless

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 4a70ce1..0e26a96 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -279,6 +279,7 @@ static const struct ieee80211_rate mwl8k_rates[] = {
 #define MWL8K_CMD_GET_STAT		0x0014
 #define MWL8K_CMD_RADIO_CONTROL		0x001c
 #define MWL8K_CMD_RF_TX_POWER		0x001e
+#define MWL8K_CMD_RF_ANTENNA		0x0020
 #define MWL8K_CMD_SET_PRE_SCAN		0x0107
 #define MWL8K_CMD_SET_POST_SCAN		0x0108
 #define MWL8K_CMD_SET_RF_CHANNEL	0x010a
@@ -310,6 +311,7 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize)
 		MWL8K_CMDNAME(GET_STAT);
 		MWL8K_CMDNAME(RADIO_CONTROL);
 		MWL8K_CMDNAME(RF_TX_POWER);
+		MWL8K_CMDNAME(RF_ANTENNA);
 		MWL8K_CMDNAME(SET_PRE_SCAN);
 		MWL8K_CMDNAME(SET_POST_SCAN);
 		MWL8K_CMDNAME(SET_RF_CHANNEL);
@@ -1918,6 +1920,39 @@ static int mwl8k_cmd_802_11_rf_tx_power(struct ieee80211_hw *hw, int dBm)
 }
 
 /*
+ * CMD_RF_ANTENNA.
+ */
+struct mwl8k_cmd_rf_antenna {
+	struct mwl8k_cmd_pkt header;
+	__le16 antenna;
+	__le16 mode;
+} __attribute__((packed));
+
+#define MWL8K_RF_ANTENNA_RX		1
+#define MWL8K_RF_ANTENNA_TX		2
+
+static int
+mwl8k_cmd_rf_antenna(struct ieee80211_hw *hw, int antenna, int mask)
+{
+	struct mwl8k_cmd_rf_antenna *cmd;
+	int rc;
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (cmd == NULL)
+		return -ENOMEM;
+
+	cmd->header.code = cpu_to_le16(MWL8K_CMD_RF_ANTENNA);
+	cmd->header.length = cpu_to_le16(sizeof(*cmd));
+	cmd->antenna = cpu_to_le16(antenna);
+	cmd->mode = cpu_to_le16(mask);
+
+	rc = mwl8k_post_cmd(hw, &cmd->header);
+	kfree(cmd);
+
+	return rc;
+}
+
+/*
  * CMD_SET_PRE_SCAN.
  */
 struct mwl8k_cmd_set_pre_scan {
@@ -2831,8 +2866,13 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
 	if (rc)
 		goto out;
 
-	if (mwl8k_cmd_mimo_config(hw, 0x7, 0x7))
-		rc = -EINVAL;
+	if (priv->ap_fw) {
+		rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x7);
+		if (!rc)
+			rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_TX, 0x7);
+	} else {
+		rc = mwl8k_cmd_mimo_config(hw, 0x7, 0x7);
+	}
 
 out:
 	mwl8k_fw_unlock(hw);
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 25/28] mwl8k: add AP firmware handling to ->start()
From: Lennert Buytenhek @ 2009-10-22 18:21 UTC (permalink / raw)
  To: linux-wireless

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 815f73f..b2c68b2 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -2712,12 +2712,17 @@ static int mwl8k_start(struct ieee80211_hw *hw)
 	if (!rc) {
 		rc = mwl8k_cmd_802_11_radio_enable(hw);
 
-		if (!rc)
-			rc = mwl8k_cmd_set_pre_scan(hw);
+		if (!priv->ap_fw) {
+			if (!rc)
+				rc = mwl8k_enable_sniffer(hw, 0);
 
-		if (!rc)
-			rc = mwl8k_cmd_set_post_scan(hw,
-					"\x00\x00\x00\x00\x00\x00");
+			if (!rc)
+				rc = mwl8k_cmd_set_pre_scan(hw);
+
+			if (!rc)
+				rc = mwl8k_cmd_set_post_scan(hw,
+						"\x00\x00\x00\x00\x00\x00");
+		}
 
 		if (!rc)
 			rc = mwl8k_cmd_setrateadaptmode(hw, 0);
@@ -2725,9 +2730,6 @@ static int mwl8k_start(struct ieee80211_hw *hw)
 		if (!rc)
 			rc = mwl8k_set_wmm(hw, 0);
 
-		if (!rc)
-			rc = mwl8k_enable_sniffer(hw, 0);
-
 		mwl8k_fw_unlock(hw);
 	}
 
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 17/28] mwl8k: handle loading AP firmware images
From: Lennert Buytenhek @ 2009-10-22 18:20 UTC (permalink / raw)
  To: linux-wireless

AP and STA firmware images provide a different signature in the
HIU_INT_CODE register after loading.  Record which of the signatures
we saw, as it determines which command sequences to use later on.

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 37b3f31..703c306 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -129,6 +129,7 @@ struct mwl8k_priv {
 	struct pci_dev *pdev;
 
 	struct mwl8k_device_info *device_info;
+	bool ap_fw;
 
 	/* firmware files and meta data */
 	struct mwl8k_firmware fw;
@@ -533,6 +534,7 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw)
 {
 	struct mwl8k_priv *priv = hw->priv;
 	struct firmware *fw = priv->fw.ucode;
+	struct mwl8k_device_info *di = priv->device_info;
 	int rc;
 	int loops;
 
@@ -564,14 +566,26 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw)
 		return rc;
 	}
 
-	iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR);
+	if (di->modes & BIT(NL80211_IFTYPE_AP))
+		iowrite32(MWL8K_MODE_AP, priv->regs + MWL8K_HIU_GEN_PTR);
+	else
+		iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR);
 	msleep(1);
 
 	loops = 200000;
 	do {
-		if (ioread32(priv->regs + MWL8K_HIU_INT_CODE)
-						== MWL8K_FWSTA_READY)
+		u32 ready_code;
+
+		ready_code = ioread32(priv->regs + MWL8K_HIU_INT_CODE);
+		if (ready_code == MWL8K_FWAP_READY) {
+			priv->ap_fw = 1;
+			break;
+		} else if (ready_code == MWL8K_FWSTA_READY) {
+			priv->ap_fw = 0;
 			break;
+		}
+
+		cond_resched();
 		udelay(1);
 	} while (--loops);
 
@@ -3164,9 +3178,10 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 		goto err_stop_firmware;
 	}
 
-	printk(KERN_INFO "%s: %s v%d, %pM, firmware version %u.%u.%u.%u\n",
+	printk(KERN_INFO "%s: %s v%d, %pM, %s firmware %u.%u.%u.%u\n",
 	       wiphy_name(hw->wiphy), priv->device_info->part_name,
 	       priv->hw_rev, hw->wiphy->perm_addr,
+	       priv->ap_fw ? "AP" : "STA",
 	       (priv->fw_rev >> 24) & 0xff, (priv->fw_rev >> 16) & 0xff,
 	       (priv->fw_rev >> 8) & 0xff, priv->fw_rev & 0xff);
 
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 27/28] mwl8k: implement AP firmware EDCA parameter configuration
From: Lennert Buytenhek @ 2009-10-22 18:21 UTC (permalink / raw)
  To: linux-wireless

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 4eda6f9..8e4631a 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -2271,17 +2271,34 @@ struct mwl8k_cmd_set_edca_params {
 	/* TX opportunity in units of 32 us */
 	__le16 txop;
 
-	/* Log exponent of max contention period: 0...15*/
-	__u8 log_cw_max;
+	union {
+		struct {
+			/* Log exponent of max contention period: 0...15 */
+			__le32 log_cw_max;
+
+			/* Log exponent of min contention period: 0...15 */
+			__le32 log_cw_min;
+
+			/* Adaptive interframe spacing in units of 32us */
+			__u8 aifs;
+
+			/* TX queue to configure */
+			__u8 txq;
+		} ap;
+		struct {
+			/* Log exponent of max contention period: 0...15 */
+			__u8 log_cw_max;
 
-	/* Log exponent of min contention period: 0...15 */
-	__u8 log_cw_min;
+			/* Log exponent of min contention period: 0...15 */
+			__u8 log_cw_min;
 
-	/* Adaptive interframe spacing in units of 32us */
-	__u8 aifs;
+			/* Adaptive interframe spacing in units of 32us */
+			__u8 aifs;
 
-	/* TX queue to configure */
-	__u8 txq;
+			/* TX queue to configure */
+			__u8 txq;
+		} sta;
+	};
 } __attribute__((packed));
 
 #define MWL8K_SET_EDCA_CW	0x01
@@ -2297,6 +2314,7 @@ mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum,
 		__u16 cw_min, __u16 cw_max,
 		__u8 aifs, __u16 txop)
 {
+	struct mwl8k_priv *priv = hw->priv;
 	struct mwl8k_cmd_set_edca_params *cmd;
 	int rc;
 
@@ -2314,10 +2332,17 @@ mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum,
 	cmd->header.length = cpu_to_le16(sizeof(*cmd));
 	cmd->action = cpu_to_le16(MWL8K_SET_EDCA_ALL);
 	cmd->txop = cpu_to_le16(txop);
-	cmd->log_cw_max = (u8)ilog2(cw_max + 1);
-	cmd->log_cw_min = (u8)ilog2(cw_min + 1);
-	cmd->aifs = aifs;
-	cmd->txq = qnum;
+	if (priv->ap_fw) {
+		cmd->ap.log_cw_max = cpu_to_le32(ilog2(cw_max + 1));
+		cmd->ap.log_cw_min = cpu_to_le32(ilog2(cw_min + 1));
+		cmd->ap.aifs = aifs;
+		cmd->ap.txq = qnum;
+	} else {
+		cmd->sta.log_cw_max = (u8)ilog2(cw_max + 1);
+		cmd->sta.log_cw_min = (u8)ilog2(cw_min + 1);
+		cmd->sta.aifs = aifs;
+		cmd->sta.txq = qnum;
+	}
 
 	rc = mwl8k_post_cmd(hw, &cmd->header);
 	kfree(cmd);
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 28/28] mwl8k: add support for the 88w8366
From: Lennert Buytenhek @ 2009-10-22 18:21 UTC (permalink / raw)
  To: linux-wireless

Add support for the 88w8366 firmware receive descriptor format,
and add the 88w8366 PCI ID.

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 8e4631a..40075d4 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -755,7 +755,89 @@ static inline void mwl8k_add_dma_header(struct sk_buff *skb)
 
 
 /*
- * Packet reception.
+ * Packet reception for 88w8366.
+ */
+struct mwl8k_rxd_8366 {
+	__le16 pkt_len;
+	__u8 sq2;
+	__u8 rate;
+	__le32 pkt_phys_addr;
+	__le32 next_rxd_phys_addr;
+	__le16 qos_control;
+	__le16 htsig2;
+	__le32 hw_rssi_info;
+	__le32 hw_noise_floor_info;
+	__u8 noise_floor;
+	__u8 pad0[3];
+	__u8 rssi;
+	__u8 rx_status;
+	__u8 channel;
+	__u8 rx_ctrl;
+} __attribute__((packed));
+
+#define MWL8K_8366_RX_CTRL_OWNED_BY_HOST	0x80
+
+static void mwl8k_rxd_8366_init(void *_rxd, dma_addr_t next_dma_addr)
+{
+	struct mwl8k_rxd_8366 *rxd = _rxd;
+
+	rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr);
+	rxd->rx_ctrl = MWL8K_8366_RX_CTRL_OWNED_BY_HOST;
+}
+
+static void mwl8k_rxd_8366_refill(void *_rxd, dma_addr_t addr, int len)
+{
+	struct mwl8k_rxd_8366 *rxd = _rxd;
+
+	rxd->pkt_len = cpu_to_le16(len);
+	rxd->pkt_phys_addr = cpu_to_le32(addr);
+	wmb();
+	rxd->rx_ctrl = 0;
+}
+
+static int
+mwl8k_rxd_8366_process(void *_rxd, struct ieee80211_rx_status *status)
+{
+	struct mwl8k_rxd_8366 *rxd = _rxd;
+
+	if (!(rxd->rx_ctrl & MWL8K_8366_RX_CTRL_OWNED_BY_HOST))
+		return -1;
+	rmb();
+
+	memset(status, 0, sizeof(*status));
+
+	status->signal = -rxd->rssi;
+	status->noise = -rxd->noise_floor;
+
+	if (rxd->rate & 0x80) {
+		status->flag |= RX_FLAG_HT;
+		status->rate_idx = rxd->rate & 0x7f;
+	} else {
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(mwl8k_rates); i++) {
+			if (mwl8k_rates[i].hw_value == rxd->rate) {
+				status->rate_idx = i;
+				break;
+			}
+		}
+	}
+
+	status->band = IEEE80211_BAND_2GHZ;
+	status->freq = ieee80211_channel_to_frequency(rxd->channel);
+
+	return le16_to_cpu(rxd->pkt_len);
+}
+
+static struct rxd_ops rxd_8366_ops = {
+	.rxd_size	= sizeof(struct mwl8k_rxd_8366),
+	.rxd_init	= mwl8k_rxd_8366_init,
+	.rxd_refill	= mwl8k_rxd_8366_refill,
+	.rxd_process	= mwl8k_rxd_8366_process,
+};
+
+/*
+ * Packet reception for 88w8687.
  */
 struct mwl8k_rxd_8687 {
 	__le16 pkt_len;
@@ -3225,6 +3307,14 @@ static void mwl8k_finalize_join_worker(struct work_struct *work)
 	priv->beacon_skb = NULL;
 }
 
+static struct mwl8k_device_info di_8366 = {
+	.part_name	= "88w8366",
+	.helper_image	= "mwl8k/helper_8366.fw",
+	.fw_image	= "mwl8k/fmimage_8366.fw",
+	.rxd_ops	= &rxd_8366_ops,
+	.modes		= 0,
+};
+
 static struct mwl8k_device_info di_8687 = {
 	.part_name	= "88w8687",
 	.helper_image	= "mwl8k/helper_8687.fw",
@@ -3241,6 +3331,9 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
 		PCI_VDEVICE(MARVELL, 0x2a30),
 		.driver_data = (unsigned long)&di_8687,
 	}, {
+		PCI_VDEVICE(MARVELL, 0x2a40),
+		.driver_data = (unsigned long)&di_8366,
+	}, {
 	},
 };
 MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table);
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 19/28] mwl8k: allow for different receive descriptor formats
From: Lennert Buytenhek @ 2009-10-22 18:20 UTC (permalink / raw)
  To: linux-wireless

As the receive descriptor format is determined by the firmware running
on the hardware and not by the hardware itself, and as these
descriptor formats vary a bit between different firmware releases,
abstract out the receive descriptor init/refill/process methods, and
allow choosing between different formats at run time depending on the
chip and firmware we're running on.

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 96faec6..9c10c88 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -79,10 +79,18 @@
 #define MWL8K_RX_QUEUES		1
 #define MWL8K_TX_QUEUES		4
 
+struct rxd_ops {
+	int rxd_size;
+	void (*rxd_init)(void *rxd, dma_addr_t next_dma_addr);
+	void (*rxd_refill)(void *rxd, dma_addr_t addr, int len);
+	int (*rxd_process)(void *rxd, struct ieee80211_rx_status *status);
+};
+
 struct mwl8k_device_info {
 	char *part_name;
 	char *helper_image;
 	char *fw_image;
+	struct rxd_ops *rxd_ops;
 };
 
 struct mwl8k_rx_queue {
@@ -94,7 +102,7 @@ struct mwl8k_rx_queue {
 	/* refill descs here */
 	int tail;
 
-	struct mwl8k_rx_desc *rxd;
+	void *rxd;
 	dma_addr_t rxd_dma;
 	struct {
 		struct sk_buff *skb;
@@ -133,6 +141,7 @@ struct mwl8k_priv {
 
 	struct mwl8k_device_info *device_info;
 	bool ap_fw;
+	struct rxd_ops *rxd_ops;
 
 	/* firmware files and meta data */
 	struct mwl8k_firmware fw;
@@ -743,9 +752,7 @@ static inline void mwl8k_add_dma_header(struct sk_buff *skb)
 /*
  * Packet reception.
  */
-#define MWL8K_RX_CTRL_OWNED_BY_HOST	0x02
-
-struct mwl8k_rx_desc {
+struct mwl8k_rxd_8687 {
 	__le16 pkt_len;
 	__u8 link_quality;
 	__u8 noise_level;
@@ -762,16 +769,79 @@ struct mwl8k_rx_desc {
 	__u8 pad2[2];
 } __attribute__((packed));
 
+#define MWL8K_8687_RATE_INFO_SHORTPRE		0x8000
+#define MWL8K_8687_RATE_INFO_ANTSELECT(x)	(((x) >> 11) & 0x3)
+#define MWL8K_8687_RATE_INFO_RATEID(x)		(((x) >> 3) & 0x3f)
+#define MWL8K_8687_RATE_INFO_40MHZ		0x0004
+#define MWL8K_8687_RATE_INFO_SHORTGI		0x0002
+#define MWL8K_8687_RATE_INFO_MCS_FORMAT		0x0001
+
+#define MWL8K_8687_RX_CTRL_OWNED_BY_HOST	0x02
+
+static void mwl8k_rxd_8687_init(void *_rxd, dma_addr_t next_dma_addr)
+{
+	struct mwl8k_rxd_8687 *rxd = _rxd;
+
+	rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr);
+	rxd->rx_ctrl = MWL8K_8687_RX_CTRL_OWNED_BY_HOST;
+}
+
+static void mwl8k_rxd_8687_refill(void *_rxd, dma_addr_t addr, int len)
+{
+	struct mwl8k_rxd_8687 *rxd = _rxd;
+
+	rxd->pkt_len = cpu_to_le16(len);
+	rxd->pkt_phys_addr = cpu_to_le32(addr);
+	wmb();
+	rxd->rx_ctrl = 0;
+}
+
+static int
+mwl8k_rxd_8687_process(void *_rxd, struct ieee80211_rx_status *status)
+{
+	struct mwl8k_rxd_8687 *rxd = _rxd;
+	u16 rate_info;
+
+	if (!(rxd->rx_ctrl & MWL8K_8687_RX_CTRL_OWNED_BY_HOST))
+		return -1;
+	rmb();
+
+	rate_info = le16_to_cpu(rxd->rate_info);
+
+	memset(status, 0, sizeof(*status));
+
+	status->signal = -rxd->rssi;
+	status->noise = -rxd->noise_level;
+	status->qual = rxd->link_quality;
+	status->antenna = MWL8K_8687_RATE_INFO_ANTSELECT(rate_info);
+	status->rate_idx = MWL8K_8687_RATE_INFO_RATEID(rate_info);
+
+	if (rate_info & MWL8K_8687_RATE_INFO_SHORTPRE)
+		status->flag |= RX_FLAG_SHORTPRE;
+	if (rate_info & MWL8K_8687_RATE_INFO_40MHZ)
+		status->flag |= RX_FLAG_40MHZ;
+	if (rate_info & MWL8K_8687_RATE_INFO_SHORTGI)
+		status->flag |= RX_FLAG_SHORT_GI;
+	if (rate_info & MWL8K_8687_RATE_INFO_MCS_FORMAT)
+		status->flag |= RX_FLAG_HT;
+
+	status->band = IEEE80211_BAND_2GHZ;
+	status->freq = ieee80211_channel_to_frequency(rxd->channel);
+
+	return le16_to_cpu(rxd->pkt_len);
+}
+
+static struct rxd_ops rxd_8687_ops = {
+	.rxd_size	= sizeof(struct mwl8k_rxd_8687),
+	.rxd_init	= mwl8k_rxd_8687_init,
+	.rxd_refill	= mwl8k_rxd_8687_refill,
+	.rxd_process	= mwl8k_rxd_8687_process,
+};
+
+
 #define MWL8K_RX_DESCS		256
 #define MWL8K_RX_MAXSZ		3800
 
-#define RATE_INFO_SHORTPRE		0x8000
-#define RATE_INFO_ANTSELECT(x)		(((x) >> 11) & 0x3)
-#define RATE_INFO_RATEID(x)		(((x) >> 3) & 0x3f)
-#define RATE_INFO_40MHZ			0x0004
-#define RATE_INFO_SHORTGI		0x0002
-#define RATE_INFO_MCS_FORMAT		0x0001
-
 static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index)
 {
 	struct mwl8k_priv *priv = hw->priv;
@@ -783,7 +853,7 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index)
 	rxq->head = 0;
 	rxq->tail = 0;
 
-	size = MWL8K_RX_DESCS * sizeof(struct mwl8k_rx_desc);
+	size = MWL8K_RX_DESCS * priv->rxd_ops->rxd_size;
 
 	rxq->rxd = pci_alloc_consistent(priv->pdev, size, &rxq->rxd_dma);
 	if (rxq->rxd == NULL) {
@@ -803,15 +873,20 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index)
 	memset(rxq->buf, 0, MWL8K_RX_DESCS * sizeof(*rxq->buf));
 
 	for (i = 0; i < MWL8K_RX_DESCS; i++) {
-		struct mwl8k_rx_desc *rx_desc;
+		int desc_size;
+		void *rxd;
 		int nexti;
+		dma_addr_t next_dma_addr;
+
+		desc_size = priv->rxd_ops->rxd_size;
+		rxd = rxq->rxd + (i * priv->rxd_ops->rxd_size);
 
-		rx_desc = rxq->rxd + i;
-		nexti = (i + 1) % MWL8K_RX_DESCS;
+		nexti = i + 1;
+		if (nexti == MWL8K_RX_DESCS)
+			nexti = 0;
+		next_dma_addr = rxq->rxd_dma + (nexti * desc_size);
 
-		rx_desc->next_rxd_phys_addr =
-			cpu_to_le32(rxq->rxd_dma + nexti * sizeof(*rx_desc));
-		rx_desc->rx_ctrl = MWL8K_RX_CTRL_OWNED_BY_HOST;
+		priv->rxd_ops->rxd_init(rxd, next_dma_addr);
 	}
 
 	return 0;
@@ -828,25 +903,24 @@ static int rxq_refill(struct ieee80211_hw *hw, int index, int limit)
 		struct sk_buff *skb;
 		dma_addr_t addr;
 		int rx;
+		void *rxd;
 
 		skb = dev_alloc_skb(MWL8K_RX_MAXSZ);
 		if (skb == NULL)
 			break;
 
-		rxq->rxd_count++;
-
-		rx = rxq->tail;
-		rxq->tail = (rx + 1) % MWL8K_RX_DESCS;
-
 		addr = pci_map_single(priv->pdev, skb->data,
 				      MWL8K_RX_MAXSZ, DMA_FROM_DEVICE);
 
-		rxq->rxd[rx].pkt_len = cpu_to_le16(MWL8K_RX_MAXSZ);
-		rxq->rxd[rx].pkt_phys_addr = cpu_to_le32(addr);
+		rxq->rxd_count++;
+		rx = rxq->tail++;
+		if (rxq->tail == MWL8K_RX_DESCS)
+			rxq->tail = 0;
 		rxq->buf[rx].skb = skb;
 		pci_unmap_addr_set(&rxq->buf[rx], dma, addr);
-		wmb();
-		rxq->rxd[rx].rx_ctrl = 0;
+
+		rxd = rxq->rxd + (rx * priv->rxd_ops->rxd_size);
+		priv->rxd_ops->rxd_refill(rxd, addr, MWL8K_RX_MAXSZ);
 
 		refilled++;
 	}
@@ -877,7 +951,7 @@ static void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index)
 	rxq->buf = NULL;
 
 	pci_free_consistent(priv->pdev,
-			    MWL8K_RX_DESCS * sizeof(struct mwl8k_rx_desc),
+			    MWL8K_RX_DESCS * priv->rxd_ops->rxd_size,
 			    rxq->rxd, rxq->rxd_dma);
 	rxq->rxd = NULL;
 }
@@ -921,20 +995,21 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
 
 	processed = 0;
 	while (rxq->rxd_count && limit--) {
-		struct mwl8k_rx_desc *rx_desc;
 		struct sk_buff *skb;
+		void *rxd;
+		int pkt_len;
 		struct ieee80211_rx_status status;
-		struct ieee80211_hdr *wh;
-		u16 rate_info;
-
-		rx_desc = rxq->rxd + rxq->head;
-		if (!(rx_desc->rx_ctrl & MWL8K_RX_CTRL_OWNED_BY_HOST))
-			break;
-		rmb();
 
 		skb = rxq->buf[rxq->head].skb;
 		if (skb == NULL)
 			break;
+
+		rxd = rxq->rxd + (rxq->head * priv->rxd_ops->rxd_size);
+
+		pkt_len = priv->rxd_ops->rxd_process(rxd, &status);
+		if (pkt_len < 0)
+			break;
+
 		rxq->buf[rxq->head].skb = NULL;
 
 		pci_unmap_single(priv->pdev,
@@ -942,42 +1017,23 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
 				 MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE);
 		pci_unmap_addr_set(&rxq->buf[rxq->head], dma, 0);
 
-		rxq->head = (rxq->head + 1) % MWL8K_RX_DESCS;
+		rxq->head++;
+		if (rxq->head == MWL8K_RX_DESCS)
+			rxq->head = 0;
+
 		rxq->rxd_count--;
 
-		skb_put(skb, le16_to_cpu(rx_desc->pkt_len));
+		skb_put(skb, pkt_len);
 		mwl8k_remove_dma_header(skb);
 
-		wh = (struct ieee80211_hdr *)skb->data;
-
 		/*
 		 * Check for a pending join operation.  Save a
 		 * copy of the beacon and schedule a tasklet to
 		 * send a FINALIZE_JOIN command to the firmware.
 		 */
-		if (mwl8k_capture_bssid(priv, wh))
+		if (mwl8k_capture_bssid(priv, (void *)skb->data))
 			mwl8k_save_beacon(hw, skb);
 
-		rate_info = le16_to_cpu(rx_desc->rate_info);
-
-		memset(&status, 0, sizeof(status));
-		status.mactime = 0;
-		status.signal = -rx_desc->rssi;
-		status.noise = -rx_desc->noise_level;
-		status.qual = rx_desc->link_quality;
-		status.antenna = RATE_INFO_ANTSELECT(rate_info);
-		status.rate_idx = RATE_INFO_RATEID(rate_info);
-		status.flag = 0;
-		if (rate_info & RATE_INFO_SHORTPRE)
-			status.flag |= RX_FLAG_SHORTPRE;
-		if (rate_info & RATE_INFO_40MHZ)
-			status.flag |= RX_FLAG_40MHZ;
-		if (rate_info & RATE_INFO_SHORTGI)
-			status.flag |= RX_FLAG_SHORT_GI;
-		if (rate_info & RATE_INFO_MCS_FORMAT)
-			status.flag |= RX_FLAG_HT;
-		status.band = IEEE80211_BAND_2GHZ;
-		status.freq = ieee80211_channel_to_frequency(rx_desc->channel);
 		memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
 		ieee80211_rx_irqsafe(hw, skb);
 
@@ -2958,6 +3014,7 @@ static struct mwl8k_device_info di_8687 = {
 	.part_name	= "88w8687",
 	.helper_image	= "mwl8k/helper_8687.fw",
 	.fw_image	= "mwl8k/fmimage_8687.fw",
+	.rxd_ops	= &rxd_8687_ops,
 };
 
 static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
@@ -3013,6 +3070,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 	priv->hw = hw;
 	priv->pdev = pdev;
 	priv->device_info = (void *)id->driver_data;
+	priv->rxd_ops = priv->device_info->rxd_ops;
 	priv->sniffer_enabled = false;
 	priv->wmm_enabled = false;
 	priv->pending_tx_pkts = 0;
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 01/28] mwl8k: fix GET_STAT firmware command packet layout
From: Lennert Buytenhek @ 2009-10-22 18:19 UTC (permalink / raw)
  To: linux-wireless

The GET_STAT command doesn't have an 'action' field like other
commands do, so remove it.

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 746532e..3249998 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -1590,7 +1590,6 @@ __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw,
  */
 struct mwl8k_cmd_802_11_get_stat {
 	struct mwl8k_cmd_pkt header;
-	__le16 action;
 	__le32 stats[64];
 } __attribute__((packed));
 
@@ -1611,7 +1610,6 @@ static int mwl8k_cmd_802_11_get_stat(struct ieee80211_hw *hw,
 
 	cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_STAT);
 	cmd->header.length = cpu_to_le16(sizeof(*cmd));
-	cmd->action = cpu_to_le16(MWL8K_CMD_GET);
 
 	rc = mwl8k_post_cmd(hw, &cmd->header);
 	if (!rc) {
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 10/28] mwl8k: clarify WME transmit queue 0/1 swizzling
From: Lennert Buytenhek @ 2009-10-22 18:20 UTC (permalink / raw)
  To: linux-wireless

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 08ae219..8931be9 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -83,12 +83,6 @@ MODULE_DEVICE_TABLE(pci, mwl8k_table);
 				 MWL8K_A2H_INT_RX_READY | \
 				 MWL8K_A2H_INT_TX_DONE)
 
-/* WME stream classes */
-#define WME_AC_BE	0		/* best effort */
-#define WME_AC_BK	1		/* background */
-#define WME_AC_VI	2		/* video */
-#define WME_AC_VO	3		/* voice */
-
 #define MWL8K_RX_QUEUES		1
 #define MWL8K_TX_QUEUES		4
 
@@ -967,24 +961,10 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
  * Packet transmission.
  */
 
-/* Transmit queue assignment.  */
-enum {
-	MWL8K_WME_AC_BK	= 0,		/* background access */
-	MWL8K_WME_AC_BE	= 1,		/* best effort access */
-	MWL8K_WME_AC_VI	= 2,		/* video access */
-	MWL8K_WME_AC_VO	= 3,		/* voice access */
-};
-
 /* Transmit packet ACK policy */
 #define MWL8K_TXD_ACK_POLICY_NORMAL		0
 #define MWL8K_TXD_ACK_POLICY_BLOCKACK		3
 
-#define GET_TXQ(_ac) (\
-		((_ac) == WME_AC_VO) ? MWL8K_WME_AC_VO : \
-		((_ac) == WME_AC_VI) ? MWL8K_WME_AC_VI : \
-		((_ac) == WME_AC_BK) ? MWL8K_WME_AC_BK : \
-		MWL8K_WME_AC_BE)
-
 #define MWL8K_TXD_STATUS_OK			0x00000001
 #define MWL8K_TXD_STATUS_OK_RETRY		0x00000002
 #define MWL8K_TXD_STATUS_OK_MORE_RETRY		0x00000004
@@ -2068,6 +2048,12 @@ mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum,
 	if (cmd == NULL)
 		return -ENOMEM;
 
+	/*
+	 * Queues 0 (BE) and 1 (BK) are swapped in hardware for
+	 * this call.
+	 */
+	qnum ^= !(qnum >> 1);
+
 	cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_EDCA_PARAMS);
 	cmd->header.length = cpu_to_le16(sizeof(*cmd));
 	cmd->action = cpu_to_le16(MWL8K_SET_EDCA_ALL);
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 05/28] mwl8k: use the mac80211-provided workqueue instead of creating our own
From: Lennert Buytenhek @ 2009-10-22 18:19 UTC (permalink / raw)
  To: linux-wireless

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 0b4fa14..77985e9 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -195,9 +195,6 @@ struct mwl8k_priv {
 
 	/* Tasklet to reclaim TX descriptors and buffers after tx */
 	struct tasklet_struct tx_reclaim_task;
-
-	/* Work thread to serialize configuration requests */
-	struct workqueue_struct *config_wq;
 };
 
 /* Per interface specific private data */
@@ -881,9 +878,11 @@ mwl8k_capture_bssid(struct mwl8k_priv *priv, struct ieee80211_hdr *wh)
 		!compare_ether_addr(wh->addr3, priv->capture_bssid);
 }
 
-static inline void mwl8k_save_beacon(struct mwl8k_priv *priv,
-							struct sk_buff *skb)
+static inline void mwl8k_save_beacon(struct ieee80211_hw *hw,
+				     struct sk_buff *skb)
 {
+	struct mwl8k_priv *priv = hw->priv;
+
 	priv->capture_beacon = false;
 	memset(priv->capture_bssid, 0, ETH_ALEN);
 
@@ -894,8 +893,7 @@ static inline void mwl8k_save_beacon(struct mwl8k_priv *priv,
 	 */
 	priv->beacon_skb = skb_copy(skb, GFP_ATOMIC);
 	if (priv->beacon_skb != NULL)
-		queue_work(priv->config_wq,
-				&priv->finalize_join_worker);
+		ieee80211_queue_work(hw, &priv->finalize_join_worker);
 }
 
 static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
@@ -940,7 +938,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
 		 * send a FINALIZE_JOIN command to the firmware.
 		 */
 		if (mwl8k_capture_bssid(priv, wh))
-			mwl8k_save_beacon(priv, skb);
+			mwl8k_save_beacon(hw, skb);
 
 		memset(&status, 0, sizeof(status));
 		status.mactime = 0;
@@ -2504,9 +2502,6 @@ static void mwl8k_stop(struct ieee80211_hw *hw)
 	/* Stop tx reclaim tasklet */
 	tasklet_disable(&priv->tx_reclaim_task);
 
-	/* Stop config thread */
-	flush_workqueue(priv->config_wq);
-
 	/* Return all skbs to mac80211 */
 	for (i = 0; i < MWL8K_TX_QUEUES; i++)
 		mwl8k_txq_reclaim(hw, i, 1);
@@ -2920,11 +2915,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 			mwl8k_tx_reclaim_handler, (unsigned long)hw);
 	tasklet_disable(&priv->tx_reclaim_task);
 
-	/* Config workthread */
-	priv->config_wq = create_singlethread_workqueue("mwl8k_config");
-	if (priv->config_wq == NULL)
-		goto err_iounmap;
-
 	/* Power management cookie */
 	priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma);
 	if (priv->cookie == NULL)
@@ -3047,9 +3037,6 @@ err_iounmap:
 	if (priv->regs != NULL)
 		pci_iounmap(pdev, priv->regs);
 
-	if (priv->config_wq != NULL)
-		destroy_workqueue(priv->config_wq);
-
 	pci_set_drvdata(pdev, NULL);
 	ieee80211_free_hw(hw);
 
@@ -3082,9 +3069,6 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev)
 	/* Remove tx reclaim tasklet */
 	tasklet_kill(&priv->tx_reclaim_task);
 
-	/* Stop config thread */
-	destroy_workqueue(priv->config_wq);
-
 	/* Stop hardware */
 	mwl8k_hw_reset(priv);
 
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 08/28] mwl8k: clear hardware MAC address if no STA interface configured
From: Lennert Buytenhek @ 2009-10-22 18:20 UTC (permalink / raw)
  To: linux-wireless

If there is no STA interface configured, clear the hardware MAC
address to prevent ACKing frames sent to our MAC address.

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 53447f6..fcf7139 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -280,6 +280,7 @@ static const struct ieee80211_rate mwl8k_rates[] = {
 #define MWL8K_CMD_MIMO_CONFIG		0x0125
 #define MWL8K_CMD_USE_FIXED_RATE	0x0126
 #define MWL8K_CMD_ENABLE_SNIFFER	0x0150
+#define MWL8K_CMD_SET_MAC_ADDR		0x0202
 #define MWL8K_CMD_SET_RATEADAPT_MODE	0x0203
 #define MWL8K_CMD_UPDATE_STADB		0x1123
 
@@ -309,6 +310,7 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize)
 		MWL8K_CMDNAME(MIMO_CONFIG);
 		MWL8K_CMDNAME(USE_FIXED_RATE);
 		MWL8K_CMDNAME(ENABLE_SNIFFER);
+		MWL8K_CMDNAME(SET_MAC_ADDR);
 		MWL8K_CMDNAME(SET_RATEADAPT_MODE);
 		MWL8K_CMDNAME(UPDATE_STADB);
 	default:
@@ -1903,6 +1905,34 @@ static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable)
 }
 
 /*
+ * CMD_SET_MAC_ADDR.
+ */
+struct mwl8k_cmd_set_mac_addr {
+	struct mwl8k_cmd_pkt header;
+	__u8 mac_addr[ETH_ALEN];
+} __attribute__((packed));
+
+static int mwl8k_set_mac_addr(struct ieee80211_hw *hw, u8 *mac)
+{
+	struct mwl8k_cmd_set_mac_addr *cmd;
+	int rc;
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (cmd == NULL)
+		return -ENOMEM;
+
+	cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR);
+	cmd->header.length = cpu_to_le16(sizeof(*cmd));
+	memcpy(cmd->mac_addr, mac, ETH_ALEN);
+
+	rc = mwl8k_post_cmd(hw, &cmd->header);
+	kfree(cmd);
+
+	return rc;
+}
+
+
+/*
  * CMD_SET_RATEADAPT_MODE.
  */
 struct mwl8k_cmd_set_rate_adapt_mode {
@@ -2527,7 +2557,8 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
 	mwl8k_vif = MWL8K_VIF(conf->vif);
 	memset(mwl8k_vif, 0, sizeof(*mwl8k_vif));
 
-	/* Save the mac address */
+	/* Set and save the mac address */
+	mwl8k_set_mac_addr(hw, conf->mac_addr);
 	memcpy(mwl8k_vif->mac_addr, conf->mac_addr, ETH_ALEN);
 
 	/* Back pointer to parent config block */
@@ -2555,6 +2586,8 @@ static void mwl8k_remove_interface(struct ieee80211_hw *hw,
 	if (priv->vif == NULL)
 		return;
 
+	mwl8k_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00");
+
 	priv->vif = NULL;
 }
 
@@ -3025,6 +3058,14 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 		goto err_stop_firmware;
 	}
 
+	/* Clear MAC address */
+	rc = mwl8k_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00");
+	if (rc) {
+		printk(KERN_ERR "%s: Cannot clear MAC address\n",
+		       wiphy_name(hw->wiphy));
+		goto err_stop_firmware;
+	}
+
 	/* 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 04/28] mwl8k: fix multicast address filter programming
From: Lennert Buytenhek @ 2009-10-22 18:19 UTC (permalink / raw)
  To: linux-wireless

mwl8k's ->prepare_multicast() currently just enables reception of
all multicast packets, which is somewhat ineffective.

Fix this by either disabling all multicast RX, enabling multicast
RX according to the multicast address filter table, or enabling all
multicast RX, depending on whether ->prepare_multicast() was given
any multicast addresses and whether the hardware multicast address
filter table is large enough to fit all requested addresses.

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index ba7b8ef..0b4fa14 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -1539,7 +1539,10 @@ struct mwl8k_cmd_mac_multicast_adr {
 	__u8 addr[0][ETH_ALEN];
 };
 
-#define MWL8K_ENABLE_RX_MULTICAST 0x000F
+#define MWL8K_ENABLE_RX_DIRECTED	0x0001
+#define MWL8K_ENABLE_RX_MULTICAST	0x0002
+#define MWL8K_ENABLE_RX_ALL_MULTICAST	0x0004
+#define MWL8K_ENABLE_RX_BROADCAST	0x0008
 
 static struct mwl8k_cmd_pkt *
 __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw,
@@ -1547,11 +1550,14 @@ __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw,
 {
 	struct mwl8k_priv *priv = hw->priv;
 	struct mwl8k_cmd_mac_multicast_adr *cmd;
+	int allmulti;
 	int size;
-	int i;
 
-	if (mc_count > priv->num_mcaddrs)
-		mc_count = priv->num_mcaddrs;
+	allmulti = 0;
+	if (mc_count > priv->num_mcaddrs) {
+		allmulti = 1;
+		mc_count = 0;
+	}
 
 	size = sizeof(*cmd) + mc_count * ETH_ALEN;
 
@@ -1561,16 +1567,24 @@ __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw,
 
 	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);
-
-	for (i = 0; i < mc_count && mclist; i++) {
-		if (mclist->da_addrlen != ETH_ALEN) {
-			kfree(cmd);
-			return NULL;
+	cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_DIRECTED |
+				  MWL8K_ENABLE_RX_BROADCAST);
+
+	if (allmulti) {
+		cmd->action |= cpu_to_le16(MWL8K_ENABLE_RX_ALL_MULTICAST);
+	} else if (mc_count) {
+		int i;
+
+		cmd->action |= cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST);
+		cmd->numaddr = cpu_to_le16(mc_count);
+		for (i = 0; i < mc_count && mclist; i++) {
+			if (mclist->da_addrlen != ETH_ALEN) {
+				kfree(cmd);
+				return NULL;
+			}
+			memcpy(cmd->addr[i], mclist->da_addr, ETH_ALEN);
+			mclist = mclist->next;
 		}
-		memcpy(cmd->addr[i], mclist->da_addr, ETH_ALEN);
-		mclist = mclist->next;
 	}
 
 	return &cmd->header;
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 02/28] mwl8k: coding style cleanups
From: Lennert Buytenhek @ 2009-10-22 18:19 UTC (permalink / raw)
  To: linux-wireless

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 3249998..252ef9c 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -27,11 +27,6 @@
 #define MWL8K_NAME	KBUILD_MODNAME
 #define MWL8K_VERSION	"0.10"
 
-MODULE_DESCRIPTION(MWL8K_DESC);
-MODULE_VERSION(MWL8K_VERSION);
-MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com>");
-MODULE_LICENSE("GPL");
-
 static DEFINE_PCI_DEVICE_TABLE(mwl8k_table) = {
 	{ PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = 8687, },
 	{ PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = 8687, },
@@ -138,7 +133,6 @@ struct mwl8k_priv {
 	struct ieee80211_hw *hw;
 
 	struct pci_dev *pdev;
-	u8 name[16];
 
 	/* firmware files and meta data */
 	struct mwl8k_firmware fw;
@@ -353,14 +347,14 @@ static void mwl8k_release_firmware(struct mwl8k_priv *priv)
 
 /* Request fw image */
 static int mwl8k_request_fw(struct mwl8k_priv *priv,
-				const char *fname, struct firmware **fw)
+			    const char *fname, struct firmware **fw)
 {
 	/* release current image */
 	if (*fw != NULL)
 		mwl8k_release_fw(fw);
 
 	return request_firmware((const struct firmware **)fw,
-						fname, &priv->pdev->dev);
+				fname, &priv->pdev->dev);
 }
 
 static int mwl8k_request_firmware(struct mwl8k_priv *priv, u32 part_num)
@@ -375,9 +369,8 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv, u32 part_num)
 
 	rc = mwl8k_request_fw(priv, filename, &priv->fw.helper);
 	if (rc) {
-		printk(KERN_ERR
-			"%s Error requesting helper firmware file %s\n",
-			pci_name(priv->pdev), filename);
+		printk(KERN_ERR "%s: Error requesting helper firmware "
+		       "file %s\n", pci_name(priv->pdev), filename);
 		return rc;
 	}
 
@@ -386,8 +379,8 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv, u32 part_num)
 
 	rc = mwl8k_request_fw(priv, filename, &priv->fw.ucode);
 	if (rc) {
-		printk(KERN_ERR "%s Error requesting firmware file %s\n",
-					pci_name(priv->pdev), filename);
+		printk(KERN_ERR "%s: Error requesting firmware file %s\n",
+		       pci_name(priv->pdev), filename);
 		mwl8k_release_fw(&priv->fw.helper);
 		return rc;
 	}
@@ -542,32 +535,38 @@ static int mwl8k_feed_fw_image(struct mwl8k_priv *priv,
 	return rc;
 }
 
-static int mwl8k_load_firmware(struct mwl8k_priv *priv)
+static int mwl8k_load_firmware(struct ieee80211_hw *hw)
 {
-	int loops, rc;
+	struct mwl8k_priv *priv = hw->priv;
+	struct firmware *fw = priv->fw.ucode;
+	int rc;
+	int loops;
+
+	if (!memcmp(fw->data, "\x01\x00\x00\x00", 4)) {
+		struct firmware *helper = priv->fw.helper;
 
-	const u8 *ucode = priv->fw.ucode->data;
-	size_t ucode_len = priv->fw.ucode->size;
-	const u8 *helper = priv->fw.helper->data;
-	size_t helper_len = priv->fw.helper->size;
+		if (helper == NULL) {
+			printk(KERN_ERR "%s: helper image needed but none "
+			       "given\n", pci_name(priv->pdev));
+			return -EINVAL;
+		}
 
-	if (!memcmp(ucode, "\x01\x00\x00\x00", 4)) {
-		rc = mwl8k_load_fw_image(priv, helper, helper_len);
+		rc = mwl8k_load_fw_image(priv, helper->data, helper->size);
 		if (rc) {
 			printk(KERN_ERR "%s: unable to load firmware "
-				"helper image\n", pci_name(priv->pdev));
+			       "helper image\n", pci_name(priv->pdev));
 			return rc;
 		}
 		msleep(1);
 
-		rc = mwl8k_feed_fw_image(priv, ucode, ucode_len);
+		rc = mwl8k_feed_fw_image(priv, fw->data, fw->size);
 	} else {
-		rc = mwl8k_load_fw_image(priv, ucode, ucode_len);
+		rc = mwl8k_load_fw_image(priv, fw->data, fw->size);
 	}
 
 	if (rc) {
-		printk(KERN_ERR "%s: unable to load firmware data\n",
-			pci_name(priv->pdev));
+		printk(KERN_ERR "%s: unable to load firmware image\n",
+		       pci_name(priv->pdev));
 		return rc;
 	}
 
@@ -772,7 +771,7 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index)
 		pci_alloc_consistent(priv->pdev, size, &rxq->rx_desc_dma);
 	if (rxq->rx_desc_area == NULL) {
 		printk(KERN_ERR "%s: failed to alloc RX descriptors\n",
-		       priv->name);
+		       wiphy_name(hw->wiphy));
 		return -ENOMEM;
 	}
 	memset(rxq->rx_desc_area, 0, size);
@@ -781,7 +780,7 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index)
 				sizeof(*rxq->rx_skb), GFP_KERNEL);
 	if (rxq->rx_skb == NULL) {
 		printk(KERN_ERR "%s: failed to alloc RX skbuff list\n",
-			priv->name);
+		       wiphy_name(hw->wiphy));
 		pci_free_consistent(priv->pdev, size,
 				    rxq->rx_desc_area, rxq->rx_desc_dma);
 		return -ENOMEM;
@@ -934,9 +933,9 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
 		wh = (struct ieee80211_hdr *)skb->data;
 
 		/*
-		 * Check for pending join operation. save a copy of
-		 * the beacon and schedule a tasklet to send finalize
-		 * join command to the firmware.
+		 * Check for a pending join operation.  Save a
+		 * copy of the beacon and schedule a tasklet to
+		 * send a FINALIZE_JOIN command to the firmware.
 		 */
 		if (mwl8k_capture_bssid(priv, wh))
 			mwl8k_save_beacon(priv, skb);
@@ -1024,7 +1023,7 @@ static int mwl8k_txq_init(struct ieee80211_hw *hw, int index)
 		pci_alloc_consistent(priv->pdev, size, &txq->tx_desc_dma);
 	if (txq->tx_desc_area == NULL) {
 		printk(KERN_ERR "%s: failed to alloc TX descriptors\n",
-		       priv->name);
+		       wiphy_name(hw->wiphy));
 		return -ENOMEM;
 	}
 	memset(txq->tx_desc_area, 0, size);
@@ -1033,7 +1032,7 @@ static int mwl8k_txq_init(struct ieee80211_hw *hw, int index)
 								GFP_KERNEL);
 	if (txq->tx_skb == NULL) {
 		printk(KERN_ERR "%s: failed to alloc TX skbuff list\n",
-		       priv->name);
+		       wiphy_name(hw->wiphy));
 		pci_free_consistent(priv->pdev, size,
 				    txq->tx_desc_area, txq->tx_desc_dma);
 		return -ENOMEM;
@@ -1154,8 +1153,8 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
 
 		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",
+			printk(KERN_ERR "TXQ:%u L:%u H:%u T:%u FW:%u "
+			       "DRV:%u U:%u\n",
 					index,
 					txinfo[index].len,
 					txinfo[index].head,
@@ -1317,7 +1316,7 @@ 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);
+		       "dropping TX frame.\n", wiphy_name(hw->wiphy));
 		dev_kfree_skb(skb);
 		return NETDEV_TX_OK;
 	}
@@ -1431,7 +1430,7 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
 	unsigned long timeout = 0;
 	u8 buf[32];
 
-	cmd->result = 0xFFFF;
+	cmd->result = 0xffff;
 	dma_size = le16_to_cpu(cmd->length);
 	dma_addr = pci_map_single(priv->pdev, cmd, dma_size,
 				  PCI_DMA_BIDIRECTIONAL);
@@ -1464,7 +1463,7 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
 
 	if (!timeout) {
 		printk(KERN_ERR "%s: Command %s timeout after %u ms\n",
-		       priv->name,
+		       wiphy_name(hw->wiphy),
 		       mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
 		       MWL8K_CMD_TIMEOUT_MS);
 		rc = -ETIMEDOUT;
@@ -1472,7 +1471,7 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
 		rc = cmd->result ? -EINVAL : 0;
 		if (rc)
 			printk(KERN_ERR "%s: Command %s error 0x%x\n",
-			       priv->name,
+			       wiphy_name(hw->wiphy),
 			       mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
 			       le16_to_cpu(cmd->result));
 	}
@@ -2091,8 +2090,8 @@ static int mwl8k_finalize_join(struct ieee80211_hw *hw, void *frame,
 	/* XXX TBD Might just have to abort and return an error */
 	if (payload_len > MWL8K_FJ_BEACON_MAXLEN)
 		printk(KERN_ERR "%s(): WARNING: Incomplete beacon "
-			"sent to firmware. Sz=%u MAX=%u\n", __func__,
-			payload_len, MWL8K_FJ_BEACON_MAXLEN);
+		       "sent to firmware. Sz=%u MAX=%u\n", __func__,
+		       payload_len, MWL8K_FJ_BEACON_MAXLEN);
 
 	if (payload_len > MWL8K_FJ_BEACON_MAXLEN)
 		payload_len = MWL8K_FJ_BEACON_MAXLEN;
@@ -2339,9 +2338,10 @@ static int mwl8k_cmd_use_fixed_rate(struct ieee80211_hw *hw,
 	cmd->rate_type = cpu_to_le32(rate_type);
 
 	if (rate_table != NULL) {
-		/* Copy over each field manually so
-		* that bitflipping can be done
-		*/
+		/*
+		 * Copy over each field manually so that endian
+		 * conversion can be done.
+		 */
 		cmd->rate_table.allow_rate_drop =
 				cpu_to_le32(rate_table->allow_rate_drop);
 		cmd->rate_table.num_rates =
@@ -2416,7 +2416,7 @@ static int mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 
 	if (priv->current_channel == NULL) {
 		printk(KERN_DEBUG "%s: dropped TX frame since radio "
-		       "disabled\n", priv->name);
+		       "disabled\n", wiphy_name(hw->wiphy));
 		dev_kfree_skb(skb);
 		return NETDEV_TX_OK;
 	}
@@ -2435,7 +2435,7 @@ static int mwl8k_start(struct ieee80211_hw *hw)
 			 IRQF_SHARED, MWL8K_NAME, hw);
 	if (rc) {
 		printk(KERN_ERR "%s: failed to register IRQ handler\n",
-		       priv->name);
+		       wiphy_name(hw->wiphy));
 		return -EIO;
 	}
 
@@ -2862,14 +2862,14 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 	priv->pdev = pdev;
 	priv->wmm_enabled = false;
 	priv->pending_tx_pkts = 0;
-	strncpy(priv->name, MWL8K_NAME, sizeof(priv->name));
 
 	SET_IEEE80211_DEV(hw, &pdev->dev);
 	pci_set_drvdata(pdev, hw);
 
 	priv->regs = pci_iomap(pdev, 1, 0x10000);
 	if (priv->regs == NULL) {
-		printk(KERN_ERR "%s: Cannot map device memory\n", priv->name);
+		printk(KERN_ERR "%s: Cannot map device memory\n",
+		       wiphy_name(hw->wiphy));
 		goto err_iounmap;
 	}
 
@@ -2952,7 +2952,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 			 IRQF_SHARED, MWL8K_NAME, hw);
 	if (rc) {
 		printk(KERN_ERR "%s: failed to register IRQ handler\n",
-		       priv->name);
+		       wiphy_name(hw->wiphy));
 		goto err_free_queues;
 	}
 
@@ -2962,14 +2962,16 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 	/* Ask userland hotplug daemon for the device firmware */
 	rc = mwl8k_request_firmware(priv, (u32)id->driver_data);
 	if (rc) {
-		printk(KERN_ERR "%s: Firmware files not found\n", priv->name);
+		printk(KERN_ERR "%s: Firmware files not found\n",
+		       wiphy_name(hw->wiphy));
 		goto err_free_irq;
 	}
 
 	/* Load firmware into hardware */
-	rc = mwl8k_load_firmware(priv);
+	rc = mwl8k_load_firmware(hw);
 	if (rc) {
-		printk(KERN_ERR "%s: Cannot start firmware\n", priv->name);
+		printk(KERN_ERR "%s: Cannot start firmware\n",
+		       wiphy_name(hw->wiphy));
 		goto err_stop_firmware;
 	}
 
@@ -2986,14 +2988,15 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 	/* Get config data, mac addrs etc */
 	rc = mwl8k_cmd_get_hw_spec(hw);
 	if (rc) {
-		printk(KERN_ERR "%s: Cannot initialise firmware\n", priv->name);
+		printk(KERN_ERR "%s: Cannot initialise firmware\n",
+		       wiphy_name(hw->wiphy));
 		goto err_stop_firmware;
 	}
 
 	/* Turn radio off */
 	rc = mwl8k_cmd_802_11_radio_disable(hw);
 	if (rc) {
-		printk(KERN_ERR "%s: Cannot disable\n", priv->name);
+		printk(KERN_ERR "%s: Cannot disable\n", wiphy_name(hw->wiphy));
 		goto err_stop_firmware;
 	}
 
@@ -3003,7 +3006,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 
 	rc = ieee80211_register_hw(hw);
 	if (rc) {
-		printk(KERN_ERR "%s: Cannot register device\n", priv->name);
+		printk(KERN_ERR "%s: Cannot register device\n",
+		       wiphy_name(hw->wiphy));
 		goto err_stop_firmware;
 	}
 
@@ -3086,8 +3090,7 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev)
 
 	mwl8k_rxq_deinit(hw, 0);
 
-	pci_free_consistent(priv->pdev, 4,
-				priv->cookie, priv->cookie_dma);
+	pci_free_consistent(priv->pdev, 4, priv->cookie, priv->cookie_dma);
 
 	pci_iounmap(pdev, priv->regs);
 	pci_set_drvdata(pdev, NULL);
@@ -3116,3 +3119,8 @@ static void __exit mwl8k_exit(void)
 
 module_init(mwl8k_init);
 module_exit(mwl8k_exit);
+
+MODULE_DESCRIPTION(MWL8K_DESC);
+MODULE_VERSION(MWL8K_VERSION);
+MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com>");
+MODULE_LICENSE("GPL");
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 09/28] mwl8k: use cond_resched() when loading firmware blocks
From: Lennert Buytenhek @ 2009-10-22 18:20 UTC (permalink / raw)
  To: linux-wireless

Since each firmware block takes on the order of several hundred usec
to upload to the hardware, using msleep in the inner loop would make
the firmware loading process take a lot more time than just doing
busy-waiting like we do now.  But if we keep the busy-waiting, we can
at least add a cond_resched() to the inner loop so that we give other
tasks a chance to run while the firmware is being loaded.

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index fcf7139..496d3c5 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -12,6 +12,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/list.h>
 #include <linux/pci.h>
@@ -428,6 +429,7 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length)
 			break;
 		}
 
+		cond_resched();
 		udelay(1);
 	} while (--loops);
 
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 03/28] mwl8k: minor transmit quiescing rework
From: Lennert Buytenhek @ 2009-10-22 18:19 UTC (permalink / raw)
  To: linux-wireless

Minor changes to the transmit quiescing logic:
- Clarify the locking rules for ->tx_wait: only the holder of fw_mutex
  can wait for the TX path to become idle, but tx_wait itself is read
  and cleared by the TX reclaim tasklet under tx_lock.
- Inline mwl8k_txq_busy() in its callers.
- There's no need to kick the transmitter again in
  mwl8k_tx_wait_empty(), since it will have been kicked when the
  packets currently in the TX ring were added to it.
- If the TX ring didn't drain in time, run mwl8k_scan_tx_ring() after
  reading priv->pending_pkts without dropping tx_lock in between.

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 252ef9c..ba7b8ef 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -142,12 +142,14 @@ struct mwl8k_priv {
 	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;
 
+	/* TX quiesce completion, protected by fw_mutex and tx_lock */
+	struct completion *tx_wait;
+
 	struct ieee80211_vif *vif;
 
 	struct ieee80211_channel *current_channel;
@@ -1064,11 +1066,6 @@ static inline void mwl8k_tx_start(struct mwl8k_priv *priv)
 	ioread32(priv->regs + MWL8K_HIU_INT_CODE);
 }
 
-static inline int mwl8k_txq_busy(struct mwl8k_priv *priv)
-{
-	return priv->pending_tx_pkts;
-}
-
 struct mwl8k_txq_info {
 	u32 fw_owned;
 	u32 drv_owned;
@@ -1088,7 +1085,6 @@ static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv,
 
 	memset(txinfo, 0, MWL8K_TX_QUEUES * sizeof(struct mwl8k_txq_info));
 
-	spin_lock_bh(&priv->tx_lock);
 	for (count = 0; count < MWL8K_TX_QUEUES; count++) {
 		txq = priv->txq + count;
 		txinfo[count].len = txq->tx_stats.len;
@@ -1107,30 +1103,26 @@ static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv,
 				txinfo[count].unused++;
 		}
 	}
-	spin_unlock_bh(&priv->tx_lock);
 
 	return ndescs;
 }
 
 /*
- * Must be called with hw->fw_mutex held and tx queues stopped.
+ * Must be called with priv->fw_mutex held and tx queues stopped.
  */
 static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
 {
 	struct mwl8k_priv *priv = hw->priv;
-	DECLARE_COMPLETION_ONSTACK(cmd_wait);
+	DECLARE_COMPLETION_ONSTACK(tx_wait);
 	u32 count;
 	unsigned long timeout;
 
 	might_sleep();
 
 	spin_lock_bh(&priv->tx_lock);
-	count = mwl8k_txq_busy(priv);
-	if (count) {
-		priv->tx_wait = &cmd_wait;
-		if (priv->radio_on)
-			mwl8k_tx_start(priv);
-	}
+	count = priv->pending_tx_pkts;
+	if (count)
+		priv->tx_wait = &tx_wait;
 	spin_unlock_bh(&priv->tx_lock);
 
 	if (count) {
@@ -1138,20 +1130,20 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
 		int index;
 		int newcount;
 
-		timeout = wait_for_completion_timeout(&cmd_wait,
+		timeout = wait_for_completion_timeout(&tx_wait,
 					msecs_to_jiffies(5000));
 		if (timeout)
 			return 0;
 
 		spin_lock_bh(&priv->tx_lock);
 		priv->tx_wait = NULL;
-		newcount = mwl8k_txq_busy(priv);
+		newcount = priv->pending_tx_pkts;
+		mwl8k_scan_tx_ring(priv, txinfo);
 		spin_unlock_bh(&priv->tx_lock);
 
 		printk(KERN_ERR "%s(%u) TIMEDOUT:5000ms Pend:%u-->%u\n",
 		       __func__, __LINE__, count, newcount);
 
-		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",
@@ -2397,7 +2389,7 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id)
 
 	if (status & MWL8K_A2H_INT_QUEUE_EMPTY) {
 		if (!mutex_is_locked(&priv->fw_mutex) &&
-		    priv->radio_on && mwl8k_txq_busy(priv))
+		    priv->radio_on && priv->pending_tx_pkts)
 			mwl8k_tx_start(priv);
 	}
 
@@ -2800,7 +2792,7 @@ static void mwl8k_tx_reclaim_handler(unsigned long data)
 	for (i = 0; i < MWL8K_TX_QUEUES; i++)
 		mwl8k_txq_reclaim(hw, i, 0);
 
-	if (priv->tx_wait != NULL && mwl8k_txq_busy(priv) == 0) {
+	if (priv->tx_wait != NULL && !priv->pending_tx_pkts) {
 		complete(priv->tx_wait);
 		priv->tx_wait = NULL;
 	}
@@ -2932,11 +2924,12 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 	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);
 
+	priv->tx_wait = NULL;
+
 	for (i = 0; i < MWL8K_TX_QUEUES; i++) {
 		rc = mwl8k_txq_init(hw, i);
 		if (rc)
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 06/28] mwl8k: implement FIF_ALLMULTI
From: Lennert Buytenhek @ 2009-10-22 18:19 UTC (permalink / raw)
  To: linux-wireless

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

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 77985e9..cc58ecb 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -1543,16 +1543,14 @@ struct mwl8k_cmd_mac_multicast_adr {
 #define MWL8K_ENABLE_RX_BROADCAST	0x0008
 
 static struct mwl8k_cmd_pkt *
-__mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw,
+__mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, int allmulti,
 			      int mc_count, struct dev_addr_list *mclist)
 {
 	struct mwl8k_priv *priv = hw->priv;
 	struct mwl8k_cmd_mac_multicast_adr *cmd;
-	int allmulti;
 	int size;
 
-	allmulti = 0;
-	if (mc_count > priv->num_mcaddrs) {
+	if (allmulti || mc_count > priv->num_mcaddrs) {
 		allmulti = 1;
 		mc_count = 0;
 	}
@@ -2680,7 +2678,14 @@ static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw,
 {
 	struct mwl8k_cmd_pkt *cmd;
 
-	cmd = __mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist);
+	/*
+	 * Synthesize and return a command packet that programs the
+	 * hardware multicast address filter.  At this point we don't
+	 * know whether FIF_ALLMULTI is being requested, but if it is,
+	 * we'll end up throwing this packet away and creating a new
+	 * one in mwl8k_configure_filter().
+	 */
+	cmd = __mwl8k_cmd_mac_multicast_adr(hw, 0, mc_count, mclist);
 
 	return (unsigned long)cmd;
 }
@@ -2691,10 +2696,10 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw,
 				   u64 multicast)
 {
 	struct mwl8k_priv *priv = hw->priv;
-	struct mwl8k_cmd_pkt *multicast_adr_cmd;
+	struct mwl8k_cmd_pkt *cmd;
 
 	/* Clear unsupported feature flags */
-	*total_flags &= FIF_BCN_PRBRESP_PROMISC;
+	*total_flags &= FIF_ALLMULTI | FIF_BCN_PRBRESP_PROMISC;
 
 	if (mwl8k_fw_lock(hw))
 		return;
@@ -2713,10 +2718,22 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw,
 		}
 	}
 
-	multicast_adr_cmd = (void *)(unsigned long)multicast;
-	if (multicast_adr_cmd != NULL) {
-		mwl8k_post_cmd(hw, multicast_adr_cmd);
-		kfree(multicast_adr_cmd);
+	cmd = (void *)(unsigned long)multicast;
+
+	/*
+	 * If FIF_ALLMULTI is being requested, throw away the command
+	 * packet that ->prepare_multicast() built and replace it with
+	 * a command packet that enables reception of all multicast
+	 * packets.
+	 */
+	if (*total_flags & FIF_ALLMULTI) {
+		kfree(cmd);
+		cmd = __mwl8k_cmd_mac_multicast_adr(hw, 1, 0, NULL);
+	}
+
+	if (cmd != NULL) {
+		mwl8k_post_cmd(hw, cmd);
+		kfree(cmd);
 	}
 
 	mwl8k_fw_unlock(hw);
-- 
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