Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d31ab357 authored by Amitkumar Karwar's avatar Amitkumar Karwar Committed by John W. Linville
Browse files

mwifiex: add support for SDIO card reset



When command timeout happens due to a bug in firmware/hardware,
the timeout handler just prints some debug information. User is
unable to reload the driver in this case.

Inspired by 9a821f5d "libertas: add sd8686 reset_card support",
this patch adds card reset support for SDIO interface when
command timeout happens. If the SDIO host contoller supports
MMC_POWER_OFF|UP|ON operations, the chip will be reset and the
firmware will be re-downloaded.

Signed-off-by: default avatarAmitkumar Karwar <akarwar@marvell.com>
Signed-off-by: default avatarBing Zhao <bzhao@marvell.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent b2cb1a90
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -944,6 +944,9 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
	}
	if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING)
		mwifiex_init_fw_complete(adapter);

	if (adapter->if_ops.card_reset)
		adapter->if_ops.card_reset(adapter);
}

/*
+1 −0
Original line number Diff line number Diff line
@@ -600,6 +600,7 @@ struct mwifiex_if_ops {
	int (*event_complete) (struct mwifiex_adapter *, struct sk_buff *);
	int (*data_complete) (struct mwifiex_adapter *, struct sk_buff *);
	int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *);
	void (*card_reset) (struct mwifiex_adapter *);
};

struct mwifiex_adapter {
+33 −0
Original line number Diff line number Diff line
@@ -1748,6 +1748,37 @@ mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port)
		port, card->mp_data_port_mask);
}

static struct mmc_host *reset_host;
static void sdio_card_reset_worker(struct work_struct *work)
{
	/* The actual reset operation must be run outside of driver thread.
	 * This is because mmc_remove_host() will cause the device to be
	 * instantly destroyed, and the driver then needs to end its thread,
	 * leading to a deadlock.
	 *
	 * We run it in a totally independent workqueue.
	 */

	pr_err("Resetting card...\n");
	mmc_remove_host(reset_host);
	/* 20ms delay is based on experiment with sdhci controller */
	mdelay(20);
	mmc_add_host(reset_host);
}
static DECLARE_WORK(card_reset_work, sdio_card_reset_worker);

/* This function resets the card */
static void mwifiex_sdio_card_reset(struct mwifiex_adapter *adapter)
{
	struct sdio_mmc_card *card = adapter->card;

	if (work_pending(&card_reset_work))
		return;

	reset_host = card->func->card->host;
	schedule_work(&card_reset_work);
}

static struct mwifiex_if_ops sdio_ops = {
	.init_if = mwifiex_init_sdio,
	.cleanup_if = mwifiex_cleanup_sdio,
@@ -1766,6 +1797,7 @@ static struct mwifiex_if_ops sdio_ops = {
	.cleanup_mpa_buf = mwifiex_cleanup_mpa_buf,
	.cmdrsp_complete = mwifiex_sdio_cmdrsp_complete,
	.event_complete = mwifiex_sdio_event_complete,
	.card_reset = mwifiex_sdio_card_reset,
};

/*
@@ -1803,6 +1835,7 @@ mwifiex_sdio_cleanup_module(void)
	/* Set the flag as user is removing this module. */
	user_rmmod = 1;

	cancel_work_sync(&card_reset_work);
	sdio_unregister_driver(&mwifiex_sdio);
}

+1 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>

#include "main.h"