Skip to content

Commit

Permalink
brcmfmac: reset SDIO bus on a firmware crash
Browse files Browse the repository at this point in the history
commit 4684997 ("brcmfmac: reset PCIe bus on a firmware crash")
adds a reset function to recover firmware trap for PCIe bus. This commit
adds an implementation for SDIO bus.

Upon SDIO firmware trap, do below:
 - Remove the device
 - Reset hardware
 - Probe the device again

Signed-off-by: Chi-Hsien Lin <[email protected]>
Signed-off-by: Kalle Valo <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
  • Loading branch information
cy-chihsien authored and Kalle Valo committed Jul 14, 2020
1 parent 0d9de08 commit 7836102
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 3 deletions.
4 changes: 2 additions & 2 deletions drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
Original file line number Diff line number Diff line change
Expand Up @@ -863,7 +863,7 @@ static void brcmf_sdiod_freezer_detach(struct brcmf_sdio_dev *sdiodev)
}
#endif /* CONFIG_PM_SLEEP */

static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
{
sdiodev->state = BRCMF_SDIOD_DOWN;
if (sdiodev->bus) {
Expand Down Expand Up @@ -898,7 +898,7 @@ static void brcmf_sdiod_host_fixup(struct mmc_host *host)
host->caps |= MMC_CAP_NONREMOVABLE;
}

static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
{
int ret = 0;
unsigned int f2_blksz = SDIO_FUNC2_BLOCKSIZE;
Expand Down
34 changes: 33 additions & 1 deletion drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/card.h>
#include <linux/mmc/core.h>
#include <linux/semaphore.h>
#include <linux/firmware.h>
#include <linux/module.h>
Expand Down Expand Up @@ -4126,6 +4127,36 @@ int brcmf_sdio_get_fwname(struct device *dev, const char *ext, u8 *fw_name)
return 0;
}

static int brcmf_sdio_bus_reset(struct device *dev)
{
int ret = 0;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;

brcmf_dbg(SDIO, "Enter\n");

/* start by unregistering irqs */
brcmf_sdiod_intr_unregister(sdiodev);

brcmf_sdiod_remove(sdiodev);

/* reset the adapter */
sdio_claim_host(sdiodev->func1);
mmc_hw_reset(sdiodev->func1->card->host);
sdio_release_host(sdiodev->func1);

brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_DOWN);

ret = brcmf_sdiod_probe(sdiodev);
if (ret) {
brcmf_err("Failed to probe after sdio device reset: ret %d\n",
ret);
brcmf_sdiod_remove(sdiodev);
}

return ret;
}

static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
.stop = brcmf_sdio_bus_stop,
.preinit = brcmf_sdio_bus_preinit,
Expand All @@ -4137,7 +4168,8 @@ static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
.get_ramsize = brcmf_sdio_bus_get_ramsize,
.get_memdump = brcmf_sdio_bus_get_memdump,
.get_fwname = brcmf_sdio_get_fwname,
.debugfs_create = brcmf_sdio_debugfs_create
.debugfs_create = brcmf_sdio_debugfs_create,
.reset = brcmf_sdio_bus_reset
};

#define BRCMF_SDIO_FW_CODE 0
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,9 @@ static inline void brcmf_sdiod_freezer_uncount(struct brcmf_sdio_dev *sdiodev)
}
#endif /* CONFIG_PM_SLEEP */

int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev);
int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev);

struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev);
void brcmf_sdio_remove(struct brcmf_sdio *bus);
void brcmf_sdio_isr(struct brcmf_sdio *bus);
Expand Down

0 comments on commit 7836102

Please sign in to comment.