2016-10-31 08:02:32

by Xinming Hu

[permalink] [raw]
Subject: [PATCH 01/12] mwifiex: fix power save issue when suspend

From: Shengzhen Li <[email protected]>

This patch fixes a corner case for "FROMLIST: mwifiex: fix corner case
power save issue", main process will check the power save condition in
PS_PRE_SLEEP status so the sleep handshake could continue.

Signed-off-by: Cathy Luo <[email protected]>
Signed-off-by: Shengzhen Li <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>

BUG=chrome-os-partner:58164
TEST=stress Wifi w/ power_save enabled

Change-Id: I5a36d9eaeb7fe5faaccc533e0d1ba1f3253666dc
---
drivers/net/wireless/marvell/mwifiex/cmdevt.c | 3 ++-
drivers/net/wireless/marvell/mwifiex/main.c | 5 +++++
2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
index 5347728..9075be5 100644
--- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
@@ -1123,8 +1123,9 @@ mwifiex_check_ps_cond(struct mwifiex_adapter *adapter)
mwifiex_dnld_sleep_confirm_cmd(adapter);
else
mwifiex_dbg(adapter, CMD,
- "cmd: Delay Sleep Confirm (%s%s%s)\n",
+ "cmd: Delay Sleep Confirm (%s%s%s%s)\n",
(adapter->cmd_sent) ? "D" : "",
+ (adapter->data_sent) ? "T" : "",
(adapter->curr_cmd) ? "C" : "",
(IS_CARD_RX_RCVD(adapter)) ? "R" : "");
}
diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c
index 2478ccd..f559ead 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.c
+++ b/drivers/net/wireless/marvell/mwifiex/main.c
@@ -308,6 +308,11 @@ process_start:
/* We have tried to wakeup the card already */
if (adapter->pm_wakeup_fw_try)
break;
+ if (adapter->ps_state == PS_STATE_PRE_SLEEP) {
+ if (!adapter->cmd_sent && !adapter->curr_cmd)
+ mwifiex_check_ps_cond(adapter);
+ }
+
if (adapter->ps_state != PS_STATE_AWAKE)
break;
if (adapter->tx_lock_flag) {
--
1.8.1.4


2016-10-31 08:02:42

by Xinming Hu

[permalink] [raw]
Subject: [PATCH 04/12] mwifiex: resolve races between async FW init (failure) and device removal

From: Brian Norris <[email protected]>

It's possible for the FW init sequence to fail, which will trigger a
device cleanup sequence in mwifiex_fw_dpc(). This sequence can race with
device suspend() or remove() (e.g., reboot or unbind), and can trigger
use-after-free issues. Currently, this driver attempts (poorly) to
synchronize remove() using a semaphore, but it doesn't protect some of
the critical sections properly. Particularly, we grab a pointer to the
adapter struct (card->adapter) without checking if it's being freed or
not. We later do a NULL check on the adapter, but that doesn't work if
the adapter was freed.

Also note that the PCIe interface driver doesn't ever set card->adapter
to NULL, so even if we get the synchronization right, we still might try
to redo the cleanup in ->remove(), even if the FW init failure sequence
already did it.

This patch replaces the static semaphore with a per-device completion
struct, and uses that completion to synchronize the remove() thread with
the mwifiex_fw_dpc(). A future patch will utilize this completion to
synchronize the suspend() thread as well.

Signed-off-by: Brian Norris <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/main.c | 46 ++++++++++-------------------
drivers/net/wireless/marvell/mwifiex/main.h | 10 +++++--
drivers/net/wireless/marvell/mwifiex/pcie.c | 18 +++++------
drivers/net/wireless/marvell/mwifiex/pcie.h | 2 ++
drivers/net/wireless/marvell/mwifiex/sdio.c | 18 +++++------
drivers/net/wireless/marvell/mwifiex/sdio.h | 2 ++
drivers/net/wireless/marvell/mwifiex/usb.c | 23 +++++++--------
drivers/net/wireless/marvell/mwifiex/usb.h | 2 ++
8 files changed, 53 insertions(+), 68 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c
index f559ead..206be45 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.c
+++ b/drivers/net/wireless/marvell/mwifiex/main.c
@@ -525,7 +525,6 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
struct mwifiex_private *priv;
struct mwifiex_adapter *adapter = context;
struct mwifiex_fw_image fw;
- struct semaphore *sem = adapter->card_sem;
bool init_failed = false;
struct wireless_dev *wdev;

@@ -674,7 +673,8 @@ done:
}
if (init_failed)
mwifiex_free_adapter(adapter);
- up(sem);
+ /* Tell all current and future waiters we're finished */
+ complete_all(adapter->fw_done);
return;
}

@@ -1369,7 +1369,7 @@ static void mwifiex_main_work_queue(struct work_struct *work)
* code is extracted from mwifiex_remove_card()
*/
static int
-mwifiex_shutdown_sw(struct mwifiex_adapter *adapter, struct semaphore *sem)
+mwifiex_shutdown_sw(struct mwifiex_adapter *adapter)
{
struct mwifiex_private *priv;
int i;
@@ -1377,8 +1377,9 @@ mwifiex_shutdown_sw(struct mwifiex_adapter *adapter, struct semaphore *sem)
if (!adapter)
goto exit_return;

- if (down_interruptible(sem))
- goto exit_sem_err;
+ wait_for_completion(adapter->fw_done);
+ /* Caller should ensure we aren't suspending while this happens */
+ reinit_completion(adapter->fw_done);

priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
mwifiex_deauthenticate(priv, NULL);
@@ -1435,8 +1436,6 @@ mwifiex_shutdown_sw(struct mwifiex_adapter *adapter, struct semaphore *sem)
rtnl_unlock();
}

- up(sem);
-exit_sem_err:
mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
exit_return:
return 0;
@@ -1446,21 +1445,18 @@ exit_return:
* code is extracted from mwifiex_add_card()
*/
static int
-mwifiex_reinit_sw(struct mwifiex_adapter *adapter, struct semaphore *sem,
+mwifiex_reinit_sw(struct mwifiex_adapter *adapter, struct completion *fw_done,
struct mwifiex_if_ops *if_ops, u8 iface_type)
{
char fw_name[32];
struct pcie_service_card *card = adapter->card;

- if (down_interruptible(sem))
- goto exit_sem_err;
-
mwifiex_init_lock_list(adapter);
if (adapter->if_ops.up_dev)
adapter->if_ops.up_dev(adapter);

adapter->iface_type = iface_type;
- adapter->card_sem = sem;
+ adapter->fw_done = fw_done;

adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
adapter->surprise_removed = false;
@@ -1511,7 +1507,8 @@ mwifiex_reinit_sw(struct mwifiex_adapter *adapter, struct semaphore *sem,
}
strcpy(adapter->fw_name, fw_name);
mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
- up(sem);
+
+ complete_all(adapter->fw_done);
return 0;

err_init_fw:
@@ -1531,8 +1528,7 @@ err_init_fw:
err_kmalloc:
mwifiex_terminate_workqueue(adapter);
adapter->surprise_removed = true;
- up(sem);
-exit_sem_err:
+ complete_all(adapter->fw_done);
mwifiex_dbg(adapter, INFO, "%s, error\n", __func__);

return -1;
@@ -1547,12 +1543,12 @@ void mwifiex_do_flr(struct mwifiex_adapter *adapter, bool prepare)
struct mwifiex_if_ops if_ops;

if (!prepare) {
- mwifiex_reinit_sw(adapter, adapter->card_sem, &if_ops,
+ mwifiex_reinit_sw(adapter, adapter->fw_done, &if_ops,
adapter->iface_type);
} else {
memcpy(&if_ops, &adapter->if_ops,
sizeof(struct mwifiex_if_ops));
- mwifiex_shutdown_sw(adapter, adapter->card_sem);
+ mwifiex_shutdown_sw(adapter);
}
}
EXPORT_SYMBOL_GPL(mwifiex_do_flr);
@@ -1571,21 +1567,18 @@ EXPORT_SYMBOL_GPL(mwifiex_do_flr);
* - Add logical interfaces
*/
int
-mwifiex_add_card(void *card, struct semaphore *sem,
+mwifiex_add_card(void *card, struct completion *fw_done,
struct mwifiex_if_ops *if_ops, u8 iface_type)
{
struct mwifiex_adapter *adapter;

- if (down_interruptible(sem))
- goto exit_sem_err;
-
if (mwifiex_register(card, if_ops, (void **)&adapter)) {
pr_err("%s: software init failed\n", __func__);
goto err_init_sw;
}

adapter->iface_type = iface_type;
- adapter->card_sem = sem;
+ adapter->fw_done = fw_done;

adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
adapter->surprise_removed = false;
@@ -1654,9 +1647,7 @@ err_kmalloc:
mwifiex_free_adapter(adapter);

err_init_sw:
- up(sem);

-exit_sem_err:
return -1;
}
EXPORT_SYMBOL_GPL(mwifiex_add_card);
@@ -1672,14 +1663,11 @@ EXPORT_SYMBOL_GPL(mwifiex_add_card);
* - Unregister the device
* - Free the adapter structure
*/
-int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
+int mwifiex_remove_card(struct mwifiex_adapter *adapter)
{
struct mwifiex_private *priv = NULL;
int i;

- if (down_trylock(sem))
- goto exit_sem_err;
-
if (!adapter)
goto exit_remove;

@@ -1749,8 +1737,6 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
mwifiex_free_adapter(adapter);

exit_remove:
- up(sem);
-exit_sem_err:
return 0;
}
EXPORT_SYMBOL_GPL(mwifiex_remove_card);
diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h
index 7f67f23..bbd8d63 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.h
+++ b/drivers/net/wireless/marvell/mwifiex/main.h
@@ -20,6 +20,7 @@
#ifndef _MWIFIEX_MAIN_H_
#define _MWIFIEX_MAIN_H_

+#include <linux/completion.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
@@ -985,7 +986,10 @@ struct mwifiex_adapter {
u32 usr_dot_11ac_mcs_support;

atomic_t pending_bridged_pkts;
- struct semaphore *card_sem;
+
+ /* For synchronizing FW initialization with device lifecycle. */
+ struct completion *fw_done;
+
bool ext_scan;
u8 fw_api_ver;
u8 key_api_major_ver, key_api_minor_ver;
@@ -1413,8 +1417,8 @@ static inline u8 mwifiex_is_tdls_link_setup(u8 status)

int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
u32 func_init_shutdown);
-int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8);
-int mwifiex_remove_card(struct mwifiex_adapter *, struct semaphore *);
+int mwifiex_add_card(void *, struct completion *, struct mwifiex_if_ops *, u8);
+int mwifiex_remove_card(struct mwifiex_adapter *);

void mwifiex_get_version(struct mwifiex_adapter *adapter, char *version,
int maxlen);
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index e6bea02..5507c89 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -35,8 +35,6 @@ static u8 user_rmmod;

static struct mwifiex_if_ops pcie_ops;

-static struct semaphore add_remove_card_sem;
-
static int
mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
size_t size, int flags)
@@ -193,6 +191,8 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
if (!card)
return -ENOMEM;

+ init_completion(&card->fw_done);
+
card->dev = pdev;

if (ent->driver_data) {
@@ -206,7 +206,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
card->pcie.can_ext_scan = data->can_ext_scan;
}

- if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops,
+ if (mwifiex_add_card(card, &card->fw_done, &pcie_ops,
MWIFIEX_PCIE)) {
pr_err("%s failed\n", __func__);
return -1;
@@ -228,6 +228,8 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
if (!card)
return;

+ wait_for_completion(&card->fw_done);
+
adapter = card->adapter;
if (!adapter || !adapter->priv_num)
return;
@@ -247,7 +249,7 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
mwifiex_init_shutdown_fw(priv, MWIFIEX_FUNC_SHUTDOWN);
}

- mwifiex_remove_card(card->adapter, &add_remove_card_sem);
+ mwifiex_remove_card(adapter);
}

static void mwifiex_pcie_shutdown(struct pci_dev *pdev)
@@ -3151,8 +3153,7 @@ static struct mwifiex_if_ops pcie_ops = {
/*
* This function initializes the PCIE driver module.
*
- * This initiates the semaphore and registers the device with
- * PCIE bus.
+ * This registers the device with PCIE bus.
*/
static int mwifiex_pcie_init_module(void)
{
@@ -3160,8 +3161,6 @@ static int mwifiex_pcie_init_module(void)

pr_debug("Marvell PCIe Driver\n");

- sema_init(&add_remove_card_sem, 1);
-
/* Clear the flag in case user removes the card. */
user_rmmod = 0;

@@ -3185,9 +3184,6 @@ static int mwifiex_pcie_init_module(void)
*/
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;

diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.h b/drivers/net/wireless/marvell/mwifiex/pcie.h
index 46f99ca..ae3365d 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.h
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.h
@@ -22,6 +22,7 @@
#ifndef _MWIFIEX_PCIE_H
#define _MWIFIEX_PCIE_H

+#include <linux/completion.h>
#include <linux/pci.h>
#include <linux/interrupt.h>

@@ -345,6 +346,7 @@ struct pcie_service_card {
struct pci_dev *dev;
struct mwifiex_adapter *adapter;
struct mwifiex_pcie_device pcie;
+ struct completion fw_done;

u8 txbd_flush;
u32 txbd_wrptr;
diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c
index f04cf5a..1f6ebde 100644
--- a/drivers/net/wireless/marvell/mwifiex/sdio.c
+++ b/drivers/net/wireless/marvell/mwifiex/sdio.c
@@ -49,8 +49,6 @@ static u8 user_rmmod;
static struct mwifiex_if_ops sdio_ops;
static unsigned long iface_work_flags;

-static struct semaphore add_remove_card_sem;
-
static struct memory_type_mapping generic_mem_type_map[] = {
{"DUMP", NULL, 0, 0xDD},
};
@@ -156,6 +154,8 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
if (!card)
return -ENOMEM;

+ init_completion(&card->fw_done);
+
card->func = func;
card->device_id = id;

@@ -197,7 +197,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
}
}

- ret = mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops,
+ ret = mwifiex_add_card(card, &card->fw_done, &sdio_ops,
MWIFIEX_SDIO);
if (ret) {
dev_err(&func->dev, "add card failed\n");
@@ -283,6 +283,8 @@ mwifiex_sdio_remove(struct sdio_func *func)
if (!card)
return;

+ wait_for_completion(&card->fw_done);
+
adapter = card->adapter;
if (!adapter || !adapter->priv_num)
return;
@@ -300,7 +302,7 @@ mwifiex_sdio_remove(struct sdio_func *func)
mwifiex_init_shutdown_fw(priv, MWIFIEX_FUNC_SHUTDOWN);
}

- mwifiex_remove_card(card->adapter, &add_remove_card_sem);
+ mwifiex_remove_card(adapter);
}

/*
@@ -2771,14 +2773,11 @@ static struct mwifiex_if_ops sdio_ops = {
/*
* This function initializes the SDIO driver.
*
- * This initiates the semaphore and registers the device with
- * SDIO bus.
+ * This registers the device with SDIO bus.
*/
static int
mwifiex_sdio_init_module(void)
{
- sema_init(&add_remove_card_sem, 1);
-
/* Clear the flag in case user removes the card. */
user_rmmod = 0;

@@ -2797,9 +2796,6 @@ mwifiex_sdio_init_module(void)
static void
mwifiex_sdio_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;
cancel_work_sync(&sdio_work);
diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.h b/drivers/net/wireless/marvell/mwifiex/sdio.h
index db837f1..cc0aac8 100644
--- a/drivers/net/wireless/marvell/mwifiex/sdio.h
+++ b/drivers/net/wireless/marvell/mwifiex/sdio.h
@@ -21,6 +21,7 @@
#define _MWIFIEX_SDIO_H


+#include <linux/completion.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio_func.h>
@@ -244,6 +245,7 @@ struct sdio_mmc_card {
struct mwifiex_adapter *adapter;
struct device_node *plt_of_node;
struct mwifiex_plt_wake_cfg *plt_wake_cfg;
+ struct completion fw_done;

const char *firmware;
const struct mwifiex_sdio_card_reg *reg;
diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c
index 57ed834..c20ff2f 100644
--- a/drivers/net/wireless/marvell/mwifiex/usb.c
+++ b/drivers/net/wireless/marvell/mwifiex/usb.c
@@ -24,7 +24,6 @@

static u8 user_rmmod;
static struct mwifiex_if_ops usb_ops;
-static struct semaphore add_remove_card_sem;

static struct usb_device_id mwifiex_usb_table[] = {
/* 8766 */
@@ -386,6 +385,8 @@ static int mwifiex_usb_probe(struct usb_interface *intf,
if (!card)
return -ENOMEM;

+ init_completion(&card->fw_done);
+
id_vendor = le16_to_cpu(udev->descriptor.idVendor);
id_product = le16_to_cpu(udev->descriptor.idProduct);
bcd_device = le16_to_cpu(udev->descriptor.bcdDevice);
@@ -475,7 +476,7 @@ static int mwifiex_usb_probe(struct usb_interface *intf,

usb_set_intfdata(intf, card);

- ret = mwifiex_add_card(card, &add_remove_card_sem, &usb_ops,
+ ret = mwifiex_add_card(card, &card->fw_done, &usb_ops,
MWIFIEX_USB);
if (ret) {
pr_err("%s: mwifiex_add_card failed: %d\n", __func__, ret);
@@ -601,13 +602,15 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf)
struct usb_card_rec *card = usb_get_intfdata(intf);
struct mwifiex_adapter *adapter;

- if (!card || !card->adapter) {
- pr_err("%s: card or card->adapter is NULL\n", __func__);
+ if (!card) {
+ dev_err(&intf->dev, "%s: card is NULL\n", __func__);
return;
}

+ wait_for_completion(&card->fw_done);
+
adapter = card->adapter;
- if (!adapter->priv_num)
+ if (!adapter || !adapter->priv_num)
return;

if (user_rmmod && !adapter->mfg_mode) {
@@ -627,7 +630,7 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf)

mwifiex_dbg(adapter, FATAL,
"%s: removing card\n", __func__);
- mwifiex_remove_card(adapter, &add_remove_card_sem);
+ mwifiex_remove_card(adapter);

usb_put_dev(interface_to_usbdev(intf));
}
@@ -1201,8 +1204,7 @@ static struct mwifiex_if_ops usb_ops = {

/* This function initializes the USB driver module.
*
- * This initiates the semaphore and registers the device with
- * USB bus.
+ * This registers the device with USB bus.
*/
static int mwifiex_usb_init_module(void)
{
@@ -1210,8 +1212,6 @@ static int mwifiex_usb_init_module(void)

pr_debug("Marvell USB8797 Driver\n");

- sema_init(&add_remove_card_sem, 1);
-
ret = usb_register(&mwifiex_usb_driver);
if (ret)
pr_err("Driver register failed!\n");
@@ -1231,9 +1231,6 @@ static int mwifiex_usb_init_module(void)
*/
static void mwifiex_usb_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;

diff --git a/drivers/net/wireless/marvell/mwifiex/usb.h b/drivers/net/wireless/marvell/mwifiex/usb.h
index 30e8eb8..e5f204e 100644
--- a/drivers/net/wireless/marvell/mwifiex/usb.h
+++ b/drivers/net/wireless/marvell/mwifiex/usb.h
@@ -20,6 +20,7 @@
#ifndef _MWIFIEX_USB_H
#define _MWIFIEX_USB_H

+#include <linux/completion.h>
#include <linux/usb.h>

#define USB8XXX_VID 0x1286
@@ -75,6 +76,7 @@ struct usb_card_rec {
struct mwifiex_adapter *adapter;
struct usb_device *udev;
struct usb_interface *intf;
+ struct completion fw_done;
u8 rx_cmd_ep;
struct urb_context rx_cmd;
atomic_t rx_cmd_urb_pending;
--
1.8.1.4

2016-10-31 08:03:05

by Xinming Hu

[permalink] [raw]
Subject: [PATCH 11/12] mwifiex: stop checking for NULL drvata/intfdata

From: Brian Norris <[email protected]>

These are never NULL, so stop making people think they might be.

I don't change this for SDIO because SDIO has a racy card-reset handler
that reallocates this struct. I'd rather not touch that mess right now.

Signed-off-by: Brian Norris <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/pcie.c | 14 +++++---------
drivers/net/wireless/marvell/mwifiex/usb.c | 15 +++------------
2 files changed, 8 insertions(+), 21 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 04b9961..c061d00 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -102,10 +102,6 @@ static int mwifiex_pcie_suspend(struct device *dev)
struct pci_dev *pdev = to_pci_dev(dev);

card = pci_get_drvdata(pdev);
- if (!card) {
- dev_err(dev, "adapter structure is not valid\n");
- return 0;
- }

/* Might still be loading firmware */
wait_for_completion(&card->fw_done);
@@ -148,8 +144,9 @@ static int mwifiex_pcie_resume(struct device *dev)
struct pci_dev *pdev = to_pci_dev(dev);

card = pci_get_drvdata(pdev);
- if (!card || !card->adapter) {
- dev_err(dev, "Card or adapter structure is not valid\n");
+
+ if (!card->adapter) {
+ dev_err(dev, "adapter structure is not valid\n");
return 0;
}

@@ -222,8 +219,6 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
struct mwifiex_private *priv;

card = pci_get_drvdata(pdev);
- if (!card)
- return;

wait_for_completion(&card->fw_done);

@@ -2216,7 +2211,8 @@ static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context)
}

card = pci_get_drvdata(pdev);
- if (!card || !card->adapter) {
+
+ if (!card->adapter) {
pr_err("info: %s: card=%p adapter=%p\n", __func__, card,
card ? card->adapter : NULL);
goto exit;
diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c
index c26daf4..78b46fa 100644
--- a/drivers/net/wireless/marvell/mwifiex/usb.c
+++ b/drivers/net/wireless/marvell/mwifiex/usb.c
@@ -503,11 +503,6 @@ static int mwifiex_usb_suspend(struct usb_interface *intf, pm_message_t message)
struct usb_tx_data_port *port;
int i, j;

- if (!card) {
- dev_err(&intf->dev, "%s: card is NULL\n", __func__);
- return 0;
- }
-
/* Might still be loading firmware */
wait_for_completion(&card->fw_done);

@@ -574,8 +569,9 @@ static int mwifiex_usb_resume(struct usb_interface *intf)
struct mwifiex_adapter *adapter;
int i;

- if (!card || !card->adapter) {
- pr_err("%s: card or card->adapter is NULL\n", __func__);
+ if (!card->adapter) {
+ dev_err(&intf->dev, "%s: card->adapter is NULL\n",
+ __func__);
return 0;
}
adapter = card->adapter;
@@ -617,11 +613,6 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf)
struct usb_card_rec *card = usb_get_intfdata(intf);
struct mwifiex_adapter *adapter;

- if (!card) {
- dev_err(&intf->dev, "%s: card is NULL\n", __func__);
- return;
- }
-
wait_for_completion(&card->fw_done);

adapter = card->adapter;
--
1.8.1.4

2016-10-31 08:02:51

by Xinming Hu

[permalink] [raw]
Subject: [PATCH 07/12] mwifiex: resolve suspend() race with async FW init failure

From: Brian Norris <[email protected]>

Signed-off-by: Brian Norris <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/pcie.c | 11 +++++++++--
drivers/net/wireless/marvell/mwifiex/sdio.c | 11 +++++++++--
drivers/net/wireless/marvell/mwifiex/usb.c | 12 ++++++++++--
3 files changed, 28 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 32fbb91..b635563 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -102,12 +102,19 @@ static int mwifiex_pcie_suspend(struct device *dev)
struct pci_dev *pdev = to_pci_dev(dev);

card = pci_get_drvdata(pdev);
- if (!card || !card->adapter) {
- pr_err("Card or adapter structure is not valid\n");
+ if (!card) {
+ dev_err(dev, "adapter structure is not valid\n");
return 0;
}

+ /* Might still be loading firmware */
+ wait_for_completion(&card->fw_done);
+
adapter = card->adapter;
+ if (!adapter) {
+ dev_err(dev, "card is not valid\n");
+ return 0;
+ }

/* Enable the Host Sleep */
if (!mwifiex_enable_hs(adapter)) {
diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c
index a750edb..4d314c1 100644
--- a/drivers/net/wireless/marvell/mwifiex/sdio.c
+++ b/drivers/net/wireless/marvell/mwifiex/sdio.c
@@ -331,8 +331,8 @@ static int mwifiex_sdio_suspend(struct device *dev)
}

card = sdio_get_drvdata(func);
- if (!card || !card->adapter) {
- pr_err("suspend: invalid card or adapter\n");
+ if (!card) {
+ dev_err(dev, "suspend: invalid card\n");
return 0;
}
} else {
@@ -340,7 +340,14 @@ static int mwifiex_sdio_suspend(struct device *dev)
return 0;
}

+ /* Might still be loading firmware */
+ wait_for_completion(&card->fw_done);
+
adapter = card->adapter;
+ if (!adapter) {
+ dev_err(dev, "card is not valid\n");
+ return 0;
+ }

/* Enable platform specific wakeup interrupt */
if (card->plt_wake_cfg && card->plt_wake_cfg->irq_wifi >= 0) {
diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c
index a61455c..70126c3 100644
--- a/drivers/net/wireless/marvell/mwifiex/usb.c
+++ b/drivers/net/wireless/marvell/mwifiex/usb.c
@@ -503,11 +503,19 @@ static int mwifiex_usb_suspend(struct usb_interface *intf, pm_message_t message)
struct usb_tx_data_port *port;
int i, j;

- if (!card || !card->adapter) {
- pr_err("%s: card or card->adapter is NULL\n", __func__);
+ if (!card) {
+ dev_err(&intf->dev, "%s: card is NULL\n", __func__);
return 0;
}
+
+ /* Might still be loading firmware */
+ wait_for_completion(&card->fw_done);
+
adapter = card->adapter;
+ if (!adapter) {
+ dev_err(&intf->dev, "card is not valid\n");
+ return 0;
+ }

if (unlikely(adapter->is_suspended))
mwifiex_dbg(adapter, WARN,
--
1.8.1.4

2016-10-31 08:03:08

by Xinming Hu

[permalink] [raw]
Subject: [PATCH 12/12] mwifiex: pcie: stop checking for NULL adapter->card

From: Brian Norris <[email protected]>

It should never be NULL here, and to think otherwise makes things
confusing.

Signed-off-by: Brian Norris <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/pcie.c | 55 +++++++++++++----------------
1 file changed, 24 insertions(+), 31 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index c061d00..86e8ce6 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -2990,31 +2990,28 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card = adapter->card;
- struct pci_dev *pdev;
+ struct pci_dev *pdev = card->dev;
int i;

- if (card) {
- pdev = card->dev;
- if (card->msix_enable) {
- for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++)
- synchronize_irq(card->msix_entries[i].vector);
+ if (card->msix_enable) {
+ for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++)
+ synchronize_irq(card->msix_entries[i].vector);

- for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++)
- free_irq(card->msix_entries[i].vector,
- &card->msix_ctx[i]);
+ for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++)
+ free_irq(card->msix_entries[i].vector,
+ &card->msix_ctx[i]);

- card->msix_enable = 0;
- pci_disable_msix(pdev);
- } else {
- mwifiex_dbg(adapter, INFO,
- "%s(): calling free_irq()\n", __func__);
- free_irq(card->dev->irq, &card->share_irq_ctx);
+ card->msix_enable = 0;
+ pci_disable_msix(pdev);
+ } else {
+ mwifiex_dbg(adapter, INFO,
+ "%s(): calling free_irq()\n", __func__);
+ free_irq(card->dev->irq, &card->share_irq_ctx);

- if (card->msi_enable)
- pci_disable_msi(pdev);
- }
- card->adapter = NULL;
- }
+ if (card->msi_enable)
+ pci_disable_msi(pdev);
+ }
+ card->adapter = NULL;
}

/* This function initializes the PCI-E host memory space, WCB rings, etc.
@@ -3097,18 +3094,14 @@ static void mwifiex_pcie_down_dev(struct mwifiex_adapter *adapter)
adapter->seq_num = 0;
adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K;

- if (card) {
- if (reg->sleep_cookie)
- 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;
- }
+ if (reg->sleep_cookie)
+ mwifiex_pcie_delete_sleep_cookie_buf(adapter);

- return;
+ 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;
}

static struct mwifiex_if_ops pcie_ops = {
--
1.8.1.4

2016-10-31 08:02:44

by Xinming Hu

[permalink] [raw]
Subject: [PATCH 05/12] mwifiex: remove redundant pdev check in suspend/resume handlers

From: Amitkumar Karwar <[email protected]>

to_pci_dev() would just do struct offset arithmetic on struct
device to get 'pdev' pointer. We never get NULL pdev pointer.

Signed-off-by: Amitkumar Karwar <[email protected]>
Signed-off-by: Brian Norris <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/pcie.c | 22 ++++++----------------
1 file changed, 6 insertions(+), 16 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 5507c89..fb34b99 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -101,14 +101,9 @@ static int mwifiex_pcie_suspend(struct device *dev)
struct pcie_service_card *card;
struct pci_dev *pdev = to_pci_dev(dev);

- if (pdev) {
- 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");
+ card = pci_get_drvdata(pdev);
+ if (!card || !card->adapter) {
+ pr_err("Card or adapter structure is not valid\n");
return 0;
}

@@ -145,14 +140,9 @@ static int mwifiex_pcie_resume(struct device *dev)
struct pcie_service_card *card;
struct pci_dev *pdev = to_pci_dev(dev);

- if (pdev) {
- 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");
+ card = pci_get_drvdata(pdev);
+ if (!card || !card->adapter) {
+ dev_err(dev, "Card or adapter structure is not valid\n");
return 0;
}

--
1.8.1.4

2016-10-31 08:03:01

by Xinming Hu

[permalink] [raw]
Subject: [PATCH 10/12] mwifiex: sdio: don't check for NULL sdio_func

From: Brian Norris <[email protected]>

sdio_func is retrieved via container_of() and should never be NULL.
Checking for NULL just makes the logic more confusing than necessary.
Stop doing that.

Signed-off-by: Brian Norris <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/sdio.c | 40 +++++++++++------------------
1 file changed, 15 insertions(+), 25 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c
index 375d0a5..8f0f072 100644
--- a/drivers/net/wireless/marvell/mwifiex/sdio.c
+++ b/drivers/net/wireless/marvell/mwifiex/sdio.c
@@ -231,15 +231,10 @@ static int mwifiex_sdio_resume(struct device *dev)
struct mwifiex_adapter *adapter;
mmc_pm_flag_t pm_flag = 0;

- if (func) {
- pm_flag = sdio_get_host_pm_caps(func);
- card = sdio_get_drvdata(func);
- if (!card || !card->adapter) {
- pr_err("resume: invalid card or adapter\n");
- return 0;
- }
- } else {
- pr_err("resume: sdio_func is not specified\n");
+ pm_flag = sdio_get_host_pm_caps(func);
+ card = sdio_get_drvdata(func);
+ if (!card || !card->adapter) {
+ dev_err(dev, "resume: invalid card or adapter\n");
return 0;
}

@@ -320,23 +315,18 @@ static int mwifiex_sdio_suspend(struct device *dev)
mmc_pm_flag_t pm_flag = 0;
int ret = 0;

- if (func) {
- pm_flag = sdio_get_host_pm_caps(func);
- pr_debug("cmd: %s: suspend: PM flag = 0x%x\n",
- sdio_func_id(func), pm_flag);
- if (!(pm_flag & MMC_PM_KEEP_POWER)) {
- pr_err("%s: cannot remain alive while host is"
- " suspended\n", sdio_func_id(func));
- return -ENOSYS;
- }
+ pm_flag = sdio_get_host_pm_caps(func);
+ pr_debug("cmd: %s: suspend: PM flag = 0x%x\n",
+ sdio_func_id(func), pm_flag);
+ if (!(pm_flag & MMC_PM_KEEP_POWER)) {
+ dev_err(dev, "%s: cannot remain alive while host is"
+ " suspended\n", sdio_func_id(func));
+ return -ENOSYS;
+ }

- card = sdio_get_drvdata(func);
- if (!card) {
- dev_err(dev, "suspend: invalid card\n");
- return 0;
- }
- } else {
- pr_err("suspend: sdio_func is not specified\n");
+ card = sdio_get_drvdata(func);
+ if (!card) {
+ dev_err(dev, "suspend: invalid card\n");
return 0;
}

--
1.8.1.4

2016-10-31 08:02:54

by Xinming Hu

[permalink] [raw]
Subject: [PATCH 08/12] mwifiex: reset card->adapter during device unregister

From: Xinming Hu <[email protected]>

card->adapter gets initialized in mwifiex_register_dev(). As it's not
cleared in mwifiex_unregister_dev(), we may end up accessing the memory
which is already free in below scenario.

Scenario: Driver initialization is failed due to incorrect firmware or
some other reason. Meanwhile device reboot/unload occurs.

This is safe, now that we've properly synchronized suspend() and
remove() with the FW initialization thread; now that code can simply
check for 'card->adapter == NULL' and exit safely.

Signed-off-by: Xinming Hu <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
Signed-off-by: Brian Norris <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/pcie.c | 1 +
drivers/net/wireless/marvell/mwifiex/sdio.c | 1 +
2 files changed, 2 insertions(+)

diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index b635563..04b9961 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -3017,6 +3017,7 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
if (card->msi_enable)
pci_disable_msi(pdev);
}
+ card->adapter = NULL;
}
}

diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c
index 4d314c1..375d0a5 100644
--- a/drivers/net/wireless/marvell/mwifiex/sdio.c
+++ b/drivers/net/wireless/marvell/mwifiex/sdio.c
@@ -2070,6 +2070,7 @@ mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
struct sdio_mmc_card *card = adapter->card;

if (adapter->card) {
+ card->adapter = NULL;
sdio_claim_host(card->func);
sdio_disable_func(card->func);
sdio_release_host(card->func);
--
1.8.1.4

2016-10-31 08:02:35

by Xinming Hu

[permalink] [raw]
Subject: [PATCH 02/12] mwifiex: check tx_hw_pending before downloading sleep confirm

From: Shengzhen Li <[email protected]>

This patch will only allow downloading sleep confirm
when no tx done interrupt is pending in the hardware.

Signed-off-by: Cathy Luo <[email protected]>
Signed-off-by: Shengzhen Li <[email protected]>

Change-Id: I6d6955b4a2de0ad791ca28f0f635d636a2c7e406
---
drivers/net/wireless/marvell/mwifiex/cmdevt.c | 4 ++--
drivers/net/wireless/marvell/mwifiex/init.c | 1 +
drivers/net/wireless/marvell/mwifiex/main.h | 1 +
drivers/net/wireless/marvell/mwifiex/pcie.c | 5 +++++
4 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
index 9075be5..25a7475 100644
--- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
@@ -1118,14 +1118,14 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
void
mwifiex_check_ps_cond(struct mwifiex_adapter *adapter)
{
- if (!adapter->cmd_sent &&
+ if (!adapter->cmd_sent && !atomic_read(&adapter->tx_hw_pending) &&
!adapter->curr_cmd && !IS_CARD_RX_RCVD(adapter))
mwifiex_dnld_sleep_confirm_cmd(adapter);
else
mwifiex_dbg(adapter, CMD,
"cmd: Delay Sleep Confirm (%s%s%s%s)\n",
(adapter->cmd_sent) ? "D" : "",
- (adapter->data_sent) ? "T" : "",
+ atomic_read(&adapter->tx_hw_pending) ? "T" : "",
(adapter->curr_cmd) ? "C" : "",
(IS_CARD_RX_RCVD(adapter)) ? "R" : "");
}
diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c
index 82839d9..b36cb3f 100644
--- a/drivers/net/wireless/marvell/mwifiex/init.c
+++ b/drivers/net/wireless/marvell/mwifiex/init.c
@@ -270,6 +270,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
adapter->adhoc_11n_enabled = false;

mwifiex_wmm_init(adapter);
+ atomic_set(&adapter->tx_hw_pending, 0);

sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm *)
adapter->sleep_cfm->data;
diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h
index d61fe3a..7f67f23 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.h
+++ b/drivers/net/wireless/marvell/mwifiex/main.h
@@ -857,6 +857,7 @@ struct mwifiex_adapter {
atomic_t rx_pending;
atomic_t tx_pending;
atomic_t cmd_pending;
+ atomic_t tx_hw_pending;
struct workqueue_struct *workqueue;
struct work_struct main_work;
struct workqueue_struct *rx_workqueue;
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 063c707..4aa5d91 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -516,6 +516,7 @@ static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter)
}
}

+ atomic_set(&adapter->tx_hw_pending, 0);
return 0;
}

@@ -689,6 +690,7 @@ static void mwifiex_cleanup_txq_ring(struct mwifiex_adapter *adapter)
card->tx_buf_list[i] = NULL;
}

+ atomic_set(&adapter->tx_hw_pending, 0);
return;
}

@@ -1126,6 +1128,7 @@ static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter)
-1);
else
mwifiex_write_data_complete(adapter, skb, 0, 0);
+ atomic_dec(&adapter->tx_hw_pending);
}

card->tx_buf_list[wrdoneidx] = NULL;
@@ -1218,6 +1221,7 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
wrindx = (card->txbd_wrptr & reg->tx_mask) >> reg->tx_start_ptr;
buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
card->tx_buf_list[wrindx] = skb;
+ atomic_inc(&adapter->tx_hw_pending);

if (reg->pfu_enabled) {
desc2 = card->txbd_ring[wrindx];
@@ -1295,6 +1299,7 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
done_unmap:
mwifiex_unmap_pci_memory(adapter, skb, PCI_DMA_TODEVICE);
card->tx_buf_list[wrindx] = NULL;
+ atomic_dec(&adapter->tx_hw_pending);
if (reg->pfu_enabled)
memset(desc2, 0, sizeof(*desc2));
else
--
1.8.1.4

2016-10-31 08:02:38

by Xinming Hu

[permalink] [raw]
Subject: [PATCH 03/12] mwifiex: don't do unbalanced free()'ing in cleanup_if()

From: Brian Norris <[email protected]>

The cleanup_if() callback is the inverse of init_if(). We allocate our
'card' interface structure in the probe() function, but we free it in
cleanup_if(). That gives a few problems:
(a) we leak this memory if probe() fails before we reach init_if()
(b) we can't safely utilize 'card' after cleanup_if() -- namely, in
remove() or suspend(), both of which might race with the cleanup
paths in our asynchronous FW initialization path

Solution: just use devm_kzalloc(), which will free this structure
properly when the device is removed -- and drop the set_drvdata(...,
NULL), since the driver core does this for us. This also removes the
temptation to use drvdata == NULL as a hack for checking if the device
has been "cleaned up."

This is a preparatory step for adding a card-level completion structure
to handle our FW init vs. remove/suspend races, in addition to fixing
memory leaks.

I *do* leave the set_drvdata(..., NULL) for the hacky SDIO
mwifiex_recreate_adapter(), since the device core won't be able to clear
that one for us.

Signed-off-by: Brian Norris <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/pcie.c | 5 +----
drivers/net/wireless/marvell/mwifiex/sdio.c | 16 ++++++++++------
drivers/net/wireless/marvell/mwifiex/usb.c | 7 +------
3 files changed, 12 insertions(+), 16 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 4aa5d91..e6bea02 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -189,7 +189,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
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);
+ card = devm_kzalloc(&pdev->dev, sizeof(*card), GFP_KERNEL);
if (!card)
return -ENOMEM;

@@ -2820,7 +2820,6 @@ err_req_region0:
err_set_dma_mask:
pci_disable_device(pdev);
err_enable_dev:
- pci_set_drvdata(pdev, NULL);
return ret;
}

@@ -2854,9 +2853,7 @@ static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter)
pci_disable_device(pdev);
pci_release_region(pdev, 2);
pci_release_region(pdev, 0);
- pci_set_drvdata(pdev, NULL);
}
- kfree(card);
}

static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter)
diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c
index 8718950..f04cf5a 100644
--- a/drivers/net/wireless/marvell/mwifiex/sdio.c
+++ b/drivers/net/wireless/marvell/mwifiex/sdio.c
@@ -152,7 +152,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
pr_debug("info: vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n",
func->vendor, func->device, func->class, func->num);

- card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL);
+ card = devm_kzalloc(&func->dev, sizeof(*card), GFP_KERNEL);
if (!card)
return -ENOMEM;

@@ -185,7 +185,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)

if (ret) {
dev_err(&func->dev, "failed to enable function\n");
- goto err_free;
+ return ret;
}

/* device tree node parsing and platform specific configuration*/
@@ -210,8 +210,6 @@ err_disable:
sdio_claim_host(func);
sdio_disable_func(func);
sdio_release_host(func);
-err_free:
- kfree(card);

return ret;
}
@@ -2240,8 +2238,6 @@ static void mwifiex_cleanup_sdio(struct mwifiex_adapter *adapter)
kfree(card->mpa_rx.len_arr);
kfree(card->mpa_tx.buf);
kfree(card->mpa_rx.buf);
- sdio_set_drvdata(card->func, NULL);
- kfree(card);
}

/*
@@ -2291,6 +2287,14 @@ static void mwifiex_recreate_adapter(struct sdio_mmc_card *card)

mwifiex_sdio_remove(func);

+ /*
+ * Normally, we would let the driver core take care of releasing these.
+ * But we're not letting the driver core handle this one. See above
+ * TODO.
+ */
+ sdio_set_drvdata(func, NULL);
+ devm_kfree(&func->dev, card);
+
/* power cycle the adapter */
sdio_claim_host(func);
mmc_hw_reset(func->card->host);
diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c
index 73eb084..57ed834 100644
--- a/drivers/net/wireless/marvell/mwifiex/usb.c
+++ b/drivers/net/wireless/marvell/mwifiex/usb.c
@@ -382,7 +382,7 @@ static int mwifiex_usb_probe(struct usb_interface *intf,
struct usb_card_rec *card;
u16 id_vendor, id_product, bcd_device, bcd_usb;

- card = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL);
+ card = devm_kzalloc(&intf->dev, sizeof(*card), GFP_KERNEL);
if (!card)
return -ENOMEM;

@@ -480,7 +480,6 @@ static int mwifiex_usb_probe(struct usb_interface *intf,
if (ret) {
pr_err("%s: mwifiex_add_card failed: %d\n", __func__, ret);
usb_reset_device(udev);
- kfree(card);
return ret;
}

@@ -630,11 +629,7 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf)
"%s: removing card\n", __func__);
mwifiex_remove_card(adapter, &add_remove_card_sem);

- usb_set_intfdata(intf, NULL);
usb_put_dev(interface_to_usbdev(intf));
- kfree(card);
-
- return;
}

static struct usb_driver mwifiex_usb_driver = {
--
1.8.1.4

2016-10-31 08:02:48

by Xinming Hu

[permalink] [raw]
Subject: [PATCH 06/12] mwifiex: don't pretend to resume while remove()'ing

From: Brian Norris <[email protected]>

The device core will not allow suspend() to race with remove().

Signed-off-by: Brian Norris <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/pcie.c | 5 -----
drivers/net/wireless/marvell/mwifiex/sdio.c | 3 ---
drivers/net/wireless/marvell/mwifiex/usb.c | 5 -----
3 files changed, 13 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index fb34b99..32fbb91 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -225,11 +225,6 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
return;

if (user_rmmod && !adapter->mfg_mode) {
-#ifdef CONFIG_PM_SLEEP
- if (adapter->is_suspended)
- mwifiex_pcie_resume(&pdev->dev);
-#endif
-
mwifiex_deauthenticate_all(adapter);

priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c
index 1f6ebde..a750edb 100644
--- a/drivers/net/wireless/marvell/mwifiex/sdio.c
+++ b/drivers/net/wireless/marvell/mwifiex/sdio.c
@@ -292,9 +292,6 @@ mwifiex_sdio_remove(struct sdio_func *func)
mwifiex_dbg(adapter, INFO, "info: SDIO func num=%d\n", func->num);

if (user_rmmod && !adapter->mfg_mode) {
- if (adapter->is_suspended)
- mwifiex_sdio_resume(adapter->dev);
-
mwifiex_deauthenticate_all(adapter);

priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c
index c20ff2f..a61455c 100644
--- a/drivers/net/wireless/marvell/mwifiex/usb.c
+++ b/drivers/net/wireless/marvell/mwifiex/usb.c
@@ -614,11 +614,6 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf)
return;

if (user_rmmod && !adapter->mfg_mode) {
-#ifdef CONFIG_PM
- if (adapter->is_suspended)
- mwifiex_usb_resume(intf);
-#endif
-
mwifiex_deauthenticate_all(adapter);

mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter,
--
1.8.1.4

2016-10-31 08:02:58

by Xinming Hu

[permalink] [raw]
Subject: [PATCH 09/12] mwifiex: usb: handle HS failures

From: Brian Norris <[email protected]>

SDIO and PCIe drivers handle this. Let's imitate it.

Not tested.

Signed-off-by: Brian Norris <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/usb.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c
index 70126c3..c26daf4 100644
--- a/drivers/net/wireless/marvell/mwifiex/usb.c
+++ b/drivers/net/wireless/marvell/mwifiex/usb.c
@@ -521,7 +521,14 @@ static int mwifiex_usb_suspend(struct usb_interface *intf, pm_message_t message)
mwifiex_dbg(adapter, WARN,
"Device already suspended\n");

- mwifiex_enable_hs(adapter);
+ /* Enable the Host Sleep */
+ if (!mwifiex_enable_hs(adapter)) {
+ mwifiex_dbg(adapter, ERROR,
+ "cmd: failed to suspend\n");
+ adapter->hs_enabling = false;
+ return -EFAULT;
+ }
+

/* 'is_suspended' flag indicates device is suspended.
* It must be set here before the usb_kill_urb() calls. Reason
--
1.8.1.4

2016-10-31 23:57:16

by Brian Norris

[permalink] [raw]
Subject: Re: [PATCH 01/12] mwifiex: fix power save issue when suspend

Hi,

On Mon, Oct 31, 2016 at 04:02:09PM +0800, Xinming Hu wrote:
> From: Shengzhen Li <[email protected]>
>
> This patch fixes a corner case for "FROMLIST: mwifiex: fix corner case

Upstream patches don't normally get a 'FROMLIST' tag while you're
sending them to the mailing list :) That designation is used for Chrome
OS trees, so we know where to find the patch source. But the upstream
mailing list *is* the source.

> power save issue", main process will check the power save condition in
> PS_PRE_SLEEP status so the sleep handshake could continue.
>
> Signed-off-by: Cathy Luo <[email protected]>
> Signed-off-by: Shengzhen Li <[email protected]>
> Signed-off-by: Amitkumar Karwar <[email protected]>
>
> BUG=chrome-os-partner:58164
> TEST=stress Wifi w/ power_save enabled
>
> Change-Id: I5a36d9eaeb7fe5faaccc533e0d1ba1f3253666dc

In the same vein: while I'm happy to have the BUG=, TEST=, and Gerrit
Change-ID for our Chrome OS tree, I don't think upstream reviewers
typically care about those. Please remove those from upstream
submissions like this.

(Same applies to the rest of this series. Also, consider running
scripts/checkpatch.pl. It will at least remind you about removing the
Gerrit Change-ID.)

> ---
> drivers/net/wireless/marvell/mwifiex/cmdevt.c | 3 ++-
> drivers/net/wireless/marvell/mwifiex/main.c | 5 +++++
> 2 files changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
> index 5347728..9075be5 100644
> --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c
> +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
> @@ -1123,8 +1123,9 @@ mwifiex_check_ps_cond(struct mwifiex_adapter *adapter)
> mwifiex_dnld_sleep_confirm_cmd(adapter);
> else
> mwifiex_dbg(adapter, CMD,
> - "cmd: Delay Sleep Confirm (%s%s%s)\n",
> + "cmd: Delay Sleep Confirm (%s%s%s%s)\n",
> (adapter->cmd_sent) ? "D" : "",
> + (adapter->data_sent) ? "T" : "",
> (adapter->curr_cmd) ? "C" : "",
> (IS_CARD_RX_RCVD(adapter)) ? "R" : "");
> }
> diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c
> index 2478ccd..f559ead 100644
> --- a/drivers/net/wireless/marvell/mwifiex/main.c
> +++ b/drivers/net/wireless/marvell/mwifiex/main.c
> @@ -308,6 +308,11 @@ process_start:
> /* We have tried to wakeup the card already */
> if (adapter->pm_wakeup_fw_try)
> break;
> + if (adapter->ps_state == PS_STATE_PRE_SLEEP) {
> + if (!adapter->cmd_sent && !adapter->curr_cmd)

The entire 'if' condition is unnecessary. That's all checked already
within mwifiex_check_ps_cond().

Brian

> + mwifiex_check_ps_cond(adapter);
> + }
> +
> if (adapter->ps_state != PS_STATE_AWAKE)
> break;
> if (adapter->tx_lock_flag) {
> --
> 1.8.1.4
>

2016-11-01 10:26:29

by Xinming Hu

[permalink] [raw]
Subject: RE: [PATCH 01/12] mwifiex: fix power save issue when suspend

SGkgQnJpYW4sDQoNClRoYW5rcyBmb3IgcmV2aWV3LCB3ZSB3aWxsIGFkZHJlc3MgeW91ciBjb21t
ZW50cyBpbiB1cGRhdGVkIHZlcnNpb24uDQpTaW5jZSB3ZSBoYXZlIGFuIGVuaGFuY2VkIHZlcmlz
b24gZm9yIEZST01MSVNUOiBtd2lmaWV4OiBmaXggY29ybmVyIGNhc2UsIA0KdGhhdCBpcyBodHRw
czovL3BhdGNod29yay5rZXJuZWwub3JnL3BhdGNoLzk0MDUxMTkvICwNCnRoZSB1cGRhdGVkIHBh
dGNoIHdpbGwgYmUgcmVvcmdhbml6ZWQgdG8gZm9sbG93IGFib3ZlIHBhdGNoLg0KDQo+IC0tLS0t
T3JpZ2luYWwgTWVzc2FnZS0tLS0tDQo+IEZyb206IGxpbnV4LXdpcmVsZXNzLW93bmVyQHZnZXIu
a2VybmVsLm9yZw0KPiBbbWFpbHRvOmxpbnV4LXdpcmVsZXNzLW93bmVyQHZnZXIua2VybmVsLm9y
Z10gT24gQmVoYWxmIE9mIEJyaWFuIE5vcnJpcw0KPiBTZW50OiAyMDE2xOoxMdTCMcjVIDc6NTcN
Cj4gVG86IFhpbm1pbmcgSHUNCj4gQ2M6IExpbnV4IFdpcmVsZXNzOyBLYWxsZSBWYWxvOyBEbWl0
cnkgVG9yb2tob3Y7IEFtaXRrdW1hciBLYXJ3YXI7IENhdGh5IEx1bzsNCj4gU2hlbmd6aGVuIExp
DQo+IFN1YmplY3Q6IFJlOiBbUEFUQ0ggMDEvMTJdIG13aWZpZXg6IGZpeCBwb3dlciBzYXZlIGlz
c3VlIHdoZW4gc3VzcGVuZA0KPiANCj4gSGksDQo+IA0KPiBPbiBNb24sIE9jdCAzMSwgMjAxNiBh
dCAwNDowMjowOVBNICswODAwLCBYaW5taW5nIEh1IHdyb3RlOg0KPiA+IEZyb206IFNoZW5nemhl
biBMaSA8c3psaUBtYXJ2ZWxsLmNvbT4NCj4gPg0KPiA+IFRoaXMgcGF0Y2ggZml4ZXMgYSBjb3Ju
ZXIgY2FzZSBmb3IgIkZST01MSVNUOiBtd2lmaWV4OiBmaXggY29ybmVyIGNhc2UNCj4gDQo+IFVw
c3RyZWFtIHBhdGNoZXMgZG9uJ3Qgbm9ybWFsbHkgZ2V0IGEgJ0ZST01MSVNUJyB0YWcgd2hpbGUg
eW91J3JlIHNlbmRpbmcNCj4gdGhlbSB0byB0aGUgbWFpbGluZyBsaXN0IDopIFRoYXQgZGVzaWdu
YXRpb24gaXMgdXNlZCBmb3IgQ2hyb21lIE9TIHRyZWVzLCBzbyB3ZQ0KPiBrbm93IHdoZXJlIHRv
IGZpbmQgdGhlIHBhdGNoIHNvdXJjZS4gQnV0IHRoZSB1cHN0cmVhbSBtYWlsaW5nIGxpc3QgKmlz
KiB0aGUNCj4gc291cmNlLg0KPiANCj4gPiBwb3dlciBzYXZlIGlzc3VlIiwgbWFpbiBwcm9jZXNz
IHdpbGwgY2hlY2sgdGhlIHBvd2VyIHNhdmUgY29uZGl0aW9uIGluDQo+ID4gUFNfUFJFX1NMRUVQ
IHN0YXR1cyBzbyB0aGUgc2xlZXAgaGFuZHNoYWtlIGNvdWxkIGNvbnRpbnVlLg0KPiA+DQo+ID4g
U2lnbmVkLW9mZi1ieTogQ2F0aHkgTHVvIDxjbHVvQG1hcnZlbGwuY29tPg0KPiA+IFNpZ25lZC1v
ZmYtYnk6IFNoZW5nemhlbiBMaSA8c3psaUBtYXJ2ZWxsLmNvbT4NCj4gPiBTaWduZWQtb2ZmLWJ5
OiBBbWl0a3VtYXIgS2Fyd2FyIDxha2Fyd2FyQG1hcnZlbGwuY29tPg0KPiA+DQo+ID4gQlVHPWNo
cm9tZS1vcy1wYXJ0bmVyOjU4MTY0DQo+ID4gVEVTVD1zdHJlc3MgV2lmaSB3LyBwb3dlcl9zYXZl
IGVuYWJsZWQNCj4gPg0KPiA+IENoYW5nZS1JZDogSTVhMzZkOWVhZWI3ZmU1ZmFhY2NjNTMzZTBk
MWJhMWYzMjUzNjY2ZGMNCj4gDQo+IEluIHRoZSBzYW1lIHZlaW46IHdoaWxlIEknbSBoYXBweSB0
byBoYXZlIHRoZSBCVUc9LCBURVNUPSwgYW5kIEdlcnJpdA0KPiBDaGFuZ2UtSUQgZm9yIG91ciBD
aHJvbWUgT1MgdHJlZSwgSSBkb24ndCB0aGluayB1cHN0cmVhbSByZXZpZXdlcnMgdHlwaWNhbGx5
DQo+IGNhcmUgYWJvdXQgdGhvc2UuIFBsZWFzZSByZW1vdmUgdGhvc2UgZnJvbSB1cHN0cmVhbSBz
dWJtaXNzaW9ucyBsaWtlIHRoaXMuDQo+IA0KPiAoU2FtZSBhcHBsaWVzIHRvIHRoZSByZXN0IG9m
IHRoaXMgc2VyaWVzLiBBbHNvLCBjb25zaWRlciBydW5uaW5nDQo+IHNjcmlwdHMvY2hlY2twYXRj
aC5wbC4gSXQgd2lsbCBhdCBsZWFzdCByZW1pbmQgeW91IGFib3V0IHJlbW92aW5nIHRoZSBHZXJy
aXQNCj4gQ2hhbmdlLUlELikNCj4gDQo+ID4gLS0tDQo+ID4gIGRyaXZlcnMvbmV0L3dpcmVsZXNz
L21hcnZlbGwvbXdpZmlleC9jbWRldnQuYyB8IDMgKystDQo+ID4gIGRyaXZlcnMvbmV0L3dpcmVs
ZXNzL21hcnZlbGwvbXdpZmlleC9tYWluLmMgICB8IDUgKysrKysNCj4gPiAgMiBmaWxlcyBjaGFu
Z2VkLCA3IGluc2VydGlvbnMoKyksIDEgZGVsZXRpb24oLSkNCj4gPg0KPiA+IGRpZmYgLS1naXQg
YS9kcml2ZXJzL25ldC93aXJlbGVzcy9tYXJ2ZWxsL213aWZpZXgvY21kZXZ0LmMNCj4gPiBiL2Ry
aXZlcnMvbmV0L3dpcmVsZXNzL21hcnZlbGwvbXdpZmlleC9jbWRldnQuYw0KPiA+IGluZGV4IDUz
NDc3MjguLjkwNzViZTUgMTAwNjQ0DQo+ID4gLS0tIGEvZHJpdmVycy9uZXQvd2lyZWxlc3MvbWFy
dmVsbC9td2lmaWV4L2NtZGV2dC5jDQo+ID4gKysrIGIvZHJpdmVycy9uZXQvd2lyZWxlc3MvbWFy
dmVsbC9td2lmaWV4L2NtZGV2dC5jDQo+ID4gQEAgLTExMjMsOCArMTEyMyw5IEBAIG13aWZpZXhf
Y2hlY2tfcHNfY29uZChzdHJ1Y3QgbXdpZmlleF9hZGFwdGVyDQo+ICphZGFwdGVyKQ0KPiA+ICAJ
CW13aWZpZXhfZG5sZF9zbGVlcF9jb25maXJtX2NtZChhZGFwdGVyKTsNCj4gPiAgCWVsc2UNCj4g
PiAgCQltd2lmaWV4X2RiZyhhZGFwdGVyLCBDTUQsDQo+ID4gLQkJCSAgICAiY21kOiBEZWxheSBT
bGVlcCBDb25maXJtICglcyVzJXMpXG4iLA0KPiA+ICsJCQkgICAgImNtZDogRGVsYXkgU2xlZXAg
Q29uZmlybSAoJXMlcyVzJXMpXG4iLA0KPiA+ICAJCQkgICAgKGFkYXB0ZXItPmNtZF9zZW50KSA/
ICJEIiA6ICIiLA0KPiA+ICsJCQkgICAgKGFkYXB0ZXItPmRhdGFfc2VudCkgPyAiVCIgOiAiIiwN
Cj4gPiAgCQkJICAgIChhZGFwdGVyLT5jdXJyX2NtZCkgPyAiQyIgOiAiIiwNCj4gPiAgCQkJICAg
IChJU19DQVJEX1JYX1JDVkQoYWRhcHRlcikpID8gIlIiIDogIiIpOyAgfSBkaWZmIC0tZ2l0DQo+
ID4gYS9kcml2ZXJzL25ldC93aXJlbGVzcy9tYXJ2ZWxsL213aWZpZXgvbWFpbi5jDQo+ID4gYi9k
cml2ZXJzL25ldC93aXJlbGVzcy9tYXJ2ZWxsL213aWZpZXgvbWFpbi5jDQo+ID4gaW5kZXggMjQ3
OGNjZC4uZjU1OWVhZCAxMDA2NDQNCj4gPiAtLS0gYS9kcml2ZXJzL25ldC93aXJlbGVzcy9tYXJ2
ZWxsL213aWZpZXgvbWFpbi5jDQo+ID4gKysrIGIvZHJpdmVycy9uZXQvd2lyZWxlc3MvbWFydmVs
bC9td2lmaWV4L21haW4uYw0KPiA+IEBAIC0zMDgsNiArMzA4LDExIEBAIHByb2Nlc3Nfc3RhcnQ6
DQo+ID4gIAkJCS8qIFdlIGhhdmUgdHJpZWQgdG8gd2FrZXVwIHRoZSBjYXJkIGFscmVhZHkgKi8N
Cj4gPiAgCQkJaWYgKGFkYXB0ZXItPnBtX3dha2V1cF9md190cnkpDQo+ID4gIAkJCQlicmVhazsN
Cj4gPiArCQkJaWYgKGFkYXB0ZXItPnBzX3N0YXRlID09IFBTX1NUQVRFX1BSRV9TTEVFUCkgew0K
PiA+ICsJCQkJaWYgKCFhZGFwdGVyLT5jbWRfc2VudCAmJiAhYWRhcHRlci0+Y3Vycl9jbWQpDQo+
IA0KPiBUaGUgZW50aXJlICdpZicgY29uZGl0aW9uIGlzIHVubmVjZXNzYXJ5LiBUaGF0J3MgYWxs
IGNoZWNrZWQgYWxyZWFkeSB3aXRoaW4NCj4gbXdpZmlleF9jaGVja19wc19jb25kKCkuDQo+IA0K
PiBCcmlhbg0KPiANCj4gPiArCQkJCQltd2lmaWV4X2NoZWNrX3BzX2NvbmQoYWRhcHRlcik7DQo+
ID4gKwkJCX0NCj4gPiArDQo+ID4gIAkJCWlmIChhZGFwdGVyLT5wc19zdGF0ZSAhPSBQU19TVEFU
RV9BV0FLRSkNCj4gPiAgCQkJCWJyZWFrOw0KPiA+ICAJCQlpZiAoYWRhcHRlci0+dHhfbG9ja19m
bGFnKSB7DQo+ID4gLS0NCj4gPiAxLjguMS40DQo+ID4NCg0KQmVzdCBSZWdhcmRzLA0KU2ltb24N
Cg==

2016-11-01 00:14:41

by Brian Norris

[permalink] [raw]
Subject: Re: [PATCH 02/12] mwifiex: check tx_hw_pending before downloading sleep confirm

On Mon, Oct 31, 2016 at 04:02:10PM +0800, Xinming Hu wrote:
> From: Shengzhen Li <[email protected]>
>
> This patch will only allow downloading sleep confirm
> when no tx done interrupt is pending in the hardware.
>
> Signed-off-by: Cathy Luo <[email protected]>
> Signed-off-by: Shengzhen Li <[email protected]>
>
> Change-Id: I6d6955b4a2de0ad791ca28f0f635d636a2c7e406


^^ Remove this

> ---
> drivers/net/wireless/marvell/mwifiex/cmdevt.c | 4 ++--
> drivers/net/wireless/marvell/mwifiex/init.c | 1 +
> drivers/net/wireless/marvell/mwifiex/main.h | 1 +
> drivers/net/wireless/marvell/mwifiex/pcie.c | 5 +++++
> 4 files changed, 9 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
> index 9075be5..25a7475 100644
> --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c
> +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
> @@ -1118,14 +1118,14 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
> void
> mwifiex_check_ps_cond(struct mwifiex_adapter *adapter)
> {
> - if (!adapter->cmd_sent &&
> + if (!adapter->cmd_sent && !atomic_read(&adapter->tx_hw_pending) &&

How is this different from the following?

https://patchwork.kernel.org/patch/9389485/

And parituclarly, they conflict on this line, so you need to resolve
that somehow...

And if the linked patch serves the same purpose, then I'd rather take
it, since it's much simpler.

Brian

> !adapter->curr_cmd && !IS_CARD_RX_RCVD(adapter))
> mwifiex_dnld_sleep_confirm_cmd(adapter);
> else
> mwifiex_dbg(adapter, CMD,
> "cmd: Delay Sleep Confirm (%s%s%s%s)\n",
> (adapter->cmd_sent) ? "D" : "",
> - (adapter->data_sent) ? "T" : "",
> + atomic_read(&adapter->tx_hw_pending) ? "T" : "",
> (adapter->curr_cmd) ? "C" : "",
> (IS_CARD_RX_RCVD(adapter)) ? "R" : "");
> }
> diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c
> index 82839d9..b36cb3f 100644
> --- a/drivers/net/wireless/marvell/mwifiex/init.c
> +++ b/drivers/net/wireless/marvell/mwifiex/init.c
> @@ -270,6 +270,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
> adapter->adhoc_11n_enabled = false;
>
> mwifiex_wmm_init(adapter);
> + atomic_set(&adapter->tx_hw_pending, 0);
>
> sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm *)
> adapter->sleep_cfm->data;
> diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h
> index d61fe3a..7f67f23 100644
> --- a/drivers/net/wireless/marvell/mwifiex/main.h
> +++ b/drivers/net/wireless/marvell/mwifiex/main.h
> @@ -857,6 +857,7 @@ struct mwifiex_adapter {
> atomic_t rx_pending;
> atomic_t tx_pending;
> atomic_t cmd_pending;
> + atomic_t tx_hw_pending;
> struct workqueue_struct *workqueue;
> struct work_struct main_work;
> struct workqueue_struct *rx_workqueue;
> diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
> index 063c707..4aa5d91 100644
> --- a/drivers/net/wireless/marvell/mwifiex/pcie.c
> +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
> @@ -516,6 +516,7 @@ static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter)
> }
> }
>
> + atomic_set(&adapter->tx_hw_pending, 0);
> return 0;
> }
>
> @@ -689,6 +690,7 @@ static void mwifiex_cleanup_txq_ring(struct mwifiex_adapter *adapter)
> card->tx_buf_list[i] = NULL;
> }
>
> + atomic_set(&adapter->tx_hw_pending, 0);
> return;
> }
>
> @@ -1126,6 +1128,7 @@ static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter)
> -1);
> else
> mwifiex_write_data_complete(adapter, skb, 0, 0);
> + atomic_dec(&adapter->tx_hw_pending);
> }
>
> card->tx_buf_list[wrdoneidx] = NULL;
> @@ -1218,6 +1221,7 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
> wrindx = (card->txbd_wrptr & reg->tx_mask) >> reg->tx_start_ptr;
> buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
> card->tx_buf_list[wrindx] = skb;
> + atomic_inc(&adapter->tx_hw_pending);
>
> if (reg->pfu_enabled) {
> desc2 = card->txbd_ring[wrindx];
> @@ -1295,6 +1299,7 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
> done_unmap:
> mwifiex_unmap_pci_memory(adapter, skb, PCI_DMA_TODEVICE);
> card->tx_buf_list[wrindx] = NULL;
> + atomic_dec(&adapter->tx_hw_pending);
> if (reg->pfu_enabled)
> memset(desc2, 0, sizeof(*desc2));
> else
> --
> 1.8.1.4
>

2016-11-01 10:24:42

by Xinming Hu

[permalink] [raw]
Subject: RE: [PATCH 02/12] mwifiex: check tx_hw_pending before downloading sleep confirm

SGkgQnJhaW4sDQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogbGludXgt
d2lyZWxlc3Mtb3duZXJAdmdlci5rZXJuZWwub3JnDQo+IFttYWlsdG86bGludXgtd2lyZWxlc3Mt
b3duZXJAdmdlci5rZXJuZWwub3JnXSBPbiBCZWhhbGYgT2YgQnJpYW4gTm9ycmlzDQo+IFNlbnQ6
IDIwMTbE6jEx1MIxyNUgODoxNQ0KPiBUbzogWGlubWluZyBIdQ0KPiBDYzogTGludXggV2lyZWxl
c3M7IEthbGxlIFZhbG87IERtaXRyeSBUb3Jva2hvdjsgQW1pdGt1bWFyIEthcndhcjsgQ2F0aHkg
THVvOw0KPiBTaGVuZ3poZW4gTGkNCj4gU3ViamVjdDogUmU6IFtQQVRDSCAwMi8xMl0gbXdpZmll
eDogY2hlY2sgdHhfaHdfcGVuZGluZyBiZWZvcmUgZG93bmxvYWRpbmcNCj4gc2xlZXAgY29uZmly
bQ0KPiANCj4gT24gTW9uLCBPY3QgMzEsIDIwMTYgYXQgMDQ6MDI6MTBQTSArMDgwMCwgWGlubWlu
ZyBIdSB3cm90ZToNCj4gPiBGcm9tOiBTaGVuZ3poZW4gTGkgPHN6bGlAbWFydmVsbC5jb20+DQo+
ID4NCj4gPiBUaGlzIHBhdGNoIHdpbGwgb25seSBhbGxvdyBkb3dubG9hZGluZyBzbGVlcCBjb25m
aXJtIHdoZW4gbm8gdHggZG9uZQ0KPiA+IGludGVycnVwdCBpcyBwZW5kaW5nIGluIHRoZSBoYXJk
d2FyZS4NCj4gPg0KPiA+IFNpZ25lZC1vZmYtYnk6IENhdGh5IEx1byA8Y2x1b0BtYXJ2ZWxsLmNv
bT4NCj4gPiBTaWduZWQtb2ZmLWJ5OiBTaGVuZ3poZW4gTGkgPHN6bGlAbWFydmVsbC5jb20+DQo+
ID4NCj4gPiBDaGFuZ2UtSWQ6IEk2ZDY5NTViNGEyZGUwYWQ3OTFjYTI4ZjBmNjM1ZDYzNmEyYzdl
NDA2DQo+IA0KPiANCj4gXl4gUmVtb3ZlIHRoaXMNCj4gDQoNCk9rLCB3aWxsIHJlbW92ZSBpbiB1
cGRhdGVkIHZlcnNpb24hDQoNCj4gPiAtLS0NCj4gPiAgZHJpdmVycy9uZXQvd2lyZWxlc3MvbWFy
dmVsbC9td2lmaWV4L2NtZGV2dC5jIHwgNCArKy0tDQo+ID4gIGRyaXZlcnMvbmV0L3dpcmVsZXNz
L21hcnZlbGwvbXdpZmlleC9pbml0LmMgICB8IDEgKw0KPiA+ICBkcml2ZXJzL25ldC93aXJlbGVz
cy9tYXJ2ZWxsL213aWZpZXgvbWFpbi5oICAgfCAxICsNCj4gPiAgZHJpdmVycy9uZXQvd2lyZWxl
c3MvbWFydmVsbC9td2lmaWV4L3BjaWUuYyAgIHwgNSArKysrKw0KPiA+ICA0IGZpbGVzIGNoYW5n
ZWQsIDkgaW5zZXJ0aW9ucygrKSwgMiBkZWxldGlvbnMoLSkNCj4gPg0KPiA+IGRpZmYgLS1naXQg
YS9kcml2ZXJzL25ldC93aXJlbGVzcy9tYXJ2ZWxsL213aWZpZXgvY21kZXZ0LmMNCj4gPiBiL2Ry
aXZlcnMvbmV0L3dpcmVsZXNzL21hcnZlbGwvbXdpZmlleC9jbWRldnQuYw0KPiA+IGluZGV4IDkw
NzViZTUuLjI1YTc0NzUgMTAwNjQ0DQo+ID4gLS0tIGEvZHJpdmVycy9uZXQvd2lyZWxlc3MvbWFy
dmVsbC9td2lmaWV4L2NtZGV2dC5jDQo+ID4gKysrIGIvZHJpdmVycy9uZXQvd2lyZWxlc3MvbWFy
dmVsbC9td2lmaWV4L2NtZGV2dC5jDQo+ID4gQEAgLTExMTgsMTQgKzExMTgsMTQgQEAgbXdpZmll
eF9jYW5jZWxfcGVuZGluZ19pb2N0bChzdHJ1Y3QNCj4gPiBtd2lmaWV4X2FkYXB0ZXIgKmFkYXB0
ZXIpICB2b2lkICBtd2lmaWV4X2NoZWNrX3BzX2NvbmQoc3RydWN0DQo+ID4gbXdpZmlleF9hZGFw
dGVyICphZGFwdGVyKSAgew0KPiA+IC0JaWYgKCFhZGFwdGVyLT5jbWRfc2VudCAmJg0KPiA+ICsJ
aWYgKCFhZGFwdGVyLT5jbWRfc2VudCAmJiAhYXRvbWljX3JlYWQoJmFkYXB0ZXItPnR4X2h3X3Bl
bmRpbmcpICYmDQo+IA0KPiBIb3cgaXMgdGhpcyBkaWZmZXJlbnQgZnJvbSB0aGUgZm9sbG93aW5n
Pw0KPiANCj4gaHR0cHM6Ly9wYXRjaHdvcmsua2VybmVsLm9yZy9wYXRjaC85Mzg5NDg1Lw0KPiAN
Cj4gQW5kIHBhcml0dWNsYXJseSwgdGhleSBjb25mbGljdCBvbiB0aGlzIGxpbmUsIHNvIHlvdSBu
ZWVkIHRvIHJlc29sdmUgdGhhdA0KPiBzb21laG93Li4uDQo+IA0KPiBBbmQgaWYgdGhlIGxpbmtl
ZCBwYXRjaCBzZXJ2ZXMgdGhlIHNhbWUgcHVycG9zZSwgdGhlbiBJJ2QgcmF0aGVyIHRha2UgaXQs
IHNpbmNlDQo+IGl0J3MgbXVjaCBzaW1wbGVyLg0KPiANCj4gQnJpYW4NCj4gDQoNClRoaXMgcGF0
Y2ggaXMgYW4gZW5oYW5jZWQgdmVyc2lvbiBjb21wYXJlZCB3aXRoIGh0dHBzOi8vcGF0Y2h3b3Jr
Lmtlcm5lbC5vcmcvcGF0Y2gvOTM4OTQ4NS8gLCANCk13aWZpZXggcGNpZSB0cnkgdG8gImFnZ3Jl
Z2F0ZSIgdHggcmluZyBidWZmZXJzLCBiZWZvcmUgbm90aWZ5IGZpcm13YXJlIGRhdGEgcmVhZHku
DQpkYXRhX3NlbnQgd2lsbCBvbmx5IGJlIHNldCB0cnVlIHdoZW4gcGNpZSBhZ2dyZWdhdGlvbiBp
cyBkb25lLg0KRHVyaW5nIHRoZSAicGNpZSBhZ2dyZWdhdGlvbiIgc3RhZ2UsIGRhdGFfc2VudCBp
cyBub3Qgc2V0LCBkcml2ZXIgc3RpbGwgYmUgYWJsZSB0byBkb3dubG9hZCBzbGVlcCBjb25maXJt
IGluIGFub3RoZXIgdGhyZWFkLCANCkluIHRoaXMgY2FzZSwgd2Ugd2lsbCBzdGlsbCBtZWV0IGtl
cm5lbCBjcmFzaCBjYXVzZWQgYnkgY29uY3VycmVudCBleGVjdXRpb24gYmV0d2VlbiBQTSBoYW5k
c2hha2UgYW5kIHByb2Nlc3NpbmcgdHggZG9uZSBpbnRlcnJ1cHQuIA0KdHhfaHdfcGVuZGluZyB3
aWxsIGJlIGEgYmV0dGVyIHNvbHV0aW9uIHRvIG1hdGNoIHRoaXMgY2FzZS4gDQoNCj4gPiAgCSAg
ICAhYWRhcHRlci0+Y3Vycl9jbWQgJiYgIUlTX0NBUkRfUlhfUkNWRChhZGFwdGVyKSkNCj4gPiAg
CQltd2lmaWV4X2RubGRfc2xlZXBfY29uZmlybV9jbWQoYWRhcHRlcik7DQo+ID4gIAllbHNlDQo+
ID4gIAkJbXdpZmlleF9kYmcoYWRhcHRlciwgQ01ELA0KPiA+ICAJCQkgICAgImNtZDogRGVsYXkg
U2xlZXAgQ29uZmlybSAoJXMlcyVzJXMpXG4iLA0KPiA+ICAJCQkgICAgKGFkYXB0ZXItPmNtZF9z
ZW50KSA/ICJEIiA6ICIiLA0KPiA+IC0JCQkgICAgKGFkYXB0ZXItPmRhdGFfc2VudCkgPyAiVCIg
OiAiIiwNCj4gPiArCQkJICAgIGF0b21pY19yZWFkKCZhZGFwdGVyLT50eF9od19wZW5kaW5nKSA/
ICJUIiA6ICIiLA0KPiA+ICAJCQkgICAgKGFkYXB0ZXItPmN1cnJfY21kKSA/ICJDIiA6ICIiLA0K
PiA+ICAJCQkgICAgKElTX0NBUkRfUlhfUkNWRChhZGFwdGVyKSkgPyAiUiIgOiAiIik7ICB9IGRp
ZmYgLS1naXQNCj4gPiBhL2RyaXZlcnMvbmV0L3dpcmVsZXNzL21hcnZlbGwvbXdpZmlleC9pbml0
LmMNCj4gPiBiL2RyaXZlcnMvbmV0L3dpcmVsZXNzL21hcnZlbGwvbXdpZmlleC9pbml0LmMNCj4g
PiBpbmRleCA4MjgzOWQ5Li5iMzZjYjNmIDEwMDY0NA0KPiA+IC0tLSBhL2RyaXZlcnMvbmV0L3dp
cmVsZXNzL21hcnZlbGwvbXdpZmlleC9pbml0LmMNCj4gPiArKysgYi9kcml2ZXJzL25ldC93aXJl
bGVzcy9tYXJ2ZWxsL213aWZpZXgvaW5pdC5jDQo+ID4gQEAgLTI3MCw2ICsyNzAsNyBAQCBzdGF0
aWMgdm9pZCBtd2lmaWV4X2luaXRfYWRhcHRlcihzdHJ1Y3QNCj4gbXdpZmlleF9hZGFwdGVyICph
ZGFwdGVyKQ0KPiA+ICAJYWRhcHRlci0+YWRob2NfMTFuX2VuYWJsZWQgPSBmYWxzZTsNCj4gPg0K
PiA+ICAJbXdpZmlleF93bW1faW5pdChhZGFwdGVyKTsNCj4gPiArCWF0b21pY19zZXQoJmFkYXB0
ZXItPnR4X2h3X3BlbmRpbmcsIDApOw0KPiA+DQo+ID4gIAlzbGVlcF9jZm1fYnVmID0gKHN0cnVj
dCBtd2lmaWV4X29wdF9zbGVlcF9jb25maXJtICopDQo+ID4gIAkJCQkJYWRhcHRlci0+c2xlZXBf
Y2ZtLT5kYXRhOw0KPiA+IGRpZmYgLS1naXQgYS9kcml2ZXJzL25ldC93aXJlbGVzcy9tYXJ2ZWxs
L213aWZpZXgvbWFpbi5oDQo+ID4gYi9kcml2ZXJzL25ldC93aXJlbGVzcy9tYXJ2ZWxsL213aWZp
ZXgvbWFpbi5oDQo+ID4gaW5kZXggZDYxZmUzYS4uN2Y2N2YyMyAxMDA2NDQNCj4gPiAtLS0gYS9k
cml2ZXJzL25ldC93aXJlbGVzcy9tYXJ2ZWxsL213aWZpZXgvbWFpbi5oDQo+ID4gKysrIGIvZHJp
dmVycy9uZXQvd2lyZWxlc3MvbWFydmVsbC9td2lmaWV4L21haW4uaA0KPiA+IEBAIC04NTcsNiAr
ODU3LDcgQEAgc3RydWN0IG13aWZpZXhfYWRhcHRlciB7DQo+ID4gIAlhdG9taWNfdCByeF9wZW5k
aW5nOw0KPiA+ICAJYXRvbWljX3QgdHhfcGVuZGluZzsNCj4gPiAgCWF0b21pY190IGNtZF9wZW5k
aW5nOw0KPiA+ICsJYXRvbWljX3QgdHhfaHdfcGVuZGluZzsNCj4gPiAgCXN0cnVjdCB3b3JrcXVl
dWVfc3RydWN0ICp3b3JrcXVldWU7DQo+ID4gIAlzdHJ1Y3Qgd29ya19zdHJ1Y3QgbWFpbl93b3Jr
Ow0KPiA+ICAJc3RydWN0IHdvcmtxdWV1ZV9zdHJ1Y3QgKnJ4X3dvcmtxdWV1ZTsgZGlmZiAtLWdp
dA0KPiA+IGEvZHJpdmVycy9uZXQvd2lyZWxlc3MvbWFydmVsbC9td2lmaWV4L3BjaWUuYw0KPiA+
IGIvZHJpdmVycy9uZXQvd2lyZWxlc3MvbWFydmVsbC9td2lmaWV4L3BjaWUuYw0KPiA+IGluZGV4
IDA2M2M3MDcuLjRhYTVkOTEgMTAwNjQ0DQo+ID4gLS0tIGEvZHJpdmVycy9uZXQvd2lyZWxlc3Mv
bWFydmVsbC9td2lmaWV4L3BjaWUuYw0KPiA+ICsrKyBiL2RyaXZlcnMvbmV0L3dpcmVsZXNzL21h
cnZlbGwvbXdpZmlleC9wY2llLmMNCj4gPiBAQCAtNTE2LDYgKzUxNiw3IEBAIHN0YXRpYyBpbnQg
bXdpZmlleF9wY2llX2VuYWJsZV9ob3N0X2ludChzdHJ1Y3QNCj4gbXdpZmlleF9hZGFwdGVyICph
ZGFwdGVyKQ0KPiA+ICAJCX0NCj4gPiAgCX0NCj4gPg0KPiA+ICsJYXRvbWljX3NldCgmYWRhcHRl
ci0+dHhfaHdfcGVuZGluZywgMCk7DQo+ID4gIAlyZXR1cm4gMDsNCj4gPiAgfQ0KPiA+DQo+ID4g
QEAgLTY4OSw2ICs2OTAsNyBAQCBzdGF0aWMgdm9pZCBtd2lmaWV4X2NsZWFudXBfdHhxX3Jpbmco
c3RydWN0DQo+IG13aWZpZXhfYWRhcHRlciAqYWRhcHRlcikNCj4gPiAgCQljYXJkLT50eF9idWZf
bGlzdFtpXSA9IE5VTEw7DQo+ID4gIAl9DQo+ID4NCj4gPiArCWF0b21pY19zZXQoJmFkYXB0ZXIt
PnR4X2h3X3BlbmRpbmcsIDApOw0KPiA+ICAJcmV0dXJuOw0KPiA+ICB9DQo+ID4NCj4gPiBAQCAt
MTEyNiw2ICsxMTI4LDcgQEAgc3RhdGljIGludCBtd2lmaWV4X3BjaWVfc2VuZF9kYXRhX2NvbXBs
ZXRlKHN0cnVjdA0KPiBtd2lmaWV4X2FkYXB0ZXIgKmFkYXB0ZXIpDQo+ID4gIAkJCQkJCQkgICAg
LTEpOw0KPiA+ICAJCQllbHNlDQo+ID4gIAkJCQltd2lmaWV4X3dyaXRlX2RhdGFfY29tcGxldGUo
YWRhcHRlciwgc2tiLCAwLCAwKTsNCj4gPiArCQkJYXRvbWljX2RlYygmYWRhcHRlci0+dHhfaHdf
cGVuZGluZyk7DQo+ID4gIAkJfQ0KPiA+DQo+ID4gIAkJY2FyZC0+dHhfYnVmX2xpc3Rbd3Jkb25l
aWR4XSA9IE5VTEw7IEBAIC0xMjE4LDYgKzEyMjEsNyBAQA0KPiA+IG13aWZpZXhfcGNpZV9zZW5k
X2RhdGEoc3RydWN0IG13aWZpZXhfYWRhcHRlciAqYWRhcHRlciwgc3RydWN0IHNrX2J1ZmYNCj4g
KnNrYiwNCj4gPiAgCQl3cmluZHggPSAoY2FyZC0+dHhiZF93cnB0ciAmIHJlZy0+dHhfbWFzaykg
Pj4gcmVnLT50eF9zdGFydF9wdHI7DQo+ID4gIAkJYnVmX3BhID0gTVdJRklFWF9TS0JfRE1BX0FE
RFIoc2tiKTsNCj4gPiAgCQljYXJkLT50eF9idWZfbGlzdFt3cmluZHhdID0gc2tiOw0KPiA+ICsJ
CWF0b21pY19pbmMoJmFkYXB0ZXItPnR4X2h3X3BlbmRpbmcpOw0KPiA+DQo+ID4gIAkJaWYgKHJl
Zy0+cGZ1X2VuYWJsZWQpIHsNCj4gPiAgCQkJZGVzYzIgPSBjYXJkLT50eGJkX3Jpbmdbd3JpbmR4
XTsNCj4gPiBAQCAtMTI5NSw2ICsxMjk5LDcgQEAgbXdpZmlleF9wY2llX3NlbmRfZGF0YShzdHJ1
Y3QgbXdpZmlleF9hZGFwdGVyDQo+ID4gKmFkYXB0ZXIsIHN0cnVjdCBza19idWZmICpza2IsDQo+
ID4gIGRvbmVfdW5tYXA6DQo+ID4gIAltd2lmaWV4X3VubWFwX3BjaV9tZW1vcnkoYWRhcHRlciwg
c2tiLCBQQ0lfRE1BX1RPREVWSUNFKTsNCj4gPiAgCWNhcmQtPnR4X2J1Zl9saXN0W3dyaW5keF0g
PSBOVUxMOw0KPiA+ICsJYXRvbWljX2RlYygmYWRhcHRlci0+dHhfaHdfcGVuZGluZyk7DQo+ID4g
IAlpZiAocmVnLT5wZnVfZW5hYmxlZCkNCj4gPiAgCQltZW1zZXQoZGVzYzIsIDAsIHNpemVvZigq
ZGVzYzIpKTsNCj4gPiAgCWVsc2UNCj4gPiAtLQ0KPiA+IDEuOC4xLjQNCj4gPg0KDQpCZXN0IFJl
Z2FyZHMsDQpYaW5taW5nDQoNCg==