* Re: linux-next: build failure after merge of the moduleh tree
From: Kalle Valo @ 2011-10-04 7:35 UTC (permalink / raw)
To: Stephen Rothwell
Cc: Paul Gortmaker, linux-next, linux-kernel, John W. Linville,
linux-wireless
In-Reply-To: <20111004180333.44f741dc08063a918c9b581f@canb.auug.org.au>
On 10/04/2011 10:03 AM, Stephen Rothwell wrote:
> After merging the moduleh tree, today's linux-next build (x86_64
> allmodconfig) failed like this:
>
> drivers/net/wireless/ath/ath6kl/debug.c:237:11: error: 'THIS_MODULE' undeclared here (not in a function)
>
> Caused by commit 9a7308341b71 ("ath6kl: silence "invalid rate" warning")
> from the wireless tree interacting with the module.h split.
>
> I added this patch:
John&Paul, how do we handle this patch?
> From: Stephen Rothwell <sfr@canb.auug.org.au>
> Date: Tue, 4 Oct 2011 18:01:03 +1100
> Subject: [PATCH] ath6kl: THIS_MODULES needs export.h
>
> Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
> ---
> drivers/net/wireless/ath/ath6kl/debug.c | 1 +
> 1 files changed, 1 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c
> index ba3f23d..7879b53 100644
> --- a/drivers/net/wireless/ath/ath6kl/debug.c
> +++ b/drivers/net/wireless/ath/ath6kl/debug.c
> @@ -19,6 +19,7 @@
> #include <linux/circ_buf.h>
> #include <linux/fs.h>
> #include <linux/vmalloc.h>
> +#include <linux/export.h>
>
> #include "debug.h"
> #include "target.h"
Kalle
^ permalink raw reply
* Re: [PATCH] cfg80211: allow channel change on monitor i/f if no active i/f present
From: Johannes Berg @ 2011-10-04 6:37 UTC (permalink / raw)
To: John W. Linville; +Cc: linux-wireless, Gilboa Davara
In-Reply-To: <1317673413-1467-1-git-send-email-linville@tuxdriver.com>
On Mon, 2011-10-03 at 16:23 -0400, John W. Linville wrote:
> This is the latest attempt to address the long-standing complaint from
> the aircrack-ng folks about being unable to change the channel on
> monitor interfaces. This version checks for the existance of other
> "active" interfaces and refuses the channel change if they are present.
>
> https://bugzilla.redhat.com/show_bug.cgi?id=654344
Thanks for working on this.
> @@ -81,10 +81,32 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
> enum nl80211_channel_type channel_type)
> {
> struct ieee80211_channel *chan;
> - int result;
> + int result, active_intf_present = 0;
> + struct wireless_dev *mon_wdev = NULL;
> +
> + if (wdev && wdev->iftype == NL80211_IFTYPE_MONITOR) {
> + mon_wdev = wdev;
> +
> + ASSERT_RDEV_LOCK(rdev);
> +
> + /* rdev->devlist_mtx locked by callers */
> + list_for_each_entry(wdev, &rdev->netdev_list, list) {
> + if (wdev && wdev != mon_wdev &&
> + (wdev->iftype == NL80211_IFTYPE_ADHOC ||
> + wdev->iftype == NL80211_IFTYPE_AP ||
> + wdev->iftype == NL80211_IFTYPE_AP_VLAN ||
> + wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
> + wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
> + active_intf_present = 1;
> + break;
> + }
> + }
> +
> + if (active_intf_present)
> + return -EINVAL;
>
> - if (wdev && wdev->iftype == NL80211_IFTYPE_MONITOR)
> wdev = NULL;
> + }
This really isn't the problem though, mac80211 will correctly treat
monitor interfaces already, and drivers are pretty much expected to do
the same thing.
> @@ -131,5 +153,8 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
> if (wdev)
> wdev->channel = chan;
>
> + if (mon_wdev)
> + mon_wdev->channel = chan;
This is the issue, it doesn't work. I'm finally getting to a point where
I'm not sure I care any more though, if the people who user monitor mode
are happy with this patch and don't care about getting the wrong results
then who am I to complain?
Maybe you should respin this patch with just the last bit. The checking
above is pretty much useless. Also please add *huge* warnings to it that
this *will* give the wrong results.
Alternatively, it could be fixed up properly, but I think to do that we
need a cfg80211 get_channel op to ask mac80211 what channel it really is
using. Not that this will help much once we go multi-channel :-)
johannes
^ permalink raw reply
* Re: [PATCH] mwifiex: use separate wait queue for each command node
From: Johannes Berg @ 2011-10-04 6:29 UTC (permalink / raw)
To: Bing Zhao
Cc: linux-wireless, John W. Linville, Amitkumar Karwar, Kiran Divekar,
Yogesh Powar, Frank Huang
In-Reply-To: <1317701303-21871-1-git-send-email-bzhao@marvell.com>
On Mon, 2011-10-03 at 21:08 -0700, Bing Zhao wrote:
> From: Amitkumar Karwar <akarwar@marvell.com>
>
> Currently global wait queue (adapter->cmd_wait_q) is used for
> sending synchronous commands to FW. When two threads enter in
> mwifiex_send_cmd_sync() routine at the same time, both the
> threads wait for their command responses. They wake up
> simultaneously after getting response of 1st command. After
> this when a thread is waiting for command response of 3rd
> command, it wakes up after getting response of 2nd command
> and so on. Therefore we don't wait for the response of last
> command(0xaa) during unload. Hence while next time loading the
> driver command time out is seen for INIT command.
>
> This problem is resolved by having separate wait queue for each
> command. Since driver sends multiple scan commands asynchronously
> to FW for scanning the network, we will need separate wait queue
> for the whole scan operation. Earlier the global wait queue was
> being used for scan.
I can't say I really care about this, but this seems completely
pointless. A waitqueue doesn't imply that just a single thing can be
waiting on it, since you should be using wait_for() macros. Thus, all
you *really* need is a bit in the command that marks it as completed,
and then you use the waitqueue to wait for that bit to be set.
johannes
^ permalink raw reply
* [PATCH] mwifiex: add support for Marvell pcie8766 chipset
From: Bing Zhao @ 2011-10-04 4:08 UTC (permalink / raw)
To: linux-wireless
Cc: John W. Linville, Amitkumar Karwar, Kiran Divekar, Yogesh Powar,
Frank Huang, Bing Zhao
In-Reply-To: <1317701303-21871-1-git-send-email-bzhao@marvell.com>
From: Amitkumar Karwar <akarwar@marvell.com>
This patch supports 88W8766P chipset with a PCIe interface.
The corresponding firmware image file is located at:
"mrvl/pcie8766_uapsta.bin"
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Ramesh Radhakrishnan <rramesh@marvell.com>
Signed-off-by: Yogesh Ashok Powar <yogeshp@marvell.com>
Signed-off-by: Kiran Divekar <dkiran@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: Frank Huang <frankh@marvell.com>
---
drivers/net/wireless/mwifiex/11n_aggr.c | 3 +-
drivers/net/wireless/mwifiex/Kconfig | 11 +
drivers/net/wireless/mwifiex/Makefile | 3 +
drivers/net/wireless/mwifiex/cmdevt.c | 11 +-
drivers/net/wireless/mwifiex/fw.h | 30 +-
drivers/net/wireless/mwifiex/init.c | 17 +-
drivers/net/wireless/mwifiex/main.c | 4 +-
drivers/net/wireless/mwifiex/main.h | 20 +-
drivers/net/wireless/mwifiex/pcie.c | 1948 ++++++++++++++++++++++++++++
drivers/net/wireless/mwifiex/pcie.h | 148 +++
drivers/net/wireless/mwifiex/sdio.c | 19 +-
drivers/net/wireless/mwifiex/sdio.h | 24 +-
drivers/net/wireless/mwifiex/sta_cmd.c | 64 +
drivers/net/wireless/mwifiex/sta_cmdresp.c | 2 +
drivers/net/wireless/mwifiex/sta_tx.c | 2 +-
drivers/net/wireless/mwifiex/txrx.c | 2 +-
drivers/net/wireless/mwifiex/util.h | 9 +-
drivers/net/wireless/mwifiex/wmm.c | 4 +-
18 files changed, 2284 insertions(+), 37 deletions(-)
create mode 100644 drivers/net/wireless/mwifiex/pcie.c
create mode 100644 drivers/net/wireless/mwifiex/pcie.h
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c
index 9e63d16..079e553 100644
--- a/drivers/net/wireless/mwifiex/11n_aggr.c
+++ b/drivers/net/wireless/mwifiex/11n_aggr.c
@@ -246,8 +246,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
tx_param.next_pkt_len = 0;
ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
- skb_aggr->data,
- skb_aggr->len, &tx_param);
+ skb_aggr, &tx_param);
switch (ret) {
case -EBUSY:
spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig
index 8696292..8f2797a 100644
--- a/drivers/net/wireless/mwifiex/Kconfig
+++ b/drivers/net/wireless/mwifiex/Kconfig
@@ -19,3 +19,14 @@ config MWIFIEX_SDIO
If you choose to build it as a module, it will be called
mwifiex_sdio.
+
+config MWIFIEX_PCIE
+ tristate "Marvell WiFi-Ex Driver for PCIE 8766"
+ depends on MWIFIEX && PCI
+ select FW_LOADER
+ ---help---
+ This adds support for wireless adapters based on Marvell
+ 8766 chipset with PCIe interface.
+
+ If you choose to build it as a module, it will be called
+ mwifiex_pcie.
diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile
index 42cb733..b0257ad 100644
--- a/drivers/net/wireless/mwifiex/Makefile
+++ b/drivers/net/wireless/mwifiex/Makefile
@@ -39,3 +39,6 @@ obj-$(CONFIG_MWIFIEX) += mwifiex.o
mwifiex_sdio-y += sdio.o
obj-$(CONFIG_MWIFIEX_SDIO) += mwifiex_sdio.o
+
+mwifiex_pcie-y += pcie.o
+obj-$(CONFIG_MWIFIEX_PCIE) += mwifiex_pcie.o
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index aab805f..08f7096 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -99,7 +99,7 @@ mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter,
skb_trim(cmd_node->cmd_skb, 0);
if (cmd_node->resp_skb) {
- dev_kfree_skb_any(cmd_node->resp_skb);
+ adapter->if_ops.cmdrsp_complete(adapter, cmd_node->resp_skb);
cmd_node->resp_skb = NULL;
}
}
@@ -181,8 +181,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
skb_push(cmd_node->cmd_skb, INTF_HEADER_LEN);
ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD,
- cmd_node->cmd_skb->data,
- cmd_node->cmd_skb->len, NULL);
+ cmd_node->cmd_skb, NULL);
skb_pull(cmd_node->cmd_skb, INTF_HEADER_LEN);
@@ -243,8 +242,7 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
skb_push(adapter->sleep_cfm, INTF_HEADER_LEN);
ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD,
- adapter->sleep_cfm->data,
- adapter->sleep_cfm->len, NULL);
+ adapter->sleep_cfm, NULL);
skb_pull(adapter->sleep_cfm, INTF_HEADER_LEN);
if (ret == -1) {
@@ -411,8 +409,7 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter)
adapter->event_cause = 0;
adapter->event_skb = NULL;
-
- dev_kfree_skb_any(skb);
+ adapter->if_ops.event_complete(adapter, skb);
return ret;
}
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index f23ec72..71c61b7 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -84,7 +84,8 @@ enum KEY_TYPE_ID {
#define MAX_FIRMWARE_POLL_TRIES 100
-#define FIRMWARE_READY 0xfedc
+#define FIRMWARE_READY_SDIO 0xfedc
+#define FIRMWARE_READY_PCIE 0xfedcba00
enum MWIFIEX_802_11_PRIVACY_FILTER {
MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL,
@@ -221,7 +222,7 @@ enum MWIFIEX_802_11_WEP_STATUS {
#define HostCmd_CMD_802_11_HS_CFG_ENH 0x00e5
#define HostCmd_CMD_CAU_REG_ACCESS 0x00ed
#define HostCmd_CMD_SET_BSS_MODE 0x00f7
-
+#define HostCmd_CMD_PCIE_DESC_DETAILS 0x00fa
enum ENH_PS_MODES {
EN_PS = 1,
@@ -1137,6 +1138,30 @@ struct host_cmd_ds_set_bss_mode {
u8 con_type;
} __packed;
+struct host_cmd_ds_pcie_details {
+ /* TX buffer descriptor ring address */
+ u32 txbd_addr_lo;
+ u32 txbd_addr_hi;
+ /* TX buffer descriptor ring count */
+ u32 txbd_count;
+
+ /* RX buffer descriptor ring address */
+ u32 rxbd_addr_lo;
+ u32 rxbd_addr_hi;
+ /* RX buffer descriptor ring count */
+ u32 rxbd_count;
+
+ /* Event buffer descriptor ring address */
+ u32 evtbd_addr_lo;
+ u32 evtbd_addr_hi;
+ /* Event buffer descriptor ring count */
+ u32 evtbd_count;
+
+ /* Sleep cookie buffer physical address */
+ u32 sleep_cookie_addr_lo;
+ u32 sleep_cookie_addr_hi;
+} __packed;
+
struct host_cmd_ds_command {
__le16 command;
__le16 size;
@@ -1184,6 +1209,7 @@ struct host_cmd_ds_command {
struct host_cmd_ds_rf_reg_access rf_reg;
struct host_cmd_ds_pmic_reg_access pmic_reg;
struct host_cmd_ds_set_bss_mode bss_mode;
+ struct host_cmd_ds_pcie_details pcie_host_spec;
struct host_cmd_ds_802_11_eeprom_access eeprom;
} params;
} __packed;
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index e1076b4..0ce72fc 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -191,7 +191,12 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
(adapter->sleep_cfm->data);
adapter->cmd_sent = false;
- adapter->data_sent = true;
+
+ if (adapter->iface_type == MWIFIEX_PCIE)
+ adapter->data_sent = false;
+ else
+ adapter->data_sent = true;
+
adapter->cmd_resp_received = false;
adapter->event_received = false;
adapter->data_received = false;
@@ -581,11 +586,13 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
struct mwifiex_fw_image *pmfw)
{
- int ret, winner;
+ int ret;
u32 poll_num = 1;
+ adapter->winner = 0;
+
/* Check if firmware is already running */
- ret = adapter->if_ops.check_fw_status(adapter, poll_num, &winner);
+ ret = adapter->if_ops.check_fw_status(adapter, poll_num);
if (!ret) {
dev_notice(adapter->dev,
"WLAN FW already running! Skip FW download\n");
@@ -594,7 +601,7 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
poll_num = MAX_FIRMWARE_POLL_TRIES;
/* Check if we are the winner for downloading FW */
- if (!winner) {
+ if (!adapter->winner) {
dev_notice(adapter->dev,
"Other interface already running!"
" Skip FW download\n");
@@ -612,7 +619,7 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
poll_fw:
/* Check if the firmware is downloaded successfully or not */
- ret = adapter->if_ops.check_fw_status(adapter, poll_num, NULL);
+ ret = adapter->if_ops.check_fw_status(adapter, poll_num);
if (ret) {
dev_err(adapter->dev, "FW failed to be active in time\n");
return -1;
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index 13264b8..7bee851 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -661,7 +661,7 @@ mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter)
*/
int
mwifiex_add_card(void *card, struct semaphore *sem,
- struct mwifiex_if_ops *if_ops)
+ struct mwifiex_if_ops *if_ops, u8 iface_type)
{
struct mwifiex_adapter *adapter;
char fmt[64];
@@ -675,6 +675,8 @@ mwifiex_add_card(void *card, struct semaphore *sem,
goto err_init_sw;
}
+ adapter->iface_type = iface_type;
+
adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
adapter->surprise_removed = false;
init_waitqueue_head(&adapter->init_wait_q);
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 842ae6b..0b8c98d 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -37,6 +37,7 @@
#include "ioctl.h"
#include "util.h"
#include "fw.h"
+#include "pcie.h"
extern const char driver_version[];
@@ -107,6 +108,8 @@ enum {
#define MAX_FREQUENCY_BAND_BG 2484
+#define MWIFIEX_EVENT_HEADER_LEN 4
+
struct mwifiex_dbg {
u32 num_cmd_host_to_card_failure;
u32 num_cmd_sleep_cfm_host_to_card_failure;
@@ -156,6 +159,11 @@ enum MWIFIEX_PS_STATE {
PS_STATE_SLEEP
};
+enum mwifiex_iface_type {
+ MWIFIEX_SDIO,
+ MWIFIEX_PCIE,
+};
+
struct mwifiex_add_ba_param {
u32 tx_win_size;
u32 rx_win_size;
@@ -518,27 +526,31 @@ struct cmd_ctrl_node {
struct mwifiex_if_ops {
int (*init_if) (struct mwifiex_adapter *);
void (*cleanup_if) (struct mwifiex_adapter *);
- int (*check_fw_status) (struct mwifiex_adapter *, u32, int *);
+ int (*check_fw_status) (struct mwifiex_adapter *, u32);
int (*prog_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *);
int (*register_dev) (struct mwifiex_adapter *);
void (*unregister_dev) (struct mwifiex_adapter *);
int (*enable_int) (struct mwifiex_adapter *);
int (*process_int_status) (struct mwifiex_adapter *);
- int (*host_to_card) (struct mwifiex_adapter *, u8,
- u8 *payload, u32 pkt_len,
+ int (*host_to_card) (struct mwifiex_adapter *, u8, struct sk_buff *,
struct mwifiex_tx_param *);
int (*wakeup) (struct mwifiex_adapter *);
int (*wakeup_complete) (struct mwifiex_adapter *);
+ /* Interface specific functions */
void (*update_mp_end_port) (struct mwifiex_adapter *, u16);
void (*cleanup_mpa_buf) (struct mwifiex_adapter *);
+ int (*cmdrsp_complete) (struct mwifiex_adapter *, struct sk_buff *);
+ int (*event_complete) (struct mwifiex_adapter *, struct sk_buff *);
};
struct mwifiex_adapter {
+ u8 iface_type;
struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM];
u8 priv_num;
const struct firmware *firmware;
char fw_name[32];
+ int winner;
struct device *dev;
bool surprise_removed;
u32 fw_release_number;
@@ -876,7 +888,7 @@ struct mwifiex_private *mwifiex_bss_index_to_priv(struct mwifiex_adapter
*adapter, u8 bss_index);
int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
u32 func_init_shutdown);
-int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *);
+int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8);
int mwifiex_remove_card(struct mwifiex_adapter *, struct semaphore *);
void mwifiex_get_version(struct mwifiex_adapter *adapter, char *version,
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c
new file mode 100644
index 0000000..602c254
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/pcie.c
@@ -0,0 +1,1948 @@
+/*
+ * Marvell Wireless LAN device driver: PCIE specific handling
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include <linux/firmware.h>
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+#include "pcie.h"
+
+#define PCIE_VERSION "1.0"
+#define DRV_NAME "Marvell mwifiex PCIe"
+
+static u8 user_rmmod;
+
+static struct mwifiex_if_ops pcie_ops;
+
+static struct semaphore add_remove_card_sem;
+static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter);
+static int mwifiex_pcie_resume(struct pci_dev *pdev);
+
+/*
+ * This function is called after skb allocation to update
+ * "skb->cb" with physical address of data pointer.
+ */
+static phys_addr_t *mwifiex_update_sk_buff_pa(struct sk_buff *skb)
+{
+ phys_addr_t *buf_pa = MWIFIEX_SKB_PACB(skb);
+
+ *buf_pa = (phys_addr_t)virt_to_phys(skb->data);
+
+ return buf_pa;
+}
+
+/*
+ * This function reads sleep cookie and checks if FW is ready
+ */
+static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter)
+{
+ u32 *cookie_addr;
+ struct pcie_service_card *card = adapter->card;
+
+ if (card->sleep_cookie) {
+ cookie_addr = (u32 *)card->sleep_cookie->data;
+ dev_dbg(adapter->dev, "info: ACCESS_HW: sleep cookie=0x%x\n",
+ *cookie_addr);
+ if (*cookie_addr == FW_AWAKE_COOKIE)
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * This function probes an mwifiex device and registers it. It allocates
+ * the card structure, enables PCIE function number and initiates the
+ * device registration and initialization procedure by adding a logical
+ * interface.
+ */
+static int __devinit mwifiex_pcie_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct pcie_service_card *card;
+
+ pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n",
+ pdev->vendor, pdev->device, pdev->revision);
+
+ card = kzalloc(sizeof(struct pcie_service_card), GFP_KERNEL);
+ if (!card) {
+ pr_err("%s: failed to alloc memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ card->dev = pdev;
+
+ if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops,
+ MWIFIEX_PCIE)) {
+ pr_err("%s failed\n", __func__);
+ kfree(card);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * This function removes the interface and frees up the card structure.
+ */
+static void mwifiex_pcie_remove(struct pci_dev *pdev)
+{
+ struct pcie_service_card *card;
+ struct mwifiex_adapter *adapter;
+ int i;
+
+ card = pci_get_drvdata(pdev);
+ if (!card)
+ return;
+
+ adapter = card->adapter;
+ if (!adapter || !adapter->priv_num)
+ return;
+
+ if (user_rmmod) {
+#ifdef CONFIG_PM
+ if (adapter->is_suspended)
+ mwifiex_pcie_resume(pdev);
+#endif
+
+ for (i = 0; i < adapter->priv_num; i++)
+ if ((GET_BSS_ROLE(adapter->priv[i]) ==
+ MWIFIEX_BSS_ROLE_STA) &&
+ adapter->priv[i]->media_connected)
+ mwifiex_deauthenticate(adapter->priv[i], NULL);
+
+ mwifiex_disable_auto_ds(mwifiex_get_priv(adapter,
+ MWIFIEX_BSS_ROLE_ANY));
+
+ mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter,
+ MWIFIEX_BSS_ROLE_ANY),
+ MWIFIEX_FUNC_SHUTDOWN);
+ }
+
+ mwifiex_remove_card(card->adapter, &add_remove_card_sem);
+ kfree(card);
+}
+
+/*
+ * Kernel needs to suspend all functions separately. Therefore all
+ * registered functions must have drivers with suspend and resume
+ * methods. Failing that the kernel simply removes the whole card.
+ *
+ * If already not suspended, this function allocates and sends a host
+ * sleep activate request to the firmware and turns off the traffic.
+ */
+static int mwifiex_pcie_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct mwifiex_adapter *adapter;
+ struct pcie_service_card *card;
+ int hs_actived, i;
+
+ if (pdev) {
+ card = (struct pcie_service_card *) pci_get_drvdata(pdev);
+ if (!card || card->adapter) {
+ pr_err("Card or adapter structure is not valid\n");
+ return 0;
+ }
+ } else {
+ pr_err("PCIE device is not specified\n");
+ return 0;
+ }
+
+ adapter = card->adapter;
+
+ hs_actived = mwifiex_enable_hs(adapter);
+
+ /* Indicate device suspended */
+ adapter->is_suspended = true;
+
+ for (i = 0; i < adapter->priv_num; i++)
+ netif_carrier_off(adapter->priv[i]->netdev);
+
+ return 0;
+}
+
+/*
+ * Kernel needs to suspend all functions separately. Therefore all
+ * registered functions must have drivers with suspend and resume
+ * methods. Failing that the kernel simply removes the whole card.
+ *
+ * If already not resumed, this function turns on the traffic and
+ * sends a host sleep cancel request to the firmware.
+ */
+static int mwifiex_pcie_resume(struct pci_dev *pdev)
+{
+ struct mwifiex_adapter *adapter;
+ struct pcie_service_card *card;
+ int i;
+
+ if (pdev) {
+ card = (struct pcie_service_card *) pci_get_drvdata(pdev);
+ if (!card || !card->adapter) {
+ pr_err("Card or adapter structure is not valid\n");
+ return 0;
+ }
+ } else {
+ pr_err("PCIE device is not specified\n");
+ return 0;
+ }
+
+ adapter = card->adapter;
+
+ if (!adapter->is_suspended) {
+ dev_warn(adapter->dev, "Device already resumed\n");
+ return 0;
+ }
+
+ adapter->is_suspended = false;
+
+ for (i = 0; i < adapter->priv_num; i++)
+ if (adapter->priv[i]->media_connected)
+ netif_carrier_on(adapter->priv[i]->netdev);
+
+ mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
+ MWIFIEX_ASYNC_CMD);
+
+ return 0;
+}
+
+#define PCIE_VENDOR_ID_MARVELL (0x11ab)
+#define PCIE_DEVICE_ID_MARVELL_88W8766P (0x2b30)
+
+static DEFINE_PCI_DEVICE_TABLE(mwifiex_ids) = {
+ {
+ PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8766P,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(pci, mwifiex_ids);
+
+/* PCI Device Driver */
+static struct pci_driver mwifiex_pcie = {
+ .name = "mwifiex_pcie",
+ .id_table = mwifiex_ids,
+ .probe = mwifiex_pcie_probe,
+ .remove = mwifiex_pcie_remove,
+#ifdef CONFIG_PM
+ /* Power Management Hooks */
+ .suspend = mwifiex_pcie_suspend,
+ .resume = mwifiex_pcie_resume,
+#endif
+};
+
+/*
+ * This function writes data into PCIE card register.
+ */
+static int mwifiex_write_reg(struct mwifiex_adapter *adapter, int reg, u32 data)
+{
+ struct pcie_service_card *card = adapter->card;
+
+ iowrite32(data, card->pci_mmap1 + reg);
+
+ return 0;
+}
+
+/*
+ * This function reads data from PCIE card register.
+ */
+static int mwifiex_read_reg(struct mwifiex_adapter *adapter, int reg, u32 *data)
+{
+ struct pcie_service_card *card = adapter->card;
+
+ *data = ioread32(card->pci_mmap1 + reg);
+
+ return 0;
+}
+
+/*
+ * This function wakes up the card.
+ *
+ * A host power up command is written to the card configuration
+ * register to wake up the card.
+ */
+static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
+{
+ int i = 0;
+
+ while (mwifiex_pcie_ok_to_access_hw(adapter)) {
+ i++;
+ udelay(10);
+ /* 50ms max wait */
+ if (i == 50000)
+ break;
+ }
+
+ dev_dbg(adapter->dev, "event: Wakeup device...\n");
+
+ /* Enable interrupts or any chip access will wakeup device */
+ if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK, HOST_INTR_MASK)) {
+ dev_warn(adapter->dev, "Enable host interrupt failed\n");
+ return -1;
+ }
+
+ dev_dbg(adapter->dev, "PCIE wakeup: Setting PS_STATE_AWAKE\n");
+ adapter->ps_state = PS_STATE_AWAKE;
+
+ return 0;
+}
+
+/*
+ * This function is called after the card has woken up.
+ *
+ * The card configuration register is reset.
+ */
+static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter)
+{
+ dev_dbg(adapter->dev, "cmd: Wakeup device completed\n");
+
+ return 0;
+}
+
+/*
+ * This function disables the host interrupt.
+ *
+ * The host interrupt mask is read, the disable bit is reset and
+ * written back to the card host interrupt mask register.
+ */
+static int mwifiex_pcie_disable_host_int(struct mwifiex_adapter *adapter)
+{
+ if (mwifiex_pcie_ok_to_access_hw(adapter)) {
+ if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK,
+ 0x00000000)) {
+ dev_warn(adapter->dev, "Disable host interrupt failed\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * This function enables the host interrupt.
+ *
+ * The host interrupt enable mask is written to the card
+ * host interrupt mask register.
+ */
+static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter)
+{
+ if (mwifiex_pcie_ok_to_access_hw(adapter)) {
+ /* Simply write the mask to the register */
+ if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK,
+ HOST_INTR_MASK)) {
+ dev_warn(adapter->dev, "Enable host interrupt failed\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * This function creates buffer descriptor ring for TX
+ */
+static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ struct sk_buff *skb;
+ int i;
+ phys_addr_t *buf_pa;
+
+ /*
+ * driver maintaines the write pointer and firmware maintaines the read
+ * pointer. The write pointer starts at 0 (zero) while the read pointer
+ * starts at zero with rollover bit set
+ */
+ card->txbd_wrptr = 0;
+ card->txbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND;
+
+ /* allocate shared memory for the BD ring and divide the same in to
+ several descriptors */
+ card->txbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
+ MWIFIEX_MAX_TXRX_BD;
+ dev_dbg(adapter->dev, "info: txbd_ring: Allocating %d bytes\n",
+ card->txbd_ring_size);
+ card->txbd_ring_vbase = kzalloc(card->txbd_ring_size, GFP_KERNEL);
+ if (!card->txbd_ring_vbase) {
+ dev_err(adapter->dev, "Unable to allocate buffer for txbd ring.\n");
+ kfree(card->txbd_ring_vbase);
+ return -1;
+ }
+ card->txbd_ring_pbase = virt_to_phys(card->txbd_ring_vbase);
+
+ dev_dbg(adapter->dev, "info: txbd_ring - base: %p, pbase: %#x:%x,"
+ "len: %x\n", card->txbd_ring_vbase,
+ (u32)card->txbd_ring_pbase,
+ (u32)((u64)card->txbd_ring_pbase >> 32),
+ card->txbd_ring_size);
+
+ for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+ card->txbd_ring[i] = (struct mwifiex_pcie_buf_desc *)
+ (card->txbd_ring_vbase +
+ (sizeof(struct mwifiex_pcie_buf_desc) * i));
+
+ /* Allocate buffer here so that firmware can DMA data from it */
+ skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
+ if (!skb) {
+ dev_err(adapter->dev, "Unable to allocate skb for TX ring.\n");
+ kfree(card->txbd_ring_vbase);
+ return -ENOMEM;
+ }
+ buf_pa = mwifiex_update_sk_buff_pa(skb);
+
+ skb_put(skb, MWIFIEX_RX_DATA_BUF_SIZE);
+ dev_dbg(adapter->dev, "info: TX ring: add new skb base: %p, "
+ "buf_base: %p, buf_pbase: %#x:%x, "
+ "buf_len: %#x\n", skb, skb->data,
+ (u32)*buf_pa, (u32)(((u64)*buf_pa >> 32)),
+ skb->len);
+
+ card->tx_buf_list[i] = skb;
+ card->txbd_ring[i]->paddr = *buf_pa;
+ card->txbd_ring[i]->len = (u16)skb->len;
+ card->txbd_ring[i]->flags = 0;
+ }
+
+ return 0;
+}
+
+static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ int i;
+
+ for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+ if (card->tx_buf_list[i])
+ dev_kfree_skb_any(card->tx_buf_list[i]);
+ card->tx_buf_list[i] = NULL;
+ card->txbd_ring[i]->paddr = 0;
+ card->txbd_ring[i]->len = 0;
+ card->txbd_ring[i]->flags = 0;
+ card->txbd_ring[i] = NULL;
+ }
+
+ kfree(card->txbd_ring_vbase);
+ card->txbd_ring_size = 0;
+ card->txbd_wrptr = 0;
+ card->txbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
+ card->txbd_ring_vbase = NULL;
+
+ return 0;
+}
+
+/*
+ * This function creates buffer descriptor ring for RX
+ */
+static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ struct sk_buff *skb;
+ int i;
+ phys_addr_t *buf_pa;
+
+ /*
+ * driver maintaines the read pointer and firmware maintaines the write
+ * pointer. The write pointer starts at 0 (zero) while the read pointer
+ * starts at zero with rollover bit set
+ */
+ card->rxbd_wrptr = 0;
+ card->rxbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND;
+
+ card->rxbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
+ MWIFIEX_MAX_TXRX_BD;
+ dev_dbg(adapter->dev, "info: rxbd_ring: Allocating %d bytes\n",
+ card->rxbd_ring_size);
+ card->rxbd_ring_vbase = kzalloc(card->rxbd_ring_size, GFP_KERNEL);
+ if (!card->rxbd_ring_vbase) {
+ dev_err(adapter->dev, "Unable to allocate buffer for "
+ "rxbd_ring.\n");
+ return -1;
+ }
+ card->rxbd_ring_pbase = virt_to_phys(card->rxbd_ring_vbase);
+
+ dev_dbg(adapter->dev, "info: rxbd_ring - base: %p, pbase: %#x:%x,"
+ "len: %#x\n", card->rxbd_ring_vbase,
+ (u32)card->rxbd_ring_pbase,
+ (u32)((u64)card->rxbd_ring_pbase >> 32),
+ card->rxbd_ring_size);
+
+ for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+ card->rxbd_ring[i] = (struct mwifiex_pcie_buf_desc *)
+ (card->rxbd_ring_vbase +
+ (sizeof(struct mwifiex_pcie_buf_desc) * i));
+
+ /* Allocate skb here so that firmware can DMA data from it */
+ skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
+ if (!skb) {
+ dev_err(adapter->dev, "Unable to allocate skb for RX ring.\n");
+ kfree(card->rxbd_ring_vbase);
+ return -ENOMEM;
+ }
+ buf_pa = mwifiex_update_sk_buff_pa(skb);
+ skb_put(skb, MWIFIEX_RX_DATA_BUF_SIZE);
+
+ dev_dbg(adapter->dev, "info: RX ring: add new skb base: %p, "
+ "buf_base: %p, buf_pbase: %#x:%x, "
+ "buf_len: %#x\n", skb, skb->data,
+ (u32)*buf_pa, (u32)((u64)*buf_pa >> 32),
+ skb->len);
+
+ card->rx_buf_list[i] = skb;
+ card->rxbd_ring[i]->paddr = *buf_pa;
+ card->rxbd_ring[i]->len = (u16)skb->len;
+ card->rxbd_ring[i]->flags = 0;
+ }
+
+ return 0;
+}
+
+/*
+ * This function deletes Buffer descriptor ring for RX
+ */
+static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ int i;
+
+ for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+ if (card->rx_buf_list[i])
+ dev_kfree_skb_any(card->rx_buf_list[i]);
+ card->rx_buf_list[i] = NULL;
+ card->rxbd_ring[i]->paddr = 0;
+ card->rxbd_ring[i]->len = 0;
+ card->rxbd_ring[i]->flags = 0;
+ card->rxbd_ring[i] = NULL;
+ }
+
+ kfree(card->rxbd_ring_vbase);
+ card->rxbd_ring_size = 0;
+ card->rxbd_wrptr = 0;
+ card->rxbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
+ card->rxbd_ring_vbase = NULL;
+
+ return 0;
+}
+
+/*
+ * This function creates buffer descriptor ring for Events
+ */
+static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ struct sk_buff *skb;
+ int i;
+ phys_addr_t *buf_pa;
+
+ /*
+ * driver maintaines the read pointer and firmware maintaines the write
+ * pointer. The write pointer starts at 0 (zero) while the read pointer
+ * starts at zero with rollover bit set
+ */
+ card->evtbd_wrptr = 0;
+ card->evtbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND;
+
+ card->evtbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
+ MWIFIEX_MAX_EVT_BD;
+ dev_dbg(adapter->dev, "info: evtbd_ring: Allocating %d bytes\n",
+ card->evtbd_ring_size);
+ card->evtbd_ring_vbase = kzalloc(card->evtbd_ring_size, GFP_KERNEL);
+ if (!card->evtbd_ring_vbase) {
+ dev_err(adapter->dev, "Unable to allocate buffer. "
+ "Terminating download\n");
+ return -1;
+ }
+ card->evtbd_ring_pbase = virt_to_phys(card->evtbd_ring_vbase);
+
+ dev_dbg(adapter->dev, "info: CMDRSP/EVT bd_ring - base: %p, "
+ "pbase: %#x:%x, len: %#x\n", card->evtbd_ring_vbase,
+ (u32)card->evtbd_ring_pbase,
+ (u32)((u64)card->evtbd_ring_pbase >> 32),
+ card->evtbd_ring_size);
+
+ for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
+ card->evtbd_ring[i] = (struct mwifiex_pcie_buf_desc *)
+ (card->evtbd_ring_vbase +
+ (sizeof(struct mwifiex_pcie_buf_desc) * i));
+
+ /* Allocate skb here so that firmware can DMA data from it */
+ skb = dev_alloc_skb(MAX_EVENT_SIZE);
+ if (!skb) {
+ dev_err(adapter->dev, "Unable to allocate skb for EVENT buf.\n");
+ kfree(card->evtbd_ring_vbase);
+ return -ENOMEM;
+ }
+ buf_pa = mwifiex_update_sk_buff_pa(skb);
+ skb_put(skb, MAX_EVENT_SIZE);
+
+ dev_dbg(adapter->dev, "info: Evt ring: add new skb. base: %p, "
+ "buf_base: %p, buf_pbase: %#x:%x, "
+ "buf_len: %#x\n", skb, skb->data,
+ (u32)*buf_pa, (u32)((u64)*buf_pa >> 32),
+ skb->len);
+
+ card->evt_buf_list[i] = skb;
+ card->evtbd_ring[i]->paddr = *buf_pa;
+ card->evtbd_ring[i]->len = (u16)skb->len;
+ card->evtbd_ring[i]->flags = 0;
+ }
+
+ return 0;
+}
+
+/*
+ * This function deletes Buffer descriptor ring for Events
+ */
+static int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ int i;
+
+ for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
+ if (card->evt_buf_list[i])
+ dev_kfree_skb_any(card->evt_buf_list[i]);
+ card->evt_buf_list[i] = NULL;
+ card->evtbd_ring[i]->paddr = 0;
+ card->evtbd_ring[i]->len = 0;
+ card->evtbd_ring[i]->flags = 0;
+ card->evtbd_ring[i] = NULL;
+ }
+
+ kfree(card->evtbd_ring_vbase);
+ card->evtbd_wrptr = 0;
+ card->evtbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
+ card->evtbd_ring_size = 0;
+ card->evtbd_ring_vbase = NULL;
+
+ return 0;
+}
+
+/*
+ * This function allocates a buffer for CMDRSP
+ */
+static int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ struct sk_buff *skb;
+
+ /* Allocate memory for receiving command response data */
+ skb = dev_alloc_skb(MWIFIEX_UPLD_SIZE);
+ if (!skb) {
+ dev_err(adapter->dev, "Unable to allocate skb for command "
+ "response data.\n");
+ return -ENOMEM;
+ }
+ mwifiex_update_sk_buff_pa(skb);
+ skb_put(skb, MWIFIEX_UPLD_SIZE);
+ card->cmdrsp_buf = skb;
+
+ skb = NULL;
+ /* Allocate memory for sending command to firmware */
+ skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER);
+ if (!skb) {
+ dev_err(adapter->dev, "Unable to allocate skb for command "
+ "data.\n");
+ return -ENOMEM;
+ }
+ mwifiex_update_sk_buff_pa(skb);
+ skb_put(skb, MWIFIEX_SIZE_OF_CMD_BUFFER);
+ card->cmd_buf = skb;
+
+ return 0;
+}
+
+/*
+ * This function deletes a buffer for CMDRSP
+ */
+static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card;
+
+ if (!adapter)
+ return 0;
+
+ card = adapter->card;
+
+ if (card && card->cmdrsp_buf)
+ dev_kfree_skb_any(card->cmdrsp_buf);
+
+ if (card && card->cmd_buf)
+ dev_kfree_skb_any(card->cmd_buf);
+
+ return 0;
+}
+
+/*
+ * This function allocates a buffer for sleep cookie
+ */
+static int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter)
+{
+ struct sk_buff *skb;
+ struct pcie_service_card *card = adapter->card;
+
+ /* Allocate memory for sleep cookie */
+ skb = dev_alloc_skb(sizeof(u32));
+ if (!skb) {
+ dev_err(adapter->dev, "Unable to allocate skb for sleep "
+ "cookie!\n");
+ return -ENOMEM;
+ }
+ mwifiex_update_sk_buff_pa(skb);
+ skb_put(skb, sizeof(u32));
+
+ /* Init val of Sleep Cookie */
+ *(u32 *)skb->data = FW_AWAKE_COOKIE;
+
+ dev_dbg(adapter->dev, "alloc_scook: sleep cookie=0x%x\n",
+ *((u32 *)skb->data));
+
+ /* Save the sleep cookie */
+ card->sleep_cookie = skb;
+
+ return 0;
+}
+
+/*
+ * This function deletes buffer for sleep cookie
+ */
+static int mwifiex_pcie_delete_sleep_cookie_buf(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card;
+
+ if (!adapter)
+ return 0;
+
+ card = adapter->card;
+
+ if (card && card->sleep_cookie) {
+ dev_kfree_skb_any(card->sleep_cookie);
+ card->sleep_cookie = NULL;
+ }
+
+ return 0;
+}
+
+/*
+ * This function sends data buffer to device
+ */
+static int
+mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb)
+{
+ struct pcie_service_card *card = adapter->card;
+ u32 wrindx, rdptr;
+ phys_addr_t *buf_pa;
+ __le16 *tmp;
+
+ if (!mwifiex_pcie_ok_to_access_hw(adapter))
+ mwifiex_pm_wakeup_card(adapter);
+
+ /* Read the TX ring read pointer set by firmware */
+ if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) {
+ dev_err(adapter->dev, "SEND DATA: failed to read "
+ "REG_TXBD_RDPTR\n");
+ return -1;
+ }
+
+ wrindx = card->txbd_wrptr & MWIFIEX_TXBD_MASK;
+
+ dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n", rdptr,
+ card->txbd_wrptr);
+ if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) !=
+ (rdptr & MWIFIEX_TXBD_MASK)) ||
+ ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) !=
+ (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
+ struct sk_buff *skb_data;
+ u8 *payload;
+
+ adapter->data_sent = true;
+ skb_data = card->tx_buf_list[wrindx];
+ memcpy(skb_data->data, skb->data, skb->len);
+ payload = skb_data->data;
+ tmp = (__le16 *)&payload[0];
+ *tmp = cpu_to_le16((u16)skb->len);
+ tmp = (__le16 *)&payload[2];
+ *tmp = cpu_to_le16(MWIFIEX_TYPE_DATA);
+ skb_put(skb_data, MWIFIEX_RX_DATA_BUF_SIZE - skb_data->len);
+ skb_trim(skb_data, skb->len);
+ buf_pa = MWIFIEX_SKB_PACB(skb_data);
+ card->txbd_ring[wrindx]->paddr = *buf_pa;
+ card->txbd_ring[wrindx]->len = (u16)skb_data->len;
+ card->txbd_ring[wrindx]->flags = MWIFIEX_BD_FLAG_FIRST_DESC |
+ MWIFIEX_BD_FLAG_LAST_DESC;
+
+ if ((++card->txbd_wrptr & MWIFIEX_TXBD_MASK) ==
+ MWIFIEX_MAX_TXRX_BD)
+ card->txbd_wrptr = ((card->txbd_wrptr &
+ MWIFIEX_BD_FLAG_ROLLOVER_IND) ^
+ MWIFIEX_BD_FLAG_ROLLOVER_IND);
+
+ /* Write the TX ring write pointer in to REG_TXBD_WRPTR */
+ if (mwifiex_write_reg(adapter, REG_TXBD_WRPTR,
+ card->txbd_wrptr)) {
+ dev_err(adapter->dev, "SEND DATA: failed to write "
+ "REG_TXBD_WRPTR\n");
+ return 0;
+ }
+
+ /* Send the TX ready interrupt */
+ if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
+ CPU_INTR_DNLD_RDY)) {
+ dev_err(adapter->dev, "SEND DATA: failed to assert "
+ "door-bell interrupt.\n");
+ return -1;
+ }
+ dev_dbg(adapter->dev, "info: SEND DATA: Updated <Rd: %#x, Wr: "
+ "%#x> and sent packet to firmware "
+ "successfully\n", rdptr,
+ card->txbd_wrptr);
+ } else {
+ dev_dbg(adapter->dev, "info: TX Ring full, can't send anymore "
+ "packets to firmware\n");
+ adapter->data_sent = true;
+ /* Send the TX ready interrupt */
+ if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
+ CPU_INTR_DNLD_RDY))
+ dev_err(adapter->dev, "SEND DATA: failed to assert "
+ "door-bell interrupt\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+/*
+ * This function handles received buffer ring and
+ * dispatches packets to upper
+ */
+static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ u32 wrptr, rd_index;
+ int ret = 0;
+ struct sk_buff *skb_tmp = NULL;
+
+ /* Read the RX ring Write pointer set by firmware */
+ if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) {
+ dev_err(adapter->dev, "RECV DATA: failed to read "
+ "REG_TXBD_RDPTR\n");
+ ret = -1;
+ goto done;
+ }
+
+ while (((wrptr & MWIFIEX_RXBD_MASK) !=
+ (card->rxbd_rdptr & MWIFIEX_RXBD_MASK)) ||
+ ((wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) ==
+ (card->rxbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
+ struct sk_buff *skb_data;
+ u16 rx_len;
+
+ rd_index = card->rxbd_rdptr & MWIFIEX_RXBD_MASK;
+ skb_data = card->rx_buf_list[rd_index];
+
+ /* Get data length from interface header -
+ first byte is len, second byte is type */
+ rx_len = *((u16 *)skb_data->data);
+ dev_dbg(adapter->dev, "info: RECV DATA: Rd=%#x, Wr=%#x, "
+ "Len=%d\n", card->rxbd_rdptr, wrptr, rx_len);
+ skb_tmp = dev_alloc_skb(rx_len);
+ if (!skb_tmp) {
+ dev_dbg(adapter->dev, "info: Failed to alloc skb "
+ "for RX\n");
+ ret = -EBUSY;
+ goto done;
+ }
+
+ skb_put(skb_tmp, rx_len);
+
+ memcpy(skb_tmp->data, skb_data->data + INTF_HEADER_LEN, rx_len);
+ if ((++card->rxbd_rdptr & MWIFIEX_RXBD_MASK) ==
+ MWIFIEX_MAX_TXRX_BD) {
+ card->rxbd_rdptr = ((card->rxbd_rdptr &
+ MWIFIEX_BD_FLAG_ROLLOVER_IND) ^
+ MWIFIEX_BD_FLAG_ROLLOVER_IND);
+ }
+ dev_dbg(adapter->dev, "info: RECV DATA: <Rd: %#x, Wr: %#x>\n",
+ card->rxbd_rdptr, wrptr);
+
+ /* Write the RX ring read pointer in to REG_RXBD_RDPTR */
+ if (mwifiex_write_reg(adapter, REG_RXBD_RDPTR,
+ card->rxbd_rdptr)) {
+ dev_err(adapter->dev, "RECV DATA: failed to "
+ "write REG_RXBD_RDPTR\n");
+ ret = -1;
+ goto done;
+ }
+
+ /* Read the RX ring Write pointer set by firmware */
+ if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) {
+ dev_err(adapter->dev, "RECV DATA: failed to read "
+ "REG_TXBD_RDPTR\n");
+ ret = -1;
+ goto done;
+ }
+ dev_dbg(adapter->dev, "info: RECV DATA: Received packet from "
+ "firmware successfully\n");
+ mwifiex_handle_rx_packet(adapter, skb_tmp);
+ }
+
+done:
+ if (ret && skb_tmp)
+ dev_kfree_skb_any(skb_tmp);
+ return ret;
+}
+
+/*
+ * This function downloads the boot command to device
+ */
+static int
+mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
+{
+ phys_addr_t *buf_pa = MWIFIEX_SKB_PACB(skb);
+
+ if (!(skb->data && skb->len && *buf_pa)) {
+ dev_err(adapter->dev, "Invalid parameter in %s <%p, %#x:%x, "
+ "%x>\n", __func__, skb->data, skb->len,
+ (u32)*buf_pa, (u32)((u64)*buf_pa >> 32));
+ return -1;
+ }
+
+ /* Write the lower 32bits of the physical address to scratch
+ * register 0 */
+ if (mwifiex_write_reg(adapter, PCIE_SCRATCH_0_REG, (u32)*buf_pa)) {
+ dev_err(adapter->dev, "%s: failed to write download command "
+ "to boot code.\n", __func__);
+ return -1;
+ }
+
+ /* Write the upper 32bits of the physical address to scratch
+ * register 1 */
+ if (mwifiex_write_reg(adapter, PCIE_SCRATCH_1_REG,
+ (u32)((u64)*buf_pa >> 32))) {
+ dev_err(adapter->dev, "%s: failed to write download command "
+ "to boot code.\n", __func__);
+ return -1;
+ }
+
+ /* Write the command length to scratch register 2 */
+ if (mwifiex_write_reg(adapter, PCIE_SCRATCH_2_REG, skb->len)) {
+ dev_err(adapter->dev, "%s: failed to write command length to "
+ "scratch register 2\n", __func__);
+ return -1;
+ }
+
+ /* Ring the door bell */
+ if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
+ CPU_INTR_DOOR_BELL)) {
+ dev_err(adapter->dev, "%s: failed to assert door-bell "
+ "interrupt.\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * This function downloads commands to the device
+ */
+static int
+mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
+{
+ struct pcie_service_card *card = adapter->card;
+ int ret = 0;
+ phys_addr_t *cmd_buf_pa;
+ phys_addr_t *cmdrsp_buf_pa;
+
+ if (!(skb->data && skb->len)) {
+ dev_err(adapter->dev, "Invalid parameter in %s <%p, %#x>\n",
+ __func__, skb->data, skb->len);
+ return -1;
+ }
+
+ /* Make sure a command response buffer is available */
+ if (!card->cmdrsp_buf) {
+ dev_err(adapter->dev, "No response buffer available, send "
+ "command failed\n");
+ return -EBUSY;
+ }
+
+ /* Make sure a command buffer is available */
+ if (!card->cmd_buf) {
+ dev_err(adapter->dev, "Command buffer not available\n");
+ return -EBUSY;
+ }
+
+ adapter->cmd_sent = true;
+ /* Copy the given skb in to DMA accessable shared buffer */
+ skb_put(card->cmd_buf, MWIFIEX_SIZE_OF_CMD_BUFFER - card->cmd_buf->len);
+ skb_trim(card->cmd_buf, skb->len);
+ memcpy(card->cmd_buf->data, skb->data, skb->len);
+
+ /* To send a command, the driver will:
+ 1. Write the 64bit physical address of the data buffer to
+ SCRATCH1 + SCRATCH0
+ 2. Ring the door bell (i.e. set the door bell interrupt)
+
+ In response to door bell interrupt, the firmware will perform
+ the DMA of the command packet (first header to obtain the total
+ length and then rest of the command).
+ */
+
+ if (card->cmdrsp_buf) {
+ cmdrsp_buf_pa = MWIFIEX_SKB_PACB(card->cmdrsp_buf);
+ /* Write the lower 32bits of the cmdrsp buffer physical
+ address */
+ if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO,
+ (u32)*cmdrsp_buf_pa)) {
+ dev_err(adapter->dev, "Failed to write download command to boot code.\n");
+ ret = -1;
+ goto done;
+ }
+ /* Write the upper 32bits of the cmdrsp buffer physical
+ address */
+ if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI,
+ (u32)((u64)*cmdrsp_buf_pa >> 32))) {
+ dev_err(adapter->dev, "Failed to write download command"
+ " to boot code.\n");
+ ret = -1;
+ goto done;
+ }
+ }
+
+ cmd_buf_pa = MWIFIEX_SKB_PACB(card->cmd_buf);
+ /* Write the lower 32bits of the physical address to REG_CMD_ADDR_LO */
+ if (mwifiex_write_reg(adapter, REG_CMD_ADDR_LO,
+ (u32)*cmd_buf_pa)) {
+ dev_err(adapter->dev, "Failed to write download command "
+ "to boot code.\n");
+ ret = -1;
+ goto done;
+ }
+ /* Write the upper 32bits of the physical address to REG_CMD_ADDR_HI */
+ if (mwifiex_write_reg(adapter, REG_CMD_ADDR_HI,
+ (u32)((u64)*cmd_buf_pa >> 32))) {
+ dev_err(adapter->dev, "Failed to write download command "
+ "to boot code.\n");
+ ret = -1;
+ goto done;
+ }
+
+ /* Write the command length to REG_CMD_SIZE */
+ if (mwifiex_write_reg(adapter, REG_CMD_SIZE,
+ card->cmd_buf->len)) {
+ dev_err(adapter->dev, "Failed to write command length to "
+ "REG_CMD_SIZE\n");
+ ret = -1;
+ goto done;
+ }
+
+ /* Ring the door bell */
+ if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
+ CPU_INTR_DOOR_BELL)) {
+ dev_err(adapter->dev, "Failed to assert door-bell "
+ "interrupt.\n");
+ ret = -1;
+ goto done;
+ }
+
+done:
+ if (ret)
+ adapter->cmd_sent = false;
+
+ return 0;
+}
+
+/*
+ * This function handles command complete interrupt
+ */
+static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ int count = 0;
+
+ dev_dbg(adapter->dev, "info: Rx CMD Response\n");
+
+ if (!adapter->curr_cmd) {
+ skb_pull(card->cmdrsp_buf, INTF_HEADER_LEN);
+ if (adapter->ps_state == PS_STATE_SLEEP_CFM) {
+ mwifiex_process_sleep_confirm_resp(adapter,
+ card->cmdrsp_buf->data,
+ card->cmdrsp_buf->len);
+ while (mwifiex_pcie_ok_to_access_hw(adapter) &&
+ (count++ < 10))
+ udelay(50);
+ } else {
+ dev_err(adapter->dev, "There is no command but "
+ "got cmdrsp\n");
+ }
+ memcpy(adapter->upld_buf, card->cmdrsp_buf->data,
+ min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER,
+ card->cmdrsp_buf->len));
+ skb_push(card->cmdrsp_buf, INTF_HEADER_LEN);
+ } else if (mwifiex_pcie_ok_to_access_hw(adapter)) {
+ skb_pull(card->cmdrsp_buf, INTF_HEADER_LEN);
+ adapter->curr_cmd->resp_skb = card->cmdrsp_buf;
+ adapter->cmd_resp_received = true;
+ /* Take the pointer and set it to CMD node and will
+ return in the response complete callback */
+ card->cmdrsp_buf = NULL;
+
+ /* Clear the cmd-rsp buffer address in scratch registers. This
+ will prevent firmware from writing to the same response
+ buffer again. */
+ if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO, 0)) {
+ dev_err(adapter->dev, "cmd_done: failed to clear "
+ "cmd_rsp address.\n");
+ return -1;
+ }
+ /* Write the upper 32bits of the cmdrsp buffer physical
+ address */
+ if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI, 0)) {
+ dev_err(adapter->dev, "cmd_done: failed to clear "
+ "cmd_rsp address.\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Command Response processing complete handler
+ */
+static int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb)
+{
+ struct pcie_service_card *card = adapter->card;
+
+ if (skb) {
+ card->cmdrsp_buf = skb;
+ skb_push(card->cmdrsp_buf, INTF_HEADER_LEN);
+ }
+
+ return 0;
+}
+
+/*
+ * This function handles firmware event ready interrupt
+ */
+static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
+ u32 wrptr, event;
+
+ if (adapter->event_received) {
+ dev_dbg(adapter->dev, "info: Event being processed, "\
+ "do not process this interrupt just yet\n");
+ return 0;
+ }
+
+ if (rdptr >= MWIFIEX_MAX_EVT_BD) {
+ dev_dbg(adapter->dev, "info: Invalid read pointer...\n");
+ return -1;
+ }
+
+ /* Read the event ring write pointer set by firmware */
+ if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) {
+ dev_err(adapter->dev, "EventReady: failed to read REG_EVTBD_WRPTR\n");
+ return -1;
+ }
+
+ dev_dbg(adapter->dev, "info: EventReady: Initial <Rd: 0x%x, Wr: 0x%x>",
+ card->evtbd_rdptr, wrptr);
+ if (((wrptr & MWIFIEX_EVTBD_MASK) !=
+ (card->evtbd_rdptr & MWIFIEX_EVTBD_MASK)) ||
+ ((wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) ==
+ (card->evtbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
+ struct sk_buff *skb_cmd;
+ __le16 data_len = 0;
+ u16 evt_len;
+
+ dev_dbg(adapter->dev, "info: Read Index: %d\n", rdptr);
+ skb_cmd = card->evt_buf_list[rdptr];
+ /* Take the pointer and set it to event pointer in adapter
+ and will return back after event handling callback */
+ card->evt_buf_list[rdptr] = NULL;
+ card->evtbd_ring[rdptr]->paddr = 0;
+ card->evtbd_ring[rdptr]->len = 0;
+ card->evtbd_ring[rdptr]->flags = 0;
+
+ event = *(u32 *) &skb_cmd->data[INTF_HEADER_LEN];
+ adapter->event_cause = event;
+ /* The first 4bytes will be the event transfer header
+ len is 2 bytes followed by type which is 2 bytes */
+ memcpy(&data_len, skb_cmd->data, sizeof(__le16));
+ evt_len = le16_to_cpu(data_len);
+
+ skb_pull(skb_cmd, INTF_HEADER_LEN);
+ dev_dbg(adapter->dev, "info: Event length: %d\n", evt_len);
+
+ if ((evt_len > 0) && (evt_len < MAX_EVENT_SIZE))
+ memcpy(adapter->event_body, skb_cmd->data +
+ MWIFIEX_EVENT_HEADER_LEN, evt_len -
+ MWIFIEX_EVENT_HEADER_LEN);
+
+ adapter->event_received = true;
+ adapter->event_skb = skb_cmd;
+
+ /* Do not update the event read pointer here, wait till the
+ buffer is released. This is just to make things simpler,
+ we need to find a better method of managing these buffers.
+ */
+ }
+
+ return 0;
+}
+
+/*
+ * Event processing complete handler
+ */
+static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb)
+{
+ struct pcie_service_card *card = adapter->card;
+ int ret = 0;
+ u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
+ u32 wrptr;
+ phys_addr_t *buf_pa;
+
+ if (!skb)
+ return 0;
+
+ if (rdptr >= MWIFIEX_MAX_EVT_BD)
+ dev_err(adapter->dev, "event_complete: Invalid rdptr 0x%x\n",
+ rdptr);
+
+ /* Read the event ring write pointer set by firmware */
+ if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) {
+ dev_err(adapter->dev, "event_complete: failed to read REG_EVTBD_WRPTR\n");
+ ret = -1;
+ goto done;
+ }
+
+ if (!card->evt_buf_list[rdptr]) {
+ skb_push(skb, INTF_HEADER_LEN);
+ card->evt_buf_list[rdptr] = skb;
+ buf_pa = MWIFIEX_SKB_PACB(skb);
+ card->evtbd_ring[rdptr]->paddr = *buf_pa;
+ card->evtbd_ring[rdptr]->len = (u16)skb->len;
+ card->evtbd_ring[rdptr]->flags = 0;
+ skb = NULL;
+ } else {
+ dev_dbg(adapter->dev, "info: ERROR: Buffer is still valid at "
+ "index %d, <%p, %p>\n", rdptr,
+ card->evt_buf_list[rdptr], skb);
+ }
+
+ if ((++card->evtbd_rdptr & MWIFIEX_EVTBD_MASK) == MWIFIEX_MAX_EVT_BD) {
+ card->evtbd_rdptr = ((card->evtbd_rdptr &
+ MWIFIEX_BD_FLAG_ROLLOVER_IND) ^
+ MWIFIEX_BD_FLAG_ROLLOVER_IND);
+ }
+
+ dev_dbg(adapter->dev, "info: Updated <Rd: 0x%x, Wr: 0x%x>",
+ card->evtbd_rdptr, wrptr);
+
+ /* Write the event ring read pointer in to REG_EVTBD_RDPTR */
+ if (mwifiex_write_reg(adapter, REG_EVTBD_RDPTR, card->evtbd_rdptr)) {
+ dev_err(adapter->dev, "event_complete: failed to read REG_EVTBD_RDPTR\n");
+ ret = -1;
+ goto done;
+ }
+
+done:
+ /* Free the buffer for failure case */
+ if (ret && skb)
+ dev_kfree_skb_any(skb);
+
+ dev_dbg(adapter->dev, "info: Check Events Again\n");
+ ret = mwifiex_pcie_process_event_ready(adapter);
+
+ return ret;
+}
+
+/*
+ * This function downloads the firmware to the card.
+ *
+ * Firmware is downloaded to the card in blocks. Every block download
+ * is tested for CRC errors, and retried a number of times before
+ * returning failure.
+ */
+static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
+ struct mwifiex_fw_image *fw)
+{
+ int ret;
+ u8 *firmware = fw->fw_buf;
+ u32 firmware_len = fw->fw_len;
+ u32 offset = 0;
+ struct sk_buff *skb;
+ u32 txlen, tx_blocks = 0, tries, len;
+ u32 block_retry_cnt = 0;
+
+ if (!adapter) {
+ pr_err("adapter structure is not valid\n");
+ return -1;
+ }
+
+ if (!firmware || !firmware_len) {
+ dev_err(adapter->dev, "No firmware image found! "
+ "Terminating download\n");
+ return -1;
+ }
+
+ dev_dbg(adapter->dev, "info: Downloading FW image (%d bytes)\n",
+ firmware_len);
+
+ if (mwifiex_pcie_disable_host_int(adapter)) {
+ dev_err(adapter->dev, "%s: Disabling interrupts"
+ " failed.\n", __func__);
+ return -1;
+ }
+
+ skb = dev_alloc_skb(MWIFIEX_UPLD_SIZE);
+ if (!skb) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ mwifiex_update_sk_buff_pa(skb);
+
+ /* Perform firmware data transfer */
+ do {
+ u32 ireg_intr = 0;
+
+ /* More data? */
+ if (offset >= firmware_len)
+ break;
+
+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+ ret = mwifiex_read_reg(adapter, PCIE_SCRATCH_2_REG,
+ &len);
+ if (ret) {
+ dev_warn(adapter->dev, "Failed reading length from boot code\n");
+ goto done;
+ }
+ if (len)
+ break;
+ udelay(10);
+ }
+
+ if (!len) {
+ break;
+ } else if (len > MWIFIEX_UPLD_SIZE) {
+ pr_err("FW download failure @ %d, invalid length %d\n",
+ offset, len);
+ ret = -1;
+ goto done;
+ }
+
+ txlen = len;
+
+ if (len & BIT(0)) {
+ block_retry_cnt++;
+ if (block_retry_cnt > MAX_WRITE_IOMEM_RETRY) {
+ pr_err("FW download failure @ %d, over max "
+ "retry count\n", offset);
+ ret = -1;
+ goto done;
+ }
+ dev_err(adapter->dev, "FW CRC error indicated by the "
+ "helper: len = 0x%04X, txlen = "
+ "%d\n", len, txlen);
+ len &= ~BIT(0);
+ /* Setting this to 0 to resend from same offset */
+ txlen = 0;
+ } else {
+ block_retry_cnt = 0;
+ /* Set blocksize to transfer - checking for
+ last block */
+ if (firmware_len - offset < txlen)
+ txlen = firmware_len - offset;
+
+ dev_dbg(adapter->dev, ".");
+
+ tx_blocks =
+ (txlen + MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD - 1) /
+ MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD;
+
+ /* Copy payload to buffer */
+ memmove(skb->data, &firmware[offset], txlen);
+ }
+
+ skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len);
+ skb_trim(skb, tx_blocks * MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD);
+
+ /* Send the boot command to device */
+ if (mwifiex_pcie_send_boot_cmd(adapter, skb)) {
+ dev_err(adapter->dev, "Failed to send firmware download command\n");
+ ret = -1;
+ goto done;
+ }
+ /* Wait for the command done interrupt */
+ do {
+ if (mwifiex_read_reg(adapter, PCIE_CPU_INT_STATUS,
+ &ireg_intr)) {
+ dev_err(adapter->dev, "%s: Failed to read "
+ "interrupt status during "
+ "fw dnld.\n", __func__);
+ ret = -1;
+ goto done;
+ }
+ } while ((ireg_intr & CPU_INTR_DOOR_BELL) ==
+ CPU_INTR_DOOR_BELL);
+ offset += txlen;
+ } while (true);
+
+ dev_dbg(adapter->dev, "info:\nFW download over, size %d bytes\n",
+ offset);
+
+ ret = 0;
+
+done:
+ dev_kfree_skb_any(skb);
+ return ret;
+}
+
+/*
+ * This function checks the firmware status in card.
+ *
+ * The winner interface is also determined by this function.
+ */
+static int
+mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
+{
+ int ret = 0;
+ u32 firmware_stat, winner_status;
+ u32 tries;
+
+ /* Mask spurios interrupts */
+ if (mwifiex_write_reg(adapter, PCIE_HOST_INT_STATUS_MASK,
+ HOST_INTR_MASK)) {
+ dev_warn(adapter->dev, "Write register failed\n");
+ return -1;
+ }
+
+ dev_dbg(adapter->dev, "Setting driver ready signature\n");
+ if (mwifiex_write_reg(adapter, REG_DRV_READY, FIRMWARE_READY_PCIE)) {
+ dev_err(adapter->dev, "Failed to write driver ready signature\n");
+ return -1;
+ }
+
+ /* Wait for firmware initialization event */
+ for (tries = 0; tries < poll_num; tries++) {
+ if (mwifiex_read_reg(adapter, PCIE_SCRATCH_3_REG,
+ &firmware_stat))
+ ret = -1;
+ else
+ ret = 0;
+ if (ret)
+ continue;
+ if (firmware_stat == FIRMWARE_READY_PCIE) {
+ ret = 0;
+ break;
+ } else {
+ mdelay(100);
+ ret = -1;
+ }
+ }
+
+ if (ret) {
+ if (mwifiex_read_reg(adapter, PCIE_SCRATCH_3_REG,
+ &winner_status))
+ ret = -1;
+ else if (!winner_status) {
+ dev_err(adapter->dev, "PCI-E is the winner\n");
+ adapter->winner = 1;
+ ret = -1;
+ } else {
+ dev_err(adapter->dev, "PCI-E is not the winner <%#x, %d>, exit download\n",
+ ret, adapter->winner);
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * This function reads the interrupt status from card.
+ */
+static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
+{
+ u32 pcie_ireg;
+ unsigned long flags;
+
+ if (!mwifiex_pcie_ok_to_access_hw(adapter))
+ return;
+
+ if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS, &pcie_ireg)) {
+ dev_warn(adapter->dev, "Read register failed\n");
+ return;
+ }
+
+ if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
+
+ mwifiex_pcie_disable_host_int(adapter);
+
+ /* Clear the pending interrupts */
+ if (mwifiex_write_reg(adapter, PCIE_HOST_INT_STATUS,
+ ~pcie_ireg)) {
+ dev_warn(adapter->dev, "Write register failed\n");
+ return;
+ }
+ spin_lock_irqsave(&adapter->int_lock, flags);
+ adapter->int_status |= pcie_ireg;
+ spin_unlock_irqrestore(&adapter->int_lock, flags);
+
+ if (pcie_ireg & HOST_INTR_CMD_DONE) {
+ if ((adapter->ps_state == PS_STATE_SLEEP_CFM) ||
+ (adapter->ps_state == PS_STATE_SLEEP)) {
+ mwifiex_pcie_enable_host_int(adapter);
+ if (mwifiex_write_reg(adapter,
+ PCIE_CPU_INT_EVENT,
+ CPU_INTR_SLEEP_CFM_DONE)) {
+ dev_warn(adapter->dev, "Write register"
+ " failed\n");
+ return;
+
+ }
+ }
+ } else if (!adapter->pps_uapsd_mode &&
+ adapter->ps_state == PS_STATE_SLEEP) {
+ /* Potentially for PCIe we could get other
+ * interrupts like shared. Don't change power
+ * state until cookie is set */
+ if (mwifiex_pcie_ok_to_access_hw(adapter))
+ adapter->ps_state = PS_STATE_AWAKE;
+ }
+ }
+}
+
+/*
+ * Interrupt handler for PCIe root port
+ *
+ * This function reads the interrupt status from firmware and assigns
+ * the main process in workqueue which will handle the interrupt.
+ */
+static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context)
+{
+ struct pci_dev *pdev = (struct pci_dev *)context;
+ struct pcie_service_card *card;
+ struct mwifiex_adapter *adapter;
+
+ if (!pdev) {
+ pr_debug("info: %s: pdev is NULL\n", (u8 *)pdev);
+ goto exit;
+ }
+
+ card = (struct pcie_service_card *) pci_get_drvdata(pdev);
+ if (!card || !card->adapter) {
+ pr_debug("info: %s: card=%p adapter=%p\n", __func__, card,
+ card ? card->adapter : NULL);
+ goto exit;
+ }
+ adapter = card->adapter;
+
+ if (adapter->surprise_removed)
+ goto exit;
+
+ mwifiex_interrupt_status(adapter);
+ queue_work(adapter->workqueue, &adapter->main_work);
+
+exit:
+ return IRQ_HANDLED;
+}
+
+/*
+ * This function checks the current interrupt status.
+ *
+ * The following interrupts are checked and handled by this function -
+ * - Data sent
+ * - Command sent
+ * - Command received
+ * - Packets received
+ * - Events received
+ *
+ * In case of Rx packets received, the packets are uploaded from card to
+ * host and processed accordingly.
+ */
+static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
+{
+ int ret;
+ u32 pcie_ireg = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->int_lock, flags);
+ /* Clear out unused interrupts */
+ adapter->int_status &= HOST_INTR_MASK;
+ spin_unlock_irqrestore(&adapter->int_lock, flags);
+
+ while (adapter->int_status & HOST_INTR_MASK) {
+ if (adapter->int_status & HOST_INTR_DNLD_DONE) {
+ adapter->int_status &= ~HOST_INTR_DNLD_DONE;
+ if (adapter->data_sent) {
+ dev_dbg(adapter->dev, "info: DATA sent Interrupt\n");
+ adapter->data_sent = false;
+ }
+ }
+ if (adapter->int_status & HOST_INTR_UPLD_RDY) {
+ adapter->int_status &= ~HOST_INTR_UPLD_RDY;
+ dev_dbg(adapter->dev, "info: Rx DATA\n");
+ ret = mwifiex_pcie_process_recv_data(adapter);
+ if (ret)
+ return ret;
+ }
+ if (adapter->int_status & HOST_INTR_EVENT_RDY) {
+ adapter->int_status &= ~HOST_INTR_EVENT_RDY;
+ dev_dbg(adapter->dev, "info: Rx EVENT\n");
+ ret = mwifiex_pcie_process_event_ready(adapter);
+ if (ret)
+ return ret;
+ }
+
+ if (adapter->int_status & HOST_INTR_CMD_DONE) {
+ adapter->int_status &= ~HOST_INTR_CMD_DONE;
+ if (adapter->cmd_sent) {
+ dev_dbg(adapter->dev, "info: CMD sent Interrupt\n");
+ adapter->cmd_sent = false;
+ }
+ /* Handle command response */
+ ret = mwifiex_pcie_process_cmd_complete(adapter);
+ if (ret)
+ return ret;
+ }
+
+ if (mwifiex_pcie_ok_to_access_hw(adapter)) {
+ if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS,
+ &pcie_ireg)) {
+ dev_warn(adapter->dev, "Read register failed\n");
+ return -1;
+ }
+
+ if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
+ if (mwifiex_write_reg(adapter,
+ PCIE_HOST_INT_STATUS, ~pcie_ireg)) {
+ dev_warn(adapter->dev, "Write register"
+ " failed\n");
+ return -1;
+ }
+ adapter->int_status |= pcie_ireg;
+ adapter->int_status &= HOST_INTR_MASK;
+ }
+
+ }
+ }
+ dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n",
+ adapter->cmd_sent, adapter->data_sent);
+ mwifiex_pcie_enable_host_int(adapter);
+
+ return 0;
+}
+
+/*
+ * This function downloads data from driver to card.
+ *
+ * Both commands and data packets are transferred to the card by this
+ * function.
+ *
+ * This function adds the PCIE specific header to the front of the buffer
+ * before transferring. The header contains the length of the packet and
+ * the type. The firmware handles the packets based upon this set type.
+ */
+static int mwifiex_pcie_host_to_card(struct mwifiex_adapter *adapter, u8 type,
+ struct sk_buff *skb,
+ struct mwifiex_tx_param *tx_param)
+{
+ if (!adapter || !skb) {
+ dev_err(adapter->dev, "Invalid parameter in %s <%p, %p>\n",
+ __func__, adapter, skb);
+ return -1;
+ }
+
+ if (type == MWIFIEX_TYPE_DATA)
+ return mwifiex_pcie_send_data(adapter, skb);
+ else if (type == MWIFIEX_TYPE_CMD)
+ return mwifiex_pcie_send_cmd(adapter, skb);
+
+ return 0;
+}
+
+/*
+ * This function initializes the PCI-E host memory space, WCB rings, etc.
+ *
+ * The following initializations steps are followed -
+ * - Allocate TXBD ring buffers
+ * - Allocate RXBD ring buffers
+ * - Allocate event BD ring buffers
+ * - Allocate command response ring buffer
+ * - Allocate sleep cookie buffer
+ */
+static int mwifiex_pcie_init(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ int ret;
+ struct pci_dev *pdev = card->dev;
+
+ pci_set_drvdata(pdev, card);
+
+ ret = pci_enable_device(pdev);
+ if (ret)
+ goto err_enable_dev;
+
+ pci_set_master(pdev);
+
+ dev_dbg(adapter->dev, "try set_consistent_dma_mask(32)\n");
+ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(adapter->dev, "set_dma_mask(32) failed\n");
+ goto err_set_dma_mask;
+ }
+
+ ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(adapter->dev, "set_consistent_dma_mask(64) failed\n");
+ goto err_set_dma_mask;
+ }
+
+ ret = pci_request_region(pdev, 0, DRV_NAME);
+ if (ret) {
+ dev_err(adapter->dev, "req_reg(0) error\n");
+ goto err_req_region0;
+ }
+ card->pci_mmap = pci_iomap(pdev, 0, 0);
+ if (!card->pci_mmap) {
+ dev_err(adapter->dev, "iomap(0) error\n");
+ goto err_iomap0;
+ }
+ ret = pci_request_region(pdev, 2, DRV_NAME);
+ if (ret) {
+ dev_err(adapter->dev, "req_reg(2) error\n");
+ goto err_req_region2;
+ }
+ card->pci_mmap1 = pci_iomap(pdev, 2, 0);
+ if (!card->pci_mmap1) {
+ dev_err(adapter->dev, "iomap(2) error\n");
+ goto err_iomap2;
+ }
+
+ dev_dbg(adapter->dev, "PCI memory map Virt0: %p PCI memory map Virt2: "
+ "%p\n", card->pci_mmap, card->pci_mmap1);
+
+ card->cmdrsp_buf = NULL;
+ ret = mwifiex_pcie_create_txbd_ring(adapter);
+ if (ret)
+ goto err_cre_txbd;
+ ret = mwifiex_pcie_create_rxbd_ring(adapter);
+ if (ret)
+ goto err_cre_rxbd;
+ ret = mwifiex_pcie_create_evtbd_ring(adapter);
+ if (ret)
+ goto err_cre_evtbd;
+ ret = mwifiex_pcie_alloc_cmdrsp_buf(adapter);
+ if (ret)
+ goto err_alloc_cmdbuf;
+ ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter);
+ if (ret)
+ goto err_alloc_cookie;
+
+ return ret;
+
+err_alloc_cookie:
+ mwifiex_pcie_delete_cmdrsp_buf(adapter);
+err_alloc_cmdbuf:
+ mwifiex_pcie_delete_evtbd_ring(adapter);
+err_cre_evtbd:
+ mwifiex_pcie_delete_rxbd_ring(adapter);
+err_cre_rxbd:
+ mwifiex_pcie_delete_txbd_ring(adapter);
+err_cre_txbd:
+ pci_iounmap(pdev, card->pci_mmap1);
+err_iomap2:
+ pci_release_region(pdev, 2);
+err_req_region2:
+ pci_iounmap(pdev, card->pci_mmap);
+err_iomap0:
+ pci_release_region(pdev, 0);
+err_req_region0:
+err_set_dma_mask:
+ pci_disable_device(pdev);
+err_enable_dev:
+ pci_set_drvdata(pdev, NULL);
+ return ret;
+}
+
+/*
+ * This function cleans up the allocated card buffers.
+ *
+ * The following are freed by this function -
+ * - TXBD ring buffers
+ * - RXBD ring buffers
+ * - Event BD ring buffers
+ * - Command response ring buffer
+ * - Sleep cookie buffer
+ */
+static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ struct pci_dev *pdev = card->dev;
+
+ mwifiex_pcie_delete_sleep_cookie_buf(adapter);
+ mwifiex_pcie_delete_cmdrsp_buf(adapter);
+ mwifiex_pcie_delete_evtbd_ring(adapter);
+ mwifiex_pcie_delete_rxbd_ring(adapter);
+ mwifiex_pcie_delete_txbd_ring(adapter);
+ card->cmdrsp_buf = NULL;
+
+ dev_dbg(adapter->dev, "Clearing driver ready signature\n");
+ if (user_rmmod) {
+ if (mwifiex_write_reg(adapter, REG_DRV_READY, 0x00000000))
+ dev_err(adapter->dev, "Failed to write driver not-ready signature\n");
+ }
+
+ if (pdev) {
+ pci_iounmap(pdev, card->pci_mmap);
+ pci_iounmap(pdev, card->pci_mmap1);
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ }
+}
+
+/*
+ * This function registers the PCIE device.
+ *
+ * PCIE IRQ is claimed, block size is set and driver data is initialized.
+ */
+static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
+{
+ int ret;
+ struct pcie_service_card *card = adapter->card;
+ struct pci_dev *pdev = card->dev;
+
+ /* save adapter pointer in card */
+ card->adapter = adapter;
+
+ ret = request_irq(pdev->irq, mwifiex_pcie_interrupt, IRQF_SHARED,
+ "MRVL_PCIE", pdev);
+ if (ret) {
+ pr_err("request_irq failed: ret=%d\n", ret);
+ adapter->card = NULL;
+ return -1;
+ }
+
+ adapter->dev = &pdev->dev;
+ strcpy(adapter->fw_name, PCIE8766_DEFAULT_FW_NAME);
+
+ return 0;
+}
+
+/*
+ * This function unregisters the PCIE device.
+ *
+ * The PCIE IRQ is released, the function is disabled and driver
+ * data is set to null.
+ */
+static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+
+ if (card) {
+ dev_dbg(adapter->dev, "%s(): calling free_irq()\n", __func__);
+ free_irq(card->dev->irq, card->dev);
+ }
+}
+
+static struct mwifiex_if_ops pcie_ops = {
+ .init_if = mwifiex_pcie_init,
+ .cleanup_if = mwifiex_pcie_cleanup,
+ .check_fw_status = mwifiex_check_fw_status,
+ .prog_fw = mwifiex_prog_fw_w_helper,
+ .register_dev = mwifiex_register_dev,
+ .unregister_dev = mwifiex_unregister_dev,
+ .enable_int = mwifiex_pcie_enable_host_int,
+ .process_int_status = mwifiex_process_int_status,
+ .host_to_card = mwifiex_pcie_host_to_card,
+ .wakeup = mwifiex_pm_wakeup_card,
+ .wakeup_complete = mwifiex_pm_wakeup_card_complete,
+
+ /* PCIE specific */
+ .cmdrsp_complete = mwifiex_pcie_cmdrsp_complete,
+ .event_complete = mwifiex_pcie_event_complete,
+ .update_mp_end_port = NULL,
+ .cleanup_mpa_buf = NULL,
+};
+
+/*
+ * This function initializes the PCIE driver module.
+ *
+ * This initiates the semaphore and registers the device with
+ * PCIE bus.
+ */
+static int mwifiex_pcie_init_module(void)
+{
+ int ret;
+
+ pr_debug("Marvell 8766 PCIe Driver\n");
+
+ sema_init(&add_remove_card_sem, 1);
+
+ /* Clear the flag in case user removes the card. */
+ user_rmmod = 0;
+
+ ret = pci_register_driver(&mwifiex_pcie);
+ if (ret)
+ pr_err("Driver register failed!\n");
+ else
+ pr_debug("info: Driver registered successfully!\n");
+
+ return ret;
+}
+
+/*
+ * This function cleans up the PCIE driver.
+ *
+ * The following major steps are followed for cleanup -
+ * - Resume the device if its suspended
+ * - Disconnect the device if connected
+ * - Shutdown the firmware
+ * - Unregister the device from PCIE bus.
+ */
+static void mwifiex_pcie_cleanup_module(void)
+{
+ if (!down_interruptible(&add_remove_card_sem))
+ up(&add_remove_card_sem);
+
+ /* Set the flag as user is removing this module. */
+ user_rmmod = 1;
+
+ pci_unregister_driver(&mwifiex_pcie);
+}
+
+module_init(mwifiex_pcie_init_module);
+module_exit(mwifiex_pcie_cleanup_module);
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_DESCRIPTION("Marvell WiFi-Ex PCI-Express Driver version " PCIE_VERSION);
+MODULE_VERSION(PCIE_VERSION);
+MODULE_LICENSE("GPL v2");
+MODULE_FIRMWARE("mrvl/pcie8766_uapsta.bin");
diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h
new file mode 100644
index 0000000..445ff21
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/pcie.h
@@ -0,0 +1,148 @@
+/* @file mwifiex_pcie.h
+ *
+ * @brief This file contains definitions for PCI-E interface.
+ * driver.
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef _MWIFIEX_PCIE_H
+#define _MWIFIEX_PCIE_H
+
+#include <linux/pci.h>
+#include <linux/pcieport_if.h>
+#include <linux/interrupt.h>
+
+#include "main.h"
+
+#define PCIE8766_DEFAULT_FW_NAME "mrvl/pcie8766_uapsta.bin"
+
+/* Constants for Buffer Descriptor (BD) rings */
+#define MWIFIEX_MAX_TXRX_BD 0x20
+#define MWIFIEX_TXBD_MASK 0x3F
+#define MWIFIEX_RXBD_MASK 0x3F
+
+#define MWIFIEX_MAX_EVT_BD 0x04
+#define MWIFIEX_EVTBD_MASK 0x07
+
+/* PCIE INTERNAL REGISTERS */
+#define PCIE_SCRATCH_0_REG 0xC10
+#define PCIE_SCRATCH_1_REG 0xC14
+#define PCIE_CPU_INT_EVENT 0xC18
+#define PCIE_CPU_INT_STATUS 0xC1C
+#define PCIE_HOST_INT_STATUS 0xC30
+#define PCIE_HOST_INT_MASK 0xC34
+#define PCIE_HOST_INT_STATUS_MASK 0xC3C
+#define PCIE_SCRATCH_2_REG 0xC40
+#define PCIE_SCRATCH_3_REG 0xC44
+#define PCIE_SCRATCH_4_REG 0xCC0
+#define PCIE_SCRATCH_5_REG 0xCC4
+#define PCIE_SCRATCH_6_REG 0xCC8
+#define PCIE_SCRATCH_7_REG 0xCCC
+#define PCIE_SCRATCH_8_REG 0xCD0
+#define PCIE_SCRATCH_9_REG 0xCD4
+#define PCIE_SCRATCH_10_REG 0xCD8
+#define PCIE_SCRATCH_11_REG 0xCDC
+#define PCIE_SCRATCH_12_REG 0xCE0
+
+#define CPU_INTR_DNLD_RDY BIT(0)
+#define CPU_INTR_DOOR_BELL BIT(1)
+#define CPU_INTR_SLEEP_CFM_DONE BIT(2)
+#define CPU_INTR_RESET BIT(3)
+
+#define HOST_INTR_DNLD_DONE BIT(0)
+#define HOST_INTR_UPLD_RDY BIT(1)
+#define HOST_INTR_CMD_DONE BIT(2)
+#define HOST_INTR_EVENT_RDY BIT(3)
+#define HOST_INTR_MASK (HOST_INTR_DNLD_DONE | \
+ HOST_INTR_UPLD_RDY | \
+ HOST_INTR_CMD_DONE | \
+ HOST_INTR_EVENT_RDY)
+
+#define MWIFIEX_BD_FLAG_ROLLOVER_IND BIT(7)
+#define MWIFIEX_BD_FLAG_FIRST_DESC BIT(0)
+#define MWIFIEX_BD_FLAG_LAST_DESC BIT(1)
+#define REG_CMD_ADDR_LO PCIE_SCRATCH_0_REG
+#define REG_CMD_ADDR_HI PCIE_SCRATCH_1_REG
+#define REG_CMD_SIZE PCIE_SCRATCH_2_REG
+
+#define REG_CMDRSP_ADDR_LO PCIE_SCRATCH_4_REG
+#define REG_CMDRSP_ADDR_HI PCIE_SCRATCH_5_REG
+
+/* TX buffer description read pointer */
+#define REG_TXBD_RDPTR PCIE_SCRATCH_6_REG
+/* TX buffer description write pointer */
+#define REG_TXBD_WRPTR PCIE_SCRATCH_7_REG
+/* RX buffer description read pointer */
+#define REG_RXBD_RDPTR PCIE_SCRATCH_8_REG
+/* RX buffer description write pointer */
+#define REG_RXBD_WRPTR PCIE_SCRATCH_9_REG
+/* Event buffer description read pointer */
+#define REG_EVTBD_RDPTR PCIE_SCRATCH_10_REG
+/* Event buffer description write pointer */
+#define REG_EVTBD_WRPTR PCIE_SCRATCH_11_REG
+/* Driver ready signature write pointer */
+#define REG_DRV_READY PCIE_SCRATCH_12_REG
+
+/* Max retry number of command write */
+#define MAX_WRITE_IOMEM_RETRY 2
+/* Define PCIE block size for firmware download */
+#define MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD 256
+/* FW awake cookie after FW ready */
+#define FW_AWAKE_COOKIE (0xAA55AA55)
+
+struct mwifiex_pcie_buf_desc {
+ u64 paddr;
+ u16 len;
+ u16 flags;
+} __packed;
+
+struct pcie_service_card {
+ struct pci_dev *dev;
+ struct mwifiex_adapter *adapter;
+
+ u32 txbd_wrptr;
+ u32 txbd_rdptr;
+ u32 txbd_ring_size;
+ u8 *txbd_ring_vbase;
+ phys_addr_t txbd_ring_pbase;
+ struct mwifiex_pcie_buf_desc *txbd_ring[MWIFIEX_MAX_TXRX_BD];
+ struct sk_buff *tx_buf_list[MWIFIEX_MAX_TXRX_BD];
+
+ u32 rxbd_wrptr;
+ u32 rxbd_rdptr;
+ u32 rxbd_ring_size;
+ u8 *rxbd_ring_vbase;
+ phys_addr_t rxbd_ring_pbase;
+ struct mwifiex_pcie_buf_desc *rxbd_ring[MWIFIEX_MAX_TXRX_BD];
+ struct sk_buff *rx_buf_list[MWIFIEX_MAX_TXRX_BD];
+
+ u32 evtbd_wrptr;
+ u32 evtbd_rdptr;
+ u32 evtbd_ring_size;
+ u8 *evtbd_ring_vbase;
+ phys_addr_t evtbd_ring_pbase;
+ struct mwifiex_pcie_buf_desc *evtbd_ring[MWIFIEX_MAX_EVT_BD];
+ struct sk_buff *evt_buf_list[MWIFIEX_MAX_EVT_BD];
+
+ struct sk_buff *cmd_buf;
+ struct sk_buff *cmdrsp_buf;
+ struct sk_buff *sleep_cookie;
+ void __iomem *pci_mmap;
+ void __iomem *pci_mmap1;
+};
+
+#endif /* _MWIFIEX_PCIE_H */
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
index 82098ac..283171b 100644
--- a/drivers/net/wireless/mwifiex/sdio.c
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -89,7 +89,8 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
return -EIO;
}
- if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops)) {
+ if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops,
+ MWIFIEX_SDIO)) {
pr_err("%s: add card failed\n", __func__);
kfree(card);
sdio_claim_host(func);
@@ -830,7 +831,7 @@ done:
* The winner interface is also determined by this function.
*/
static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
- u32 poll_num, int *winner)
+ u32 poll_num)
{
int ret = 0;
u16 firmware_stat;
@@ -842,7 +843,7 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat);
if (ret)
continue;
- if (firmware_stat == FIRMWARE_READY) {
+ if (firmware_stat == FIRMWARE_READY_SDIO) {
ret = 0;
break;
} else {
@@ -851,15 +852,15 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
}
}
- if (winner && ret) {
+ if (ret) {
if (mwifiex_read_reg
(adapter, CARD_FW_STATUS0_REG, &winner_status))
winner_status = 0;
if (winner_status)
- *winner = 0;
+ adapter->winner = 0;
else
- *winner = 1;
+ adapter->winner = 1;
}
return ret;
}
@@ -1413,7 +1414,7 @@ tx_curr_single:
* the type. The firmware handles the packets based upon this set type.
*/
static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter,
- u8 type, u8 *payload, u32 pkt_len,
+ u8 type, struct sk_buff *skb,
struct mwifiex_tx_param *tx_param)
{
struct sdio_mmc_card *card = adapter->card;
@@ -1421,6 +1422,8 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter,
u32 buf_block_len;
u32 blk_size;
u8 port = CTRL_PORT;
+ u8 *payload = (u8 *)skb->data;
+ u32 pkt_len = skb->len;
/* Allocate buffer and copy payload */
blk_size = MWIFIEX_SDIO_BLOCK_SIZE;
@@ -1722,6 +1725,8 @@ static struct mwifiex_if_ops sdio_ops = {
/* SDIO specific */
.update_mp_end_port = mwifiex_update_mp_end_port,
.cleanup_mpa_buf = mwifiex_cleanup_mpa_buf,
+ .cmdrsp_complete = mwifiex_sdio_cmdrsp_complete,
+ .event_complete = mwifiex_sdio_event_complete,
};
/*
diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h
index 524f78f..3f71180 100644
--- a/drivers/net/wireless/mwifiex/sdio.h
+++ b/drivers/net/wireless/mwifiex/sdio.h
@@ -169,9 +169,6 @@
/* Rx unit register */
#define CARD_RX_UNIT_REG 0x63
-/* Event header len w/o 4 bytes of interface header */
-#define MWIFIEX_EVENT_HEADER_LEN 4
-
/* Max retry number of CMD53 write */
#define MAX_WRITE_IOMEM_RETRY 2
@@ -304,4 +301,25 @@ struct sdio_mmc_card {
struct mwifiex_sdio_mpa_tx mpa_tx;
struct mwifiex_sdio_mpa_rx mpa_rx;
};
+
+/*
+ * .cmdrsp_complete handler
+ */
+static inline int mwifiex_sdio_cmdrsp_complete(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb)
+{
+ dev_kfree_skb_any(skb);
+ return 0;
+}
+
+/*
+ * .event_complete handler
+ */
+static inline int mwifiex_sdio_event_complete(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb)
+{
+ dev_kfree_skb_any(skb);
+ return 0;
+}
+
#endif /* _MWIFIEX_SDIO_H */
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index c54ee28..ea6518d 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -902,6 +902,59 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
}
/*
+ * This function prepares command to set PCI-Express
+ * host buffer configuration
+ *
+ * Preparation includes -
+ * - Setting command ID, action and proper size
+ * - Setting host buffer configuration
+ * - Ensuring correct endian-ness
+ */
+static int
+mwifiex_cmd_pcie_host_spec(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd, u16 action)
+{
+ struct host_cmd_ds_pcie_details *host_spec =
+ &cmd->params.pcie_host_spec;
+ struct pcie_service_card *card = priv->adapter->card;
+ phys_addr_t *buf_pa;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_PCIE_DESC_DETAILS);
+ cmd->size = cpu_to_le16(sizeof(struct
+ host_cmd_ds_pcie_details) + S_DS_GEN);
+ cmd->result = 0;
+
+ memset(host_spec, 0, sizeof(struct host_cmd_ds_pcie_details));
+
+ if (action == HostCmd_ACT_GEN_SET) {
+ /* Send the ring base addresses and count to firmware */
+ host_spec->txbd_addr_lo = (u32)(card->txbd_ring_pbase);
+ host_spec->txbd_addr_hi =
+ (u32)(((u64)card->txbd_ring_pbase)>>32);
+ host_spec->txbd_count = MWIFIEX_MAX_TXRX_BD;
+ host_spec->rxbd_addr_lo = (u32)(card->rxbd_ring_pbase);
+ host_spec->rxbd_addr_hi =
+ (u32)(((u64)card->rxbd_ring_pbase)>>32);
+ host_spec->rxbd_count = MWIFIEX_MAX_TXRX_BD;
+ host_spec->evtbd_addr_lo =
+ (u32)(card->evtbd_ring_pbase);
+ host_spec->evtbd_addr_hi =
+ (u32)(((u64)card->evtbd_ring_pbase)>>32);
+ host_spec->evtbd_count = MWIFIEX_MAX_EVT_BD;
+ if (card->sleep_cookie) {
+ buf_pa = MWIFIEX_SKB_PACB(card->sleep_cookie);
+ host_spec->sleep_cookie_addr_lo = (u32) *buf_pa;
+ host_spec->sleep_cookie_addr_hi =
+ (u32) (((u64)*buf_pa) >> 32);
+ dev_dbg(priv->adapter->dev, "sleep_cook_lo phy addr: "
+ "0x%x\n", host_spec->sleep_cookie_addr_lo);
+ }
+ }
+
+ return 0;
+}
+
+/*
* This function prepares the commands before sending them to the firmware.
*
* This is a generic function which calls specific command preparation
@@ -1079,6 +1132,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
host_cmd_ds_set_bss_mode) + S_DS_GEN);
ret = 0;
break;
+ case HostCmd_CMD_PCIE_DESC_DETAILS:
+ ret = mwifiex_cmd_pcie_host_spec(priv, cmd_ptr, cmd_action);
+ break;
default:
dev_err(priv->adapter->dev,
"PREP_CMD: unknown cmd- %#x\n", cmd_no);
@@ -1095,6 +1151,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
* working state.
*
* The following commands are issued sequentially -
+ * - Set PCI-Express host buffer configuration (PCIE only)
* - Function init (for first interface only)
* - Read MAC address (for first interface only)
* - Reconfigure Tx buffer size (for first interface only)
@@ -1116,6 +1173,13 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
struct mwifiex_ds_11n_tx_cfg tx_cfg;
if (first_sta) {
+ if (priv->adapter->iface_type == MWIFIEX_PCIE) {
+ ret = mwifiex_send_cmd_async(priv,
+ HostCmd_CMD_PCIE_DESC_DETAILS,
+ HostCmd_ACT_GEN_SET, 0, NULL);
+ if (ret)
+ return -1;
+ }
ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_FUNC_INIT,
HostCmd_ACT_GEN_SET, 0, NULL);
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index 066f204..1382f69 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -952,6 +952,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
case HostCmd_CMD_11N_CFG:
ret = mwifiex_ret_11n_cfg(resp, data_buf);
break;
+ case HostCmd_CMD_PCIE_DESC_DETAILS:
+ break;
default:
dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
resp->command);
diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c
index 1822bfa..d97facd 100644
--- a/drivers/net/wireless/mwifiex/sta_tx.c
+++ b/drivers/net/wireless/mwifiex/sta_tx.c
@@ -151,7 +151,7 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags)
skb_push(skb, INTF_HEADER_LEN);
ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
- skb->data, skb->len, NULL);
+ skb, NULL);
switch (ret) {
case -EBUSY:
adapter->data_sent = true;
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c
index 6190b2f..c3fe88a 100644
--- a/drivers/net/wireless/mwifiex/txrx.c
+++ b/drivers/net/wireless/mwifiex/txrx.c
@@ -78,7 +78,7 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
(struct txpd *) (head_ptr + INTF_HEADER_LEN);
ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
- skb->data, skb->len, tx_param);
+ skb, tx_param);
}
switch (ret) {
diff --git a/drivers/net/wireless/mwifiex/util.h b/drivers/net/wireless/mwifiex/util.h
index 9506afc..f6d36b9 100644
--- a/drivers/net/wireless/mwifiex/util.h
+++ b/drivers/net/wireless/mwifiex/util.h
@@ -22,11 +22,16 @@
static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb)
{
- return (struct mwifiex_rxinfo *)skb->cb;
+ return (struct mwifiex_rxinfo *)(skb->cb + sizeof(phys_addr_t));
}
static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb)
{
- return (struct mwifiex_txinfo *)skb->cb;
+ return (struct mwifiex_txinfo *)(skb->cb + sizeof(phys_addr_t));
+}
+
+static inline phys_addr_t *MWIFIEX_SKB_PACB(struct sk_buff *skb)
+{
+ return (phys_addr_t *)skb->cb;
}
#endif /* !_MWIFIEX_UTIL_H_ */
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
index eda2447..6c239c3 100644
--- a/drivers/net/wireless/mwifiex/wmm.c
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -1125,8 +1125,8 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
tx_param.next_pkt_len =
((skb_next) ? skb_next->len +
sizeof(struct txpd) : 0);
- ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
- skb->data, skb->len, &tx_param);
+ ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, skb,
+ &tx_param);
switch (ret) {
case -EBUSY:
dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
--
1.7.0.2
^ permalink raw reply related
* [PATCH] mwifiex: use separate wait queue for each command node
From: Bing Zhao @ 2011-10-04 4:08 UTC (permalink / raw)
To: linux-wireless
Cc: John W. Linville, Amitkumar Karwar, Kiran Divekar, Yogesh Powar,
Frank Huang, Bing Zhao
From: Amitkumar Karwar <akarwar@marvell.com>
Currently global wait queue (adapter->cmd_wait_q) is used for
sending synchronous commands to FW. When two threads enter in
mwifiex_send_cmd_sync() routine at the same time, both the
threads wait for their command responses. They wake up
simultaneously after getting response of 1st command. After
this when a thread is waiting for command response of 3rd
command, it wakes up after getting response of 2nd command
and so on. Therefore we don't wait for the response of last
command(0xaa) during unload. Hence while next time loading the
driver command time out is seen for INIT command.
This problem is resolved by having separate wait queue for each
command. Since driver sends multiple scan commands asynchronously
to FW for scanning the network, we will need separate wait queue
for the whole scan operation. Earlier the global wait queue was
being used for scan.
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
---
drivers/net/wireless/mwifiex/cmdevt.c | 84 ++++++++++++++++------------
drivers/net/wireless/mwifiex/join.c | 12 ++--
drivers/net/wireless/mwifiex/main.c | 6 +-
drivers/net/wireless/mwifiex/main.h | 15 +++--
drivers/net/wireless/mwifiex/scan.c | 19 ++++---
drivers/net/wireless/mwifiex/sta_cmdresp.c | 6 +-
drivers/net/wireless/mwifiex/sta_ioctl.c | 14 ++--
drivers/net/wireless/mwifiex/util.c | 11 ++--
8 files changed, 95 insertions(+), 72 deletions(-)
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index d12e25d..aab805f 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -40,8 +40,13 @@ mwifiex_init_cmd_node(struct mwifiex_private *priv,
{
cmd_node->priv = priv;
cmd_node->cmd_oid = cmd_oid;
- cmd_node->wait_q_enabled = priv->adapter->cmd_wait_q_required;
- priv->adapter->cmd_wait_q_required = false;
+ if (priv->adapter->cmd_wait_q_required) {
+ cmd_node->wait_q = &cmd_node->cmd_wait_q;
+ cmd_node->wait_q->condition = false;
+ priv->adapter->cmd_wait_q_required = false;
+ } else {
+ cmd_node->wait_q = NULL;
+ }
cmd_node->data_buf = data_buf;
cmd_node->cmd_skb = cmd_node->skb;
}
@@ -88,7 +93,7 @@ mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter,
cmd_node->cmd_oid = 0;
cmd_node->cmd_flag = 0;
cmd_node->data_buf = NULL;
- cmd_node->wait_q_enabled = false;
+ cmd_node->wait_q = NULL;
if (cmd_node->cmd_skb)
skb_trim(cmd_node->cmd_skb, 0);
@@ -145,8 +150,8 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
if (host_cmd == NULL || host_cmd->size == 0) {
dev_err(adapter->dev, "DNLD_CMD: host_cmd is null"
" or cmd size is 0, not sending\n");
- if (cmd_node->wait_q_enabled)
- adapter->cmd_wait_q.status = -1;
+ if (cmd_node->wait_q)
+ cmd_node->wait_q->status = -1;
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
return -1;
}
@@ -183,8 +188,8 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
if (ret == -1) {
dev_err(adapter->dev, "DNLD_CMD: host to card failed\n");
- if (cmd_node->wait_q_enabled)
- adapter->cmd_wait_q.status = -1;
+ if (cmd_node->wait_q)
+ cmd_node->wait_q->status = -1;
mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
@@ -298,13 +303,17 @@ int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter)
adapter->cmd_pool = cmd_array;
memset(adapter->cmd_pool, 0, buf_size);
- /* Allocate and initialize command buffers */
for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) {
+ /* Allocate and initialize command buffers */
cmd_array[i].skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER);
if (!cmd_array[i].skb) {
dev_err(adapter->dev, "ALLOC_CMD_BUF: out of memory\n");
return -1;
}
+ /* Initialize command wait queues */
+ init_waitqueue_head(&cmd_array[i].cmd_wait_q.wait);
+ cmd_array[i].cmd_wait_q.condition = false;
+ cmd_array[i].cmd_wait_q.status = 0;
}
for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++)
@@ -421,12 +430,12 @@ int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no,
struct mwifiex_adapter *adapter = priv->adapter;
adapter->cmd_wait_q_required = true;
- adapter->cmd_wait_q.condition = false;
ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid,
data_buf);
if (!ret)
- ret = mwifiex_wait_queue_complete(adapter);
+ ret = mwifiex_wait_queue_complete(adapter,
+ adapter->cmd_queued->wait_q);
return ret;
}
@@ -513,6 +522,8 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
return -1;
}
+ adapter->cmd_queued = cmd_node;
+
/* Send command */
if (cmd_no == HostCmd_CMD_802_11_SCAN)
mwifiex_queue_scan_cmd(priv, cmd_node);
@@ -537,8 +548,8 @@ mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
if (!cmd_node)
return;
- if (cmd_node->wait_q_enabled)
- mwifiex_complete_cmd(adapter);
+ if (cmd_node->wait_q)
+ mwifiex_complete_cmd(adapter, cmd_node->wait_q);
/* Clean the node */
mwifiex_clean_cmd_node(adapter, cmd_node);
@@ -746,8 +757,8 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
if (!(orig_cmdresp_no & HostCmd_RET_BIT)) {
dev_err(adapter->dev, "CMD_RESP: invalid cmd resp\n");
- if (adapter->curr_cmd->wait_q_enabled)
- adapter->cmd_wait_q.status = -1;
+ if (adapter->curr_cmd->wait_q)
+ adapter->curr_cmd->wait_q->status = -1;
mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
@@ -778,10 +789,10 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
}
if (adapter->curr_cmd) {
- if (adapter->curr_cmd->wait_q_enabled && (!ret))
- adapter->cmd_wait_q.status = 0;
- else if (adapter->curr_cmd->wait_q_enabled && (ret == -1))
- adapter->cmd_wait_q.status = -1;
+ if (adapter->curr_cmd->wait_q && (!ret))
+ adapter->curr_cmd->wait_q->status = 0;
+ else if (adapter->curr_cmd->wait_q && (ret == -1))
+ adapter->curr_cmd->wait_q->status = -1;
/* Clean up and put current command back to cmd_free_q */
mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
@@ -814,8 +825,8 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
return;
}
cmd_node = adapter->curr_cmd;
- if (cmd_node->wait_q_enabled)
- adapter->cmd_wait_q.status = -ETIMEDOUT;
+ if (cmd_node->wait_q)
+ cmd_node->wait_q->status = -ETIMEDOUT;
if (cmd_node) {
adapter->dbg.timeout_cmd_id =
@@ -878,14 +889,16 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
{
struct cmd_ctrl_node *cmd_node = NULL, *tmp_node;
unsigned long flags;
+ struct mwifiex_wait_queue *wait_q;
/* Cancel current cmd */
- if ((adapter->curr_cmd) && (adapter->curr_cmd->wait_q_enabled)) {
+ if ((adapter->curr_cmd) && (adapter->curr_cmd->wait_q)) {
+ wait_q = adapter->curr_cmd->wait_q;
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
- adapter->curr_cmd->wait_q_enabled = false;
+ adapter->curr_cmd->wait_q = NULL;
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
- adapter->cmd_wait_q.status = -1;
- mwifiex_complete_cmd(adapter);
+ adapter->curr_cmd->wait_q->status = -1;
+ mwifiex_complete_cmd(adapter, wait_q);
}
/* Cancel all pending command */
spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
@@ -894,10 +907,10 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
list_del(&cmd_node->list);
spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
- if (cmd_node->wait_q_enabled) {
- adapter->cmd_wait_q.status = -1;
- mwifiex_complete_cmd(adapter);
- cmd_node->wait_q_enabled = false;
+ if (cmd_node->wait_q) {
+ cmd_node->wait_q->status = -1;
+ mwifiex_complete_cmd(adapter, cmd_node->wait_q);
+ cmd_node->wait_q = NULL;
}
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
@@ -911,7 +924,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
list_del(&cmd_node->list);
spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
- cmd_node->wait_q_enabled = false;
+ cmd_node->wait_q = NULL;
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
}
@@ -933,7 +946,8 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
* are cancelled.
*/
void
-mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
+mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter,
+ struct mwifiex_wait_queue *wait_q)
{
struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL;
unsigned long cmd_flags;
@@ -942,10 +956,10 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
uint16_t cancel_scan_cmd = false;
if ((adapter->curr_cmd) &&
- (adapter->curr_cmd->wait_q_enabled)) {
+ (adapter->curr_cmd->wait_q)) {
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
cmd_node = adapter->curr_cmd;
- cmd_node->wait_q_enabled = false;
+ cmd_node->wait_q = NULL;
cmd_node->cmd_flag |= CMD_F_CANCELED;
spin_lock_irqsave(&adapter->cmd_pending_q_lock,
cmd_pending_q_flags);
@@ -964,7 +978,7 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
list_del(&cmd_node->list);
spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
scan_pending_q_flags);
- cmd_node->wait_q_enabled = false;
+ cmd_node->wait_q = NULL;
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
spin_lock_irqsave(&adapter->scan_pending_q_lock,
scan_pending_q_flags);
@@ -978,8 +992,8 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
adapter->scan_processing = false;
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
}
- adapter->cmd_wait_q.status = -1;
- mwifiex_complete_cmd(adapter);
+ wait_q->status = -1;
+ mwifiex_complete_cmd(adapter, wait_q);
}
/*
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
index 62b4c29..8260a4f 100644
--- a/drivers/net/wireless/mwifiex/join.c
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -683,11 +683,11 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
done:
/* Need to indicate IOCTL complete */
- if (adapter->curr_cmd->wait_q_enabled) {
+ if (adapter->curr_cmd->wait_q) {
if (ret)
- adapter->cmd_wait_q.status = -1;
+ adapter->curr_cmd->wait_q->status = -1;
else
- adapter->cmd_wait_q.status = 0;
+ adapter->curr_cmd->wait_q->status = 0;
}
return ret;
@@ -1213,11 +1213,11 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
done:
/* Need to indicate IOCTL complete */
- if (adapter->curr_cmd->wait_q_enabled) {
+ if (adapter->curr_cmd->wait_q) {
if (ret)
- adapter->cmd_wait_q.status = -1;
+ adapter->curr_cmd->wait_q->status = -1;
else
- adapter->cmd_wait_q.status = 0;
+ adapter->curr_cmd->wait_q->status = 0;
}
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index 8486451..13264b8 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -682,9 +682,9 @@ mwifiex_add_card(void *card, struct semaphore *sem,
adapter->hs_activated = false;
init_waitqueue_head(&adapter->hs_activate_wait_q);
adapter->cmd_wait_q_required = false;
- init_waitqueue_head(&adapter->cmd_wait_q.wait);
- adapter->cmd_wait_q.condition = false;
- adapter->cmd_wait_q.status = 0;
+ init_waitqueue_head(&adapter->scan_wait_q.wait);
+ adapter->scan_wait_q.condition = false;
+ adapter->scan_wait_q.status = 0;
adapter->workqueue = create_workqueue("MWIFIEX_WORK_QUEUE");
if (!adapter->workqueue)
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 907ab74..842ae6b 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -510,7 +510,8 @@ struct cmd_ctrl_node {
struct sk_buff *cmd_skb;
struct sk_buff *resp_skb;
void *data_buf;
- u32 wait_q_enabled;
+ struct mwifiex_wait_queue cmd_wait_q;
+ struct mwifiex_wait_queue *wait_q;
struct sk_buff *skb;
};
@@ -638,7 +639,8 @@ struct mwifiex_adapter {
u8 arp_filter[ARP_FILTER_MAX_BUF_SIZE];
u32 arp_filter_size;
u16 cmd_wait_q_required;
- struct mwifiex_wait_queue cmd_wait_q;
+ struct mwifiex_wait_queue scan_wait_q;
+ struct cmd_ctrl_node *cmd_queued;
};
int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
@@ -658,7 +660,8 @@ int mwifiex_recv_packet(struct mwifiex_adapter *, struct sk_buff *skb);
int mwifiex_process_event(struct mwifiex_adapter *adapter);
-int mwifiex_complete_cmd(struct mwifiex_adapter *adapter);
+int mwifiex_complete_cmd(struct mwifiex_adapter *adapter,
+ struct mwifiex_wait_queue *wait_q);
int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
u16 cmd_action, u32 cmd_oid, void *data_buf);
@@ -674,7 +677,8 @@ int mwifiex_get_debug_info(struct mwifiex_private *,
int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter);
int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter);
void mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter);
-void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter);
+void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter,
+ struct mwifiex_wait_queue *wait_q);
void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
struct cmd_ctrl_node *cmd_node);
@@ -881,7 +885,8 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
struct mwifiex_multicast_list *mcast_list);
int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,
struct net_device *dev);
-int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter);
+int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter,
+ struct mwifiex_wait_queue *wait_q);
int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
struct mwifiex_802_11_ssid *req_ssid);
int mwifiex_set_hs_params(struct mwifiex_private *priv,
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index ca37619..f66960f 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -185,11 +185,12 @@ int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv,
{
int status;
- priv->adapter->cmd_wait_q.condition = false;
+ priv->adapter->scan_wait_q.condition = false;
status = mwifiex_scan_networks(priv, scan_req);
if (!status)
- status = mwifiex_wait_queue_complete(priv->adapter);
+ status = mwifiex_wait_queue_complete(priv->adapter,
+ &priv->adapter->scan_wait_q);
return status;
}
@@ -1786,9 +1787,10 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
/* Need to indicate IOCTL complete */
- if (adapter->curr_cmd->wait_q_enabled) {
- adapter->cmd_wait_q.status = 0;
- mwifiex_complete_cmd(adapter);
+ if (adapter->curr_cmd->wait_q) {
+ adapter->curr_cmd->wait_q->status = 0;
+ mwifiex_complete_cmd(adapter,
+ adapter->curr_cmd->wait_q);
}
if (priv->report_scan_result)
priv->report_scan_result = false;
@@ -1844,7 +1846,7 @@ mwifiex_queue_scan_cmd(struct mwifiex_private *priv,
struct mwifiex_adapter *adapter = priv->adapter;
unsigned long flags;
- cmd_node->wait_q_enabled = true;
+ cmd_node->wait_q = &adapter->scan_wait_q;
spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
list_add_tail(&cmd_node->list, &adapter->scan_pending_q);
spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
@@ -1911,7 +1913,7 @@ int mwifiex_request_scan(struct mwifiex_private *priv,
}
priv->scan_pending_on_block = true;
- priv->adapter->cmd_wait_q.condition = false;
+ priv->adapter->scan_wait_q.condition = false;
if (req_ssid && req_ssid->ssid_len != 0)
/* Specific SSID scan */
@@ -1921,7 +1923,8 @@ int mwifiex_request_scan(struct mwifiex_private *priv,
ret = mwifiex_scan_networks(priv, NULL);
if (!ret)
- ret = mwifiex_wait_queue_complete(priv->adapter);
+ ret = mwifiex_wait_queue_complete(priv->adapter,
+ &priv->adapter->scan_wait_q);
if (ret == -1) {
priv->scan_pending_on_block = false;
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index 6804239..066f204 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -51,8 +51,8 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
dev_err(adapter->dev, "CMD_RESP: cmd %#x error, result=%#x\n",
resp->command, resp->result);
- if (adapter->curr_cmd->wait_q_enabled)
- adapter->cmd_wait_q.status = -1;
+ if (adapter->curr_cmd->wait_q)
+ adapter->curr_cmd->wait_q->status = -1;
switch (le16_to_cpu(resp->command)) {
case HostCmd_CMD_802_11_PS_MODE_ENH:
@@ -847,7 +847,7 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
break;
case HostCmd_CMD_802_11_SCAN:
ret = mwifiex_ret_802_11_scan(priv, resp);
- adapter->curr_cmd->wait_q_enabled = false;
+ adapter->curr_cmd->wait_q = NULL;
break;
case HostCmd_CMD_802_11_BG_SCAN_QUERY:
ret = mwifiex_ret_802_11_scan(priv, resp);
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 520800b..e55393a 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -51,10 +51,11 @@ int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,
* This function waits on a cmd wait queue. It also cancels the pending
* request after waking up, in case of errors.
*/
-int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter)
+int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter,
+ struct mwifiex_wait_queue *wait_q)
{
bool cancel_flag = false;
- int status = adapter->cmd_wait_q.status;
+ int status = wait_q->status;
dev_dbg(adapter->dev, "cmd pending\n");
atomic_inc(&adapter->cmd_pending);
@@ -63,16 +64,15 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter)
queue_work(adapter->workqueue, &adapter->main_work);
/* Wait for completion */
- wait_event_interruptible(adapter->cmd_wait_q.wait,
- adapter->cmd_wait_q.condition);
- if (!adapter->cmd_wait_q.condition)
+ wait_event_interruptible(wait_q->wait, wait_q->condition);
+ if (!wait_q->condition)
cancel_flag = true;
if (cancel_flag) {
- mwifiex_cancel_pending_ioctl(adapter);
+ mwifiex_cancel_pending_ioctl(adapter, wait_q);
dev_dbg(adapter->dev, "cmd cancel\n");
}
- adapter->cmd_wait_q.status = 0;
+ wait_q->status = 0;
return status;
}
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c
index d412915..430bb50 100644
--- a/drivers/net/wireless/mwifiex/util.c
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -185,18 +185,19 @@ int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb)
* corresponding waiting function. Otherwise, it processes the
* IOCTL response and frees the response buffer.
*/
-int mwifiex_complete_cmd(struct mwifiex_adapter *adapter)
+int mwifiex_complete_cmd(struct mwifiex_adapter *adapter,
+ struct mwifiex_wait_queue *wait_q)
{
atomic_dec(&adapter->cmd_pending);
dev_dbg(adapter->dev, "cmd completed: status=%d\n",
- adapter->cmd_wait_q.status);
+ wait_q->status);
- adapter->cmd_wait_q.condition = true;
+ wait_q->condition = true;
- if (adapter->cmd_wait_q.status == -ETIMEDOUT)
+ if (wait_q->status == -ETIMEDOUT)
dev_err(adapter->dev, "cmd timeout\n");
else
- wake_up_interruptible(&adapter->cmd_wait_q.wait);
+ wake_up_interruptible(&wait_q->wait);
return 0;
}
--
1.7.0.2
^ permalink raw reply related
* pull request: bluetooth-next 2011-10-03
From: Gustavo Padovan @ 2011-10-04 2:28 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, linux-bluetooth, linux-kernel
Hi John,
Last pull request for 3.2, just a few patches here. The most important ones are
from Mat Martineau that adds support to handle fragmented skbs in
bt_sock_stream_recvmsg(). The rest are just fixes and clean ups.
Please pull! Or let me know any problem, thanks.
Gustavo
The following changes since commit 76ed94be65c8bd80b565865c186dd9f24bb2f23b:
ath9k_hw: set pci_express capability true for AR9480 (2011-10-03 15:22:42 -0400)
are available in the git repository at:
git://github.com/padovan/bluetooth-next.git master
Anderson Lizardo (1):
Bluetooth: use recommended LE connection parameters
Andre Guedes (1):
Bluetooth: hci_le_adv_report_evt code refactoring
Mat Martineau (3):
Bluetooth: Linearize skbs for use in BNEP, CMTP, HIDP, and RFCOMM
Bluetooth: Handle fragmented skbs in bt_sock_stream_recvmsg()
Bluetooth: Perform L2CAP SDU reassembly without copying data
Oliver Neukum (1):
btusb: add device entry for Broadcom SoftSailing
Peter Hurley (1):
Bluetooth: Allow ACL packets over USB in HCI_RAW mode
Szymon Janc (1):
Bluetooth: Mark not declared l2cap_core functions as static
Waldemar Rymarkiewicz (1):
Bluetooth: Fix possible NULL pointer dereference
drivers/bluetooth/btusb.c | 6 +-
include/net/bluetooth/l2cap.h | 3 +-
net/bluetooth/af_bluetooth.c | 30 +++++-
net/bluetooth/bnep/core.c | 5 +-
net/bluetooth/cmtp/core.c | 5 +-
net/bluetooth/hci_conn.c | 14 +-
net/bluetooth/hci_event.c | 20 ++--
net/bluetooth/hidp/core.c | 10 ++-
net/bluetooth/l2cap_core.c | 255 ++++++++++++++---------------------------
net/bluetooth/rfcomm/core.c | 5 +-
10 files changed, 157 insertions(+), 196 deletions(-)
^ permalink raw reply
* [patch] fix the definition of AR9170_PHY_REG_CURRENT_RSSI
From: Adrian Chadd @ 2011-10-04 0:30 UTC (permalink / raw)
To: Christian Lamparter; +Cc: linux-wireless
Hi Christian,
Although it currently isn't used anywhere, I thought it'd be
worthwhile fixing the definition of AR9170_PHY_REG_CURRENT_RSSI.
It's at AR_PHY(271) rather than AR_PHY(263).
The carl9170 driver may also suffer the same problem. The older
version I have lying around here doesn't seem to use
AR9170_PHY_REG_CURRENT_RSSI anywhere but it is defined.
Thanks,
Adrian
diff --git a/include/shared/phy.h b/include/shared/phy.h
index 024fb42..08b56eb 100644
--- a/include/shared/phy.h
+++ b/include/shared/phy.h
@@ -387,7 +387,7 @@
#define AR9170_PHY_REG_CAL_MEAS_3(_i) (AR9170_PHY_REG_BASE + \
0x041c + ((_i) << 12))
-#define AR9170_PHY_REG_CURRENT_RSSI
(AR9170_PHY_REG_BASE + 0x041c)
+#define AR9170_PHY_REG_CURRENT_RSSI
(AR9170_PHY_REG_BASE + 0x043c)
#define AR9170_PHY_REG_RFBUS_GRANT
(AR9170_PHY_REG_BASE + 0x0420)
#define AR9170_PHY_RFBUS_GRANT_EN 0x00000001
^ permalink raw reply related
* Re: [PATCH v3 00/25] staging: brcm80211: 8th reaction for mainline patch #2
From: Franky Lin @ 2011-10-03 23:33 UTC (permalink / raw)
To: Greg KH; +Cc: devel@linuxdriverproject.org, linux-wireless@vger.kernel.org
In-Reply-To: <20111003232327.GA23716@suse.de>
On 10/03/2011 04:23 PM, Greg KH wrote:
> Please note that my staging git tree moved, and is now public at
> git.kernel.org, just drop the "-2.6" from your old address.
Glad to know everything is back on track. Thanks for the heads up.
Franky
^ permalink raw reply
* Re: [PATCH 00/20] staging: brcm80211: code clean up
From: Greg KH @ 2011-10-03 23:23 UTC (permalink / raw)
To: Franky Lin; +Cc: devel, linux-wireless
In-Reply-To: <1317575685-3156-1-git-send-email-frankyl@broadcom.com>
On Sun, Oct 02, 2011 at 10:14:25AM -0700, Franky Lin wrote:
> Code clean up for both brcmfmac and brcmsmac
>
> This series applies to staging-next and depends on the following patch set:
> Message-ID: <1317335676-3424-1-git-send-email-frankyl@broadcom.com>
All applied.
^ permalink raw reply
* Re: [PATCH v3 00/25] staging: brcm80211: 8th reaction for mainline patch #2
From: Greg KH @ 2011-10-03 23:23 UTC (permalink / raw)
To: Franky Lin; +Cc: devel, linux-wireless
In-Reply-To: <1317335676-3424-1-git-send-email-frankyl@broadcom.com>
On Thu, Sep 29, 2011 at 03:34:11PM -0700, Franky Lin wrote:
> Code clean up for softmac.
>
> This patch series is in order to replace the following one:
> Message-ID: <1317145530-18839-1-git-send-email-frankyl@broadcom.com>
All applied.
Please note that my staging git tree moved, and is now public at
git.kernel.org, just drop the "-2.6" from your old address.
greg k-h
^ permalink raw reply
* [PATCH] cfg80211: allow channel change on monitor i/f if no active i/f present
From: John W. Linville @ 2011-10-03 20:23 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Gilboa Davara, John W. Linville
This is the latest attempt to address the long-standing complaint from
the aircrack-ng folks about being unable to change the channel on
monitor interfaces. This version checks for the existance of other
"active" interfaces and refuses the channel change if they are present.
https://bugzilla.redhat.com/show_bug.cgi?id=654344
Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
net/wireless/chan.c | 29 +++++++++++++++++++++++++++--
1 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 17cd0c0..d4add34 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -81,10 +81,32 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
enum nl80211_channel_type channel_type)
{
struct ieee80211_channel *chan;
- int result;
+ int result, active_intf_present = 0;
+ struct wireless_dev *mon_wdev = NULL;
+
+ if (wdev && wdev->iftype == NL80211_IFTYPE_MONITOR) {
+ mon_wdev = wdev;
+
+ ASSERT_RDEV_LOCK(rdev);
+
+ /* rdev->devlist_mtx locked by callers */
+ list_for_each_entry(wdev, &rdev->netdev_list, list) {
+ if (wdev && wdev != mon_wdev &&
+ (wdev->iftype == NL80211_IFTYPE_ADHOC ||
+ wdev->iftype == NL80211_IFTYPE_AP ||
+ wdev->iftype == NL80211_IFTYPE_AP_VLAN ||
+ wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
+ wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
+ active_intf_present = 1;
+ break;
+ }
+ }
+
+ if (active_intf_present)
+ return -EINVAL;
- if (wdev && wdev->iftype == NL80211_IFTYPE_MONITOR)
wdev = NULL;
+ }
if (wdev) {
ASSERT_WDEV_LOCK(wdev);
@@ -131,5 +153,8 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
if (wdev)
wdev->channel = chan;
+ if (mon_wdev)
+ mon_wdev->channel = chan;
+
return 0;
}
--
1.7.4.4
^ permalink raw reply related
* Re: Regulatory revamp status
From: Luis R. Rodriguez @ 2011-10-03 20:00 UTC (permalink / raw)
To: Zefir Kurtisi
Cc: linux-wireless, Boris Presman, Assaf Azulay, Michael Green,
David Quan, Kevin Hayes, Arun Venkataraman
In-Reply-To: <1125417094.1836.1317285426615.JavaMail.root@idefix>
On Thu, Sep 29, 2011 at 1:37 AM, Zefir Kurtisi
<zefir.kurtisi@neratec.com> wrote:
> Thanks for the update.
>
> To me it looks not reasonable to mix in between the two approaches: either we assume countrycodes use the same DFS region for all channels, or each channel/band needs to have its own. Otherwise I feel that a DFS region bitmap would give a semi-flexible compromise that might end up being insufficient to represent some fancy countrycodes.
I reviewed this with Michael. The answer is we only want one DFS
region per country, that's it. I'll respin my DFS patches.
Luis
^ permalink raw reply
* Re: [PATCH] compat-wireless: make patches apply again
From: Luis R. Rodriguez @ 2011-10-03 19:58 UTC (permalink / raw)
To: Hauke Mehrtens; +Cc: linux-wireless
In-Reply-To: <1317465198-2733-1-git-send-email-hauke@hauke-m.de>
On Sat, Oct 1, 2011 at 3:33 AM, Hauke Mehrtens <hauke@hauke-m.de> wrote:
>
> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
Applied and pushed, thanks!
Luis
^ permalink raw reply
* Re: [PATCH] compat: add skb_tx_timestamp() and skb_defer_rx_timestamp()
From: Luis R. Rodriguez @ 2011-10-03 19:57 UTC (permalink / raw)
To: Hauke Mehrtens; +Cc: linux-wireless
In-Reply-To: <1317465174-2685-1-git-send-email-hauke@hauke-m.de>
On Sat, Oct 1, 2011 at 3:32 AM, Hauke Mehrtens <hauke@hauke-m.de> wrote:
> Just add an empty implementation of these functions to do the same as
> when timestamping is deactivated.
>
> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
Applied and pushed, thanks!
Luis
^ permalink raw reply
* Re: [RFC 5/6] ath9k: enable DFS pulse detection
From: Luis R. Rodriguez @ 2011-10-03 19:31 UTC (permalink / raw)
To: Christian Lamparter
Cc: Zefir Kurtisi, linux-wireless, ath9k-devel, kgiori, nbd
In-Reply-To: <201110032124.53937.chunkeey@googlemail.com>
On Mon, Oct 3, 2011 at 12:24 PM, Christian Lamparter
<chunkeey@googlemail.com> wrote:
> On Monday, October 03, 2011 08:27:39 PM Luis R. Rodriguez wrote:
>> On Mon, Oct 3, 2011 at 3:29 AM, Zefir Kurtisi <zefir.kurtisi@neratec.com> wrote:
>> >
>> > Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com>
>> > ---
>> > drivers/net/wireless/ath/ath9k/main.c | 12 ++++++++++++
>> > 1 files changed, 12 insertions(+), 0 deletions(-)
>> >
>> > diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
>> > index e8aeb98..5defebe 100644
>> > --- a/drivers/net/wireless/ath/ath9k/main.c
>> > +++ b/drivers/net/wireless/ath/ath9k/main.c
>> > @@ -344,6 +344,18 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
>> > "Unable to reset channel, reset status %d\n", r);
>> > goto out;
>> > }
>> > +#ifdef CONFIG_ATH9K_DFS
>> > + /**
>> > + * enable radar pulse detection
>> > + *
>> > + * TODO: do this only for DFS channels
>> > + */
>> > + ah->private_ops.set_radar_params(ah, &ah->radar_conf);
>> > + ath9k_hw_setrxfilter(ah,
>> > + ath9k_hw_getrxfilter(ah) | ATH9K_RX_FILTER_PHYRADAR);
>> > + ath_dbg(common, ATH_DBG_DFS,
>> > + "DFS enabled for channel %d\n", hchan->chan->center_freq);
>> > +#endif
>>
>> Please spare the #ifdef and just call something within dfs.c, then
>> dfs.h would wrap it to nothing if DFS is disabled.
> Why would anyone want to disable DFS driver support?
> I would say: drop the ifdefs altogether since DFS
> is and will be "required".
Because DFS requires to be properly tested before being enabled. You
may also want to simply disable DFS if you do not want to deal with
the regulatory test implications of having it enabled.
Luis
^ permalink raw reply
* Re: [RFC 5/6] ath9k: enable DFS pulse detection
From: Christian Lamparter @ 2011-10-03 19:24 UTC (permalink / raw)
To: Luis R. Rodriguez; +Cc: Zefir Kurtisi, linux-wireless, ath9k-devel, kgiori, nbd
In-Reply-To: <CAB=NE6VO4W=ZJcgb3G5Gh=YM-jdkJ3ey5Ppka2Rn0XGmpx8=Gg@mail.gmail.com>
On Monday, October 03, 2011 08:27:39 PM Luis R. Rodriguez wrote:
> On Mon, Oct 3, 2011 at 3:29 AM, Zefir Kurtisi <zefir.kurtisi@neratec.com> wrote:
> >
> > Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com>
> > ---
> > drivers/net/wireless/ath/ath9k/main.c | 12 ++++++++++++
> > 1 files changed, 12 insertions(+), 0 deletions(-)
> >
> > diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
> > index e8aeb98..5defebe 100644
> > --- a/drivers/net/wireless/ath/ath9k/main.c
> > +++ b/drivers/net/wireless/ath/ath9k/main.c
> > @@ -344,6 +344,18 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
> > "Unable to reset channel, reset status %d\n", r);
> > goto out;
> > }
> > +#ifdef CONFIG_ATH9K_DFS
> > + /**
> > + * enable radar pulse detection
> > + *
> > + * TODO: do this only for DFS channels
> > + */
> > + ah->private_ops.set_radar_params(ah, &ah->radar_conf);
> > + ath9k_hw_setrxfilter(ah,
> > + ath9k_hw_getrxfilter(ah) | ATH9K_RX_FILTER_PHYRADAR);
> > + ath_dbg(common, ATH_DBG_DFS,
> > + "DFS enabled for channel %d\n", hchan->chan->center_freq);
> > +#endif
>
> Please spare the #ifdef and just call something within dfs.c, then
> dfs.h would wrap it to nothing if DFS is disabled.
Why would anyone want to disable DFS driver support?
I would say: drop the ifdefs altogether since DFS
is and will be "required".
Regards,
Chr
^ permalink raw reply
* Compat-wireless release for 2011-10-03 is baked
From: Compat-wireless cronjob account @ 2011-10-03 19:02 UTC (permalink / raw)
To: linux-wireless
/usr/bin/sha1sum: *.tar.bz2: No such file or directory
compat-wireless code metrics
813049 - Total upstream lines of code being pulled
^ permalink raw reply
* Re: [RFC 6/6] ath9k: handle pulse data reported by DFS HW
From: Luis R. Rodriguez @ 2011-10-03 18:30 UTC (permalink / raw)
To: Zefir Kurtisi; +Cc: linux-wireless, ath9k-devel, kgiori, nbd
In-Reply-To: <1317637758-11907-7-git-send-email-zefir.kurtisi@neratec.com>
On Mon, Oct 3, 2011 at 3:29 AM, Zefir Kurtisi <zefir.kurtisi@neratec.com> wrote:
> Note: calculation of mactime had to be shifted before
> ath9k_rx_skb_preprocess() since it is used to time-stamp the
> radar pulse.
Do this in a separate patch and provide a valid commit log here of
what the addition actually does. As I see it you can unify the last
set of patches together. The debugfs stuff can be kept apart though
but with the considerations I mentioned.
Luis
^ permalink raw reply
* Re: [RFC 2/6] ath9k: add DFS debug flag
From: Luis R. Rodriguez @ 2011-10-03 18:15 UTC (permalink / raw)
To: Zefir Kurtisi; +Cc: linux-wireless, ath9k-devel, kgiori, nbd
In-Reply-To: <1317637758-11907-3-git-send-email-zefir.kurtisi@neratec.com>
T24gTW9uLCBPY3QgMywgMjAxMSBhdCAzOjI5IEFNLCBaZWZpciBLdXJ0aXNpIDx6ZWZpci5rdXJ0
aXNpQG5lcmF0ZWMuY29tPiB3cm90ZToKPgo+IFNpZ25lZC1vZmYtYnk6IFplZmlyIEt1cnRpc2kg
PHplZmlyLmt1cnRpc2lAbmVyYXRlYy5jb20+Cj4gLS0tCj4gwqBkcml2ZXJzL25ldC93aXJlbGVz
cy9hdGgvYXRoLmggfCDCoCAzNCArKysrKysrKysrKysrKysrKystLS0tLS0tLS0tLS0tLS0tCj4g
wqAxIGZpbGVzIGNoYW5nZWQsIDE4IGluc2VydGlvbnMoKyksIDE2IGRlbGV0aW9ucygtKQo+Cj4g
ZGlmZiAtLWdpdCBhL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2F0aC9hdGguaCBiL2RyaXZlcnMvbmV0
L3dpcmVsZXNzL2F0aC9hdGguaAo+IGluZGV4IDZkNTY1MzIuLjM0ZDRkYTEgMTAwNjQ0Cj4gLS0t
IGEvZHJpdmVycy9uZXQvd2lyZWxlc3MvYXRoL2F0aC5oCj4gKysrIGIvZHJpdmVycy9uZXQvd2ly
ZWxlc3MvYXRoL2F0aC5oCj4gQEAgLTIxMSw2ICsyMTEsNyBAQCBhdGhfcHJpbnRrKGNvbnN0IGNo
YXIgKmxldmVsLCBzdHJ1Y3QgYXRoX2NvbW1vbiAqY29tbW9uLCBjb25zdCBjaGFyICpmbXQsIC4u
Lik7Cj4gwqAqIEBBVEhfREJHX0hXVElNRVI6IGhhcmR3YXJlIHRpbWVyIGhhbmRsaW5nCj4gwqAq
IEBBVEhfREJHX0JUQ09FWDogYmx1ZXRvb3RoIGNvZXhpc3RhbmNlCj4gwqAqIEBBVEhfREJHX0JT
VFVDSzogc3R1Y2sgYmVhY29ucwo+ICsgKiBAQVRIX0RCR19ERlM6IHJhZGFyIGRhdGVjdGlvbgo+
IMKgKiBAQVRIX0RCR19BTlk6IGVuYWJsZSBhbGwgZGVidWdnaW5nCj4gwqAqCj4gwqAqIFRoZSBk
ZWJ1ZyBsZXZlbCBpcyB1c2VkIHRvIGNvbnRyb2wgdGhlIGFtb3VudCBhbmQgdHlwZSBvZiBkZWJ1
Z2dpbmcgb3V0cHV0Cj4gQEAgLTIyMCwyMiArMjIxLDIzIEBAIGF0aF9wcmludGsoY29uc3QgY2hh
ciAqbGV2ZWwsIHN0cnVjdCBhdGhfY29tbW9uICpjb21tb24sIGNvbnN0IGNoYXIgKmZtdCwgLi4u
KTsKPiDCoCogZW50cnkuCj4gwqAqLwo+IMKgZW51bSBBVEhfREVCVUcgewo+IC0gwqAgwqAgwqAg
QVRIX0RCR19SRVNFVCDCoCDCoCDCoCDCoCDCoCA9IDB4MDAwMDAwMDEsCj4gLSDCoCDCoCDCoCBB
VEhfREJHX1FVRVVFIMKgIMKgIMKgIMKgIMKgID0gMHgwMDAwMDAwMiwKPiAtIMKgIMKgIMKgIEFU
SF9EQkdfRUVQUk9NIMKgIMKgIMKgIMKgIMKgPSAweDAwMDAwMDA0LAo+IC0gwqAgwqAgwqAgQVRI
X0RCR19DQUxJQlJBVEUgwqAgwqAgwqAgPSAweDAwMDAwMDA4LAo+IC0gwqAgwqAgwqAgQVRIX0RC
R19JTlRFUlJVUFQgwqAgwqAgwqAgPSAweDAwMDAwMDEwLAo+IC0gwqAgwqAgwqAgQVRIX0RCR19S
RUdVTEFUT1JZIMKgIMKgIMKgPSAweDAwMDAwMDIwLAo+IC0gwqAgwqAgwqAgQVRIX0RCR19BTkkg
wqAgwqAgwqAgwqAgwqAgwqAgPSAweDAwMDAwMDQwLAo+IC0gwqAgwqAgwqAgQVRIX0RCR19YTUlU
IMKgIMKgIMKgIMKgIMKgIMKgPSAweDAwMDAwMDgwLAo+IC0gwqAgwqAgwqAgQVRIX0RCR19CRUFD
T04gwqAgwqAgwqAgwqAgwqA9IDB4MDAwMDAxMDAsCj4gLSDCoCDCoCDCoCBBVEhfREJHX0NPTkZJ
RyDCoCDCoCDCoCDCoCDCoD0gMHgwMDAwMDIwMCwKPiAtIMKgIMKgIMKgIEFUSF9EQkdfRkFUQUwg
wqAgwqAgwqAgwqAgwqAgPSAweDAwMDAwNDAwLAo+IC0gwqAgwqAgwqAgQVRIX0RCR19QUyDCoCDC
oCDCoCDCoCDCoCDCoCDCoD0gMHgwMDAwMDgwMCwKPiAtIMKgIMKgIMKgIEFUSF9EQkdfSFdUSU1F
UiDCoCDCoCDCoCDCoCA9IDB4MDAwMDEwMDAsCj4gLSDCoCDCoCDCoCBBVEhfREJHX0JUQ09FWCDC
oCDCoCDCoCDCoCDCoD0gMHgwMDAwMjAwMCwKPiAtIMKgIMKgIMKgIEFUSF9EQkdfV01JIMKgIMKg
IMKgIMKgIMKgIMKgID0gMHgwMDAwNDAwMCwKPiAtIMKgIMKgIMKgIEFUSF9EQkdfQlNUVUNLIMKg
IMKgIMKgIMKgIMKgPSAweDAwMDA4MDAwLAo+ICsgwqAgwqAgwqAgQVRIX0RCR19SRVNFVCDCoCDC
oCDCoCDCoCDCoCA9IEJJVCgwKSwKPiArIMKgIMKgIMKgIEFUSF9EQkdfUVVFVUUgwqAgwqAgwqAg
wqAgwqAgPSBCSVQoMSksCj4gKyDCoCDCoCDCoCBBVEhfREJHX0VFUFJPTSDCoCDCoCDCoCDCoCDC
oD0gQklUKDIpLAo+ICsgwqAgwqAgwqAgQVRIX0RCR19DQUxJQlJBVEUgwqAgwqAgwqAgPSBCSVQo
MyksCj4gKyDCoCDCoCDCoCBBVEhfREJHX0lOVEVSUlVQVCDCoCDCoCDCoCA9IEJJVCg0KSwKPiAr
IMKgIMKgIMKgIEFUSF9EQkdfUkVHVUxBVE9SWSDCoCDCoCDCoD0gQklUKDUpLAo+ICsgwqAgwqAg
wqAgQVRIX0RCR19BTkkgwqAgwqAgwqAgwqAgwqAgwqAgPSBCSVQoNiksCj4gKyDCoCDCoCDCoCBB
VEhfREJHX1hNSVQgwqAgwqAgwqAgwqAgwqAgwqA9IEJJVCg3KSwKPiArIMKgIMKgIMKgIEFUSF9E
QkdfQkVBQ09OIMKgIMKgIMKgIMKgIMKgPSBCSVQoOCksCj4gKyDCoCDCoCDCoCBBVEhfREJHX0NP
TkZJRyDCoCDCoCDCoCDCoCDCoD0gQklUKDkpLAo+ICsgwqAgwqAgwqAgQVRIX0RCR19GQVRBTCDC
oCDCoCDCoCDCoCDCoCA9IEJJVCgxMCksCj4gKyDCoCDCoCDCoCBBVEhfREJHX1BTIMKgIMKgIMKg
IMKgIMKgIMKgIMKgPSBCSVQoMTEpLAo+ICsgwqAgwqAgwqAgQVRIX0RCR19IV1RJTUVSIMKgIMKg
IMKgIMKgID0gQklUKDEyKSwKPiArIMKgIMKgIMKgIEFUSF9EQkdfQlRDT0VYIMKgIMKgIMKgIMKg
IMKgPSBCSVQoMTMpLAo+ICsgwqAgwqAgwqAgQVRIX0RCR19XTUkgwqAgwqAgwqAgwqAgwqAgwqAg
PSBCSVQoMTQpLAo+ICsgwqAgwqAgwqAgQVRIX0RCR19CU1RVQ0sgwqAgwqAgwqAgwqAgwqA9IEJJ
VCgxNSksCj4gKyDCoCDCoCDCoCBBVEhfREJHX0RGUyDCoCDCoCDCoCDCoCDCoCDCoCA9IEJJVCgx
NiksCj4gwqAgwqAgwqAgwqBBVEhfREJHX0FOWSDCoCDCoCDCoCDCoCDCoCDCoCA9IDB4ZmZmZmZm
ZmYKClNwbGl0IHRoaXMgaW50byB0d28gcGF0Y2hlcywgb25lIHRvIGNvbnZlcnQgc3R1ZmYgdG8g
QklUKGZvbykgYW5kIHRoZQpvdGhlciBvbmUgdG8gYWRkIEFUSF9EQkdfREZTCgogIEx1aXMK
^ permalink raw reply
* Re: [RFC 1/6] ath9k: add DFS statistics to debugfs
From: Luis R. Rodriguez @ 2011-10-03 18:14 UTC (permalink / raw)
To: Zefir Kurtisi; +Cc: linux-wireless, ath9k-devel, kgiori, nbd
In-Reply-To: <1317637758-11907-2-git-send-email-zefir.kurtisi@neratec.com>
On Mon, Oct 3, 2011 at 3:29 AM, Zefir Kurtisi <zefir.kurtisi@neratec.com> wrote:
>
> Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com>
> ---
> drivers/net/wireless/ath/ath9k/debug.c | 51 ++++++++++++++++++++++++++++++++
> drivers/net/wireless/ath/ath9k/debug.h | 29 ++++++++++++++++++
> 2 files changed, 80 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
> index cdece82..6ad2266 100644
> --- a/drivers/net/wireless/ath/ath9k/debug.c
> +++ b/drivers/net/wireless/ath/ath9k/debug.c
> @@ -89,6 +89,53 @@ static const struct file_operations fops_debug = {
>
> #endif
>
> +
> +#ifdef CONFIG_ATH9K_DFS
This kconfig entry doesn't exist yet, so no point in referring to it
yet, you can add a patch that adds this but describe it as work in
progress or something like that and later correct the text as you move
on.
> +
> +#define DFS_STAT(s, p) \
> + len += snprintf(buf + len, size - len, "%28s : %10u\n", s, \
> + sc->debug.stats.dfs_stats.p);
> +
Either rename DFS_STAT to ATH9K_DFS_STAT or undef DFS_STAT after its usage.
> +static ssize_t read_file_dfs(struct file *file, char __user *user_buf,
> + size_t count, loff_t *ppos)
> +{
> + struct ath_softc *sc = file->private_data;
> + char *buf;
> + unsigned int len = 0, size = 8000;
> + ssize_t retval = 0;
> +
> + buf = kzalloc(size, GFP_KERNEL);
> + if (buf == NULL)
> + return -ENOMEM;
> +
> + DFS_STAT("DFS pulses detected ", pulses_detected);
> + DFS_STAT("Datalen discards ", datalen_discards);
> + DFS_STAT("RSSI discards ", rssi_discards);
> + DFS_STAT("BW info discards ", bwinfo_discards);
> + DFS_STAT("Primary channel pulses ", pri_phy_errors);
> + DFS_STAT("Secondary channel pulses", ext_phy_errors);
> + DFS_STAT("Dual channel pulses ", dc_phy_errors);
> +
> + if (len > size)
> + len = size;
> +
> + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
> + kfree(buf);
> +
> + return retval;
> +}
> +
> +
> +static const struct file_operations fops_dfs_stats = {
> + .read = read_file_dfs,
> + .open = ath9k_debugfs_open,
> + .owner = THIS_MODULE,
> + .llseek = default_llseek,
> +};
> +#endif /* CONFIG_ATH9K_DFS */
I'd prefer to keep this apart into a debugfs_dfs.c but that's just me,
I would like to ensure to keep *all* DFS stat as easy to review as
possible and am not a fan of the ifdef sprinkle.
> +
> +
> #define DMA_BUF_LEN 1024
>
> static ssize_t read_file_tx_chainmask(struct file *file, char __user *user_buf,
> @@ -1385,6 +1432,10 @@ int ath9k_init_debug(struct ath_hw *ah)
> debugfs_create_u32("chanbw", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
> &sc->chan_bw);
>
> +#ifdef CONFIG_ATH9K_DFS
> + debugfs_create_file("dfs_stats", S_IRUSR, sc->debug.debugfs_phy, sc,
> + &fops_dfs_stats);
> +#endif
If you stuff the code into a file here you'd just need a caller to
ath9k_debugfs_dfs_create() or something like that.
> sc->debug.regidx = 0;
> return 0;
> }
> diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
> index 4a04510..3a3c3b7 100644
> --- a/drivers/net/wireless/ath/ath9k/debug.h
> +++ b/drivers/net/wireless/ath/ath9k/debug.h
> @@ -25,8 +25,10 @@ struct ath_buf;
>
> #ifdef CONFIG_ATH9K_DEBUGFS
> #define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++
> +#define DFS_STAT_INC(sc, c) (sc->debug.stats.dfs_stats.c++)
> #else
> #define TX_STAT_INC(q, c) do { } while (0)
> +#define DFS_STAT_INC(sc, c) do { } while (0)
Who's using this? If no one, then why add it? That is add it only when
its in code.
> #endif
>
> #ifdef CONFIG_ATH9K_DEBUGFS
> @@ -171,10 +173,37 @@ struct ath_rx_stats {
> u8 rs_antenna;
> };
>
> +#ifdef CONFIG_ATH9K_DFS
> +/**
> + * struct ath_dfs_stats - DFS Statistics
> + *
> + * @pulses_detected: No. of pulses detected so far
> + * @datalen_discards: No. of pulses discarded due to invalid datalen
> + * @rssi_discards: No. of pulses discarded due to invalid RSSI
> + * @bwinfo_discards: No. of pulses discarded due to invalid BW info
> + * @pri_phy_errors: No. of pulses reported for primary channel
> + * @ext_phy_errors: No. of pulses reported for extension channel
> + * @dc_phy_errors: No. of pulses reported for primary + extension channel
> + */
> +struct ath_dfs_stats {
> + u32 pulses_detected;
> + u32 datalen_discards;
> + u32 rssi_discards;
> + u32 bwinfo_discards;
> + u32 pri_phy_errors;
> + u32 ext_phy_errors;
> + u32 dc_phy_errors;
> +};
> +#endif
> +
> +
> struct ath_stats {
> struct ath_interrupt_stats istats;
> struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES];
> struct ath_rx_stats rxstats;
> +#ifdef CONFIG_ATH9K_DFS
> + struct ath_dfs_stats dfs_stats;
> +#endif
If code used this set of stats this would give a compile error if
CONFIG_ATH9K_DEBUGFS is enabled but CONFIG_ATH9K_DFS was disabled as
the ifdef over the increment stat stuff is over CONFIG_ATH9K_DEBUGFS
and not CONFIG_ATH9K_DFS, but again, no one uses this code yet.
Luis
^ permalink raw reply
* Re: [RFC 5/6] ath9k: enable DFS pulse detection
From: Luis R. Rodriguez @ 2011-10-03 18:27 UTC (permalink / raw)
To: Zefir Kurtisi; +Cc: linux-wireless, ath9k-devel, kgiori, nbd
In-Reply-To: <1317637758-11907-6-git-send-email-zefir.kurtisi@neratec.com>
On Mon, Oct 3, 2011 at 3:29 AM, Zefir Kurtisi <zefir.kurtisi@neratec.com> wrote:
>
> Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com>
> ---
> drivers/net/wireless/ath/ath9k/main.c | 12 ++++++++++++
> 1 files changed, 12 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
> index e8aeb98..5defebe 100644
> --- a/drivers/net/wireless/ath/ath9k/main.c
> +++ b/drivers/net/wireless/ath/ath9k/main.c
> @@ -344,6 +344,18 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
> "Unable to reset channel, reset status %d\n", r);
> goto out;
> }
> +#ifdef CONFIG_ATH9K_DFS
> + /**
> + * enable radar pulse detection
> + *
> + * TODO: do this only for DFS channels
> + */
> + ah->private_ops.set_radar_params(ah, &ah->radar_conf);
> + ath9k_hw_setrxfilter(ah,
> + ath9k_hw_getrxfilter(ah) | ATH9K_RX_FILTER_PHYRADAR);
> + ath_dbg(common, ATH_DBG_DFS,
> + "DFS enabled for channel %d\n", hchan->chan->center_freq);
> +#endif
Please spare the #ifdef and just call something within dfs.c, then
dfs.h would wrap it to nothing if DFS is disabled.
Luis
^ permalink raw reply
* Re: [RFC 4/6] ath9k: add DFS build parameter
From: Luis R. Rodriguez @ 2011-10-03 18:26 UTC (permalink / raw)
To: Zefir Kurtisi; +Cc: linux-wireless, ath9k-devel, kgiori, nbd
In-Reply-To: <1317637758-11907-5-git-send-email-zefir.kurtisi@neratec.com>
On Mon, Oct 3, 2011 at 3:29 AM, Zefir Kurtisi <zefir.kurtisi@neratec.com> wrote:
>
> Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com>
> ---
> drivers/net/wireless/ath/ath9k/Kconfig | 7 +++++++
> drivers/net/wireless/ath/ath9k/Makefile | 2 ++
> 2 files changed, 9 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
> index d9c08c6..adddcca 100644
> --- a/drivers/net/wireless/ath/ath9k/Kconfig
> +++ b/drivers/net/wireless/ath/ath9k/Kconfig
> @@ -58,6 +58,13 @@ config ATH9K_RATE_CONTROL
> Say Y, if you want to use the ath9k specific rate control
> module instead of minstrel_ht.
>
> +config ATH9K_DFS
> + bool "Atheros ath9k DFS support"
> + depends on ATH9K
> + default y
At this point selecting y does nothing. Leave this patch out until
selecting "y" means something.
Default should be n, and in particular Atheros itself can only likely
commit to supporting DFS for AR9003 when it finds resources to do so
as well as properly test it, so DFS support kconfig should state this.
If someone wants to step up to completely support all bugs for older
families that is their prerogative but we cannot commit to it, due to
the regulatory considerations though unless this happens this cannot
and should not be enabled for older families in code.
Luis
^ permalink raw reply
* Linux wireless in android phones
From: Andrés García Saavedra @ 2011-10-03 15:56 UTC (permalink / raw)
To: linux-wireless
i all,
I am working on some driver modifications (mac80211/ath5k open source
driver currently) in order to implement customized algorithms (setting
IE parameters within beacon frames, etc) on a WiFiDirect wireless
network.
I was wondering whether there existed any android phone using (open
source) customizable driver from the linux wireless stack, so I could
test on real mobile devices. Has somebody worked on these platforms?
Thanks in advance,
Andrés
^ permalink raw reply
* RE: [PATCH 4/5] ath6kl: Fix possible race in accessing bounce buffer
From: Thiagarajan, Vasanthakumar @ 2011-10-03 15:52 UTC (permalink / raw)
To: Valo, Kalle; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <1317390526-3442-4-git-send-email-vthiagar@qca.qualcomm.com>
________________________________________
From: Thiagarajan, Vasanthakumar
Sent: Friday, September 30, 2011 7:18 PM
To: Valo, Kalle
Cc: linux-wireless@vger.kernel.org
Subject: [PATCH 4/5] ath6kl: Fix possible race in accessing bounce buffer
There is only one bounce buffer (ar_sdio->dma_buffer) which is used
for both read and write without any protection. Fix this race by
allocating bounce buffer every time when it is needed.
As I have never seen any race in bounce buffer practically during my testing,
this patch can be dropped instead of making the code complex for no reason.
Vasanth
^ permalink raw reply
* Re: [RFC 3/6] ath9k: initial radar pulse detection for DFS
From: Adrian Chadd @ 2011-10-03 14:23 UTC (permalink / raw)
To: Zefir Kurtisi; +Cc: linux-wireless, ath9k-devel, kgiori, rodrigue, nbd
In-Reply-To: <4E89C4F1.2090708@neratec.com>
On 3 October 2011 22:21, Zefir Kurtisi <zefir.kurtisi@neratec.com> wrote:
> Most probably it'll end being added to the lengthy TODO list.
:) No worries. I've just added the freebsd version of this to
FreeBSD-HEAD. I'll add in the duration calculation function soon.
Now all we need is an ISC/GPL dual licenced packet classification
module. *wink* :)
Adrian
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox