[PATCH] troubleshoot broadcom wireless lockup in 5.2rc1

From: Brian Masney
Date: Sun May 26 2019 - 15:36:40 EST


Signed-off-by: Brian Masney <masneyb@xxxxxxxxxxxxx>
---
drivers/mmc/core/core.c | 15 ++++
.../broadcom/brcm80211/brcmfmac/bcmsdh.c | 32 ++++---
.../broadcom/brcm80211/brcmfmac/sdio.c | 85 ++++++++++++-------
include/linux/mmc/host.h | 1 +
4 files changed, 93 insertions(+), 40 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 6db36dc870b5..768acabf029b 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -814,7 +814,22 @@ int __mmc_claim_host(struct mmc_host *host, struct mmc_ctx *ctx,
if (stop || !host->claimed || mmc_ctx_matches(host, ctx, task))
break;
spin_unlock_irqrestore(&host->lock, flags);
+
+ if (ctx != NULL && ctx->descr != NULL) {
+ WARN_ON(1);
+ dev_info(&host->class_dev, "%s: FIXME - before schedule() - descr=%s, claimer=%s\n",
+ __func__, ctx->descr,
+ host->claimer != NULL ? host->claimer->descr : NULL);
+ }
+
schedule();
+
+ if (ctx != NULL && ctx->descr != NULL) {
+ dev_info(&host->class_dev, "%s: FIXME - after schedule() - descr=%s, claimer=%s\n",
+ __func__, ctx->descr,
+ host->claimer != NULL ? host->claimer->descr : NULL);
+ }
+
spin_lock_irqsave(&host->lock, flags);
}
set_current_state(TASK_RUNNING);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
index 60aede5abb4d..aa947fcea736 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
@@ -47,6 +47,8 @@
#include "sdio.h"
#include "core.h"
#include "common.h"
+#include "../../../../../mmc/core/host.h"
+#include "../../../../../mmc/core/core.h"

#define SDIOH_API_ACCESS_RETRY_LIMIT 2

@@ -59,6 +61,16 @@

#define BRCMF_DEFAULT_RXGLOM_SIZE 32 /* max rx frames in glom chain */

+static void sdio_claim_host_with_descr(struct sdio_func *func,
+ const char *descr)
+{
+ struct mmc_ctx mmc_ctx;
+
+ mmc_ctx.task = NULL;
+ mmc_ctx.descr = descr;
+ __mmc_claim_host(func->card->host, &mmc_ctx, NULL);
+}
+
struct brcmf_sdiod_freezer {
atomic_t freezing;
atomic_t thread_count;
@@ -132,7 +144,7 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
}
sdiodev->irq_wake = true;

- sdio_claim_host(sdiodev->func1);
+ sdio_claim_host_with_descr(sdiodev->func1, __func__);

if (sdiodev->bus_if->chip == BRCM_CC_43362_CHIP_ID) {
/* assign GPIO to SDIO core */
@@ -162,7 +174,7 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
sdio_release_host(sdiodev->func1);
} else {
brcmf_dbg(SDIO, "Entering\n");
- sdio_claim_host(sdiodev->func1);
+ sdio_claim_host_with_descr(sdiodev->func1, __func__);
sdio_claim_irq(sdiodev->func1, brcmf_sdiod_ib_irqhandler);
sdio_claim_irq(sdiodev->func2, brcmf_sdiod_dummy_irqhandler);
sdio_release_host(sdiodev->func1);
@@ -183,7 +195,7 @@ void brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev)
struct brcmfmac_sdio_pd *pdata;

pdata = &sdiodev->settings->bus.sdio;
- sdio_claim_host(sdiodev->func1);
+ sdio_claim_host_with_descr(sdiodev->func1, __func__);
brcmf_sdiod_func0_wb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
brcmf_sdiod_func0_wb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
sdio_release_host(sdiodev->func1);
@@ -199,7 +211,7 @@ void brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev)
}

if (sdiodev->sd_irq_requested) {
- sdio_claim_host(sdiodev->func1);
+ sdio_claim_host_with_descr(sdiodev->func1, __func__);
sdio_release_irq(sdiodev->func2);
sdio_release_irq(sdiodev->func1);
sdio_release_host(sdiodev->func1);
@@ -695,7 +707,7 @@ brcmf_sdiod_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
else
dsize = size;

- sdio_claim_host(sdiodev->func1);
+ sdio_claim_host_with_descr(sdiodev->func1, __func__);

/* Do the transfer(s) */
while (size) {
@@ -827,7 +839,7 @@ static int brcmf_sdiod_freezer_on(struct brcmf_sdio_dev *sdiodev)
brcmf_sdio_trigger_dpc(sdiodev->bus);
wait_event(sdiodev->freezer->thread_freeze,
atomic_read(expect) == sdiodev->freezer->frozen_count);
- sdio_claim_host(sdiodev->func1);
+ sdio_claim_host_with_descr(sdiodev->func1, __func__);
res = brcmf_sdio_sleep(sdiodev->bus, true);
sdio_release_host(sdiodev->func1);
return res;
@@ -835,7 +847,7 @@ static int brcmf_sdiod_freezer_on(struct brcmf_sdio_dev *sdiodev)

static void brcmf_sdiod_freezer_off(struct brcmf_sdio_dev *sdiodev)
{
- sdio_claim_host(sdiodev->func1);
+ sdio_claim_host_with_descr(sdiodev->func1, __func__);
brcmf_sdio_sleep(sdiodev->bus, false);
sdio_release_host(sdiodev->func1);
atomic_set(&sdiodev->freezer->freezing, 0);
@@ -887,12 +899,12 @@ static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
brcmf_sdiod_freezer_detach(sdiodev);

/* Disable Function 2 */
- sdio_claim_host(sdiodev->func2);
+ sdio_claim_host_with_descr(sdiodev->func2, __func__);
sdio_disable_func(sdiodev->func2);
sdio_release_host(sdiodev->func2);

/* Disable Function 1 */
- sdio_claim_host(sdiodev->func1);
+ sdio_claim_host_with_descr(sdiodev->func1, __func__);
sdio_disable_func(sdiodev->func1);
sdio_release_host(sdiodev->func1);

@@ -915,7 +927,7 @@ static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
{
int ret = 0;

- sdio_claim_host(sdiodev->func1);
+ sdio_claim_host_with_descr(sdiodev->func1, __func__);

ret = sdio_set_block_size(sdiodev->func1, SDIO_FUNC1_BLOCKSIZE);
if (ret) {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index 22b73da42822..31acdb347e59 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -45,6 +45,8 @@
#include "core.h"
#include "common.h"
#include "bcdc.h"
+#include "../../../../../mmc/core/host.h"
+#include "../../../../../mmc/core/core.h"

#define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500)
#define CTL_DONE_TIMEOUT msecs_to_jiffies(2500)
@@ -651,6 +653,16 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = {
BRCMF_FW_ENTRY(CY_CC_43012_CHIP_ID, 0xFFFFFFFF, 43012)
};

+static void sdio_claim_host_with_descr(struct sdio_func *func,
+ const char *descr)
+{
+ struct mmc_ctx mmc_ctx;
+
+ mmc_ctx.task = NULL;
+ mmc_ctx.descr = descr;
+ __mmc_claim_host(func->card->host, &mmc_ctx, NULL);
+}
+
static void pkt_align(struct sk_buff *p, int len, int align)
{
uint datalign;
@@ -995,7 +1007,7 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
struct sdpcm_shared_le sh_le;
__le32 addr_le;

- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);
brcmf_sdio_bus_sleep(bus, false, false);

/*
@@ -1583,7 +1595,7 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)
* read directly into the chained packet, or allocate a large
* packet and and copy into the chain.
*/
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);
errcode = brcmf_sdiod_recv_chain(bus->sdiodev,
&bus->glom, dlen);
sdio_release_host(bus->sdiodev->func1);
@@ -1594,7 +1606,8 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)
brcmf_err("glom read of %d bytes failed: %d\n",
dlen, errcode);

- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
brcmf_sdio_rxfail(bus, true, false);
bus->sdcnt.rxglomfail++;
brcmf_sdio_free_glom(bus);
@@ -1608,7 +1621,7 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)

rd_new.seq_num = rxseq;
rd_new.len = dlen;
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);
errcode = brcmf_sdio_hdparse(bus, pfirst->data, &rd_new,
BRCMF_SDIO_FT_SUPER);
sdio_release_host(bus->sdiodev->func1);
@@ -1626,7 +1639,8 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)

rd_new.len = pnext->len;
rd_new.seq_num = rxseq++;
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
errcode = brcmf_sdio_hdparse(bus, pnext->data, &rd_new,
BRCMF_SDIO_FT_SUB);
sdio_release_host(bus->sdiodev->func1);
@@ -1638,7 +1652,8 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)

if (errcode) {
/* Terminate frame on error */
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
brcmf_sdio_rxfail(bus, true, false);
bus->sdcnt.rxglomfail++;
brcmf_sdio_free_glom(bus);
@@ -1849,7 +1864,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)

rd->len_left = rd->len;
/* read header first for unknow frame length */
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);
if (!rd->len) {
ret = brcmf_sdiod_recv_buf(bus->sdiodev,
bus->rxhdr, BRCMF_FIRSTREAD);
@@ -1916,7 +1931,8 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
brcmf_err("read %d bytes from channel %d failed: %d\n",
rd->len, rd->channel, ret);
brcmu_pkt_buf_free_skb(pkt);
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
brcmf_sdio_rxfail(bus, true,
RETRYCHAN(rd->channel));
sdio_release_host(bus->sdiodev->func1);
@@ -1930,7 +1946,8 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
} else {
memcpy(bus->rxhdr, pkt->data, SDPCM_HDRLEN);
rd_new.seq_num = rd->seq_num;
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
if (brcmf_sdio_hdparse(bus, bus->rxhdr, &rd_new,
BRCMF_SDIO_FT_NORMAL)) {
rd->len = 0;
@@ -1963,7 +1980,8 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
rd_new.seq_num);
/* Force retry w/normal header read */
rd->len = 0;
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
brcmf_sdio_rxfail(bus, false, true);
sdio_release_host(bus->sdiodev->func1);
brcmu_pkt_buf_free_skb(pkt);
@@ -1988,7 +2006,8 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
} else {
brcmf_err("%s: glom superframe w/o "
"descriptor!\n", __func__);
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
brcmf_sdio_rxfail(bus, false, false);
sdio_release_host(bus->sdiodev->func1);
}
@@ -2267,7 +2286,7 @@ static int brcmf_sdio_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
if (ret)
goto done;

- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);
ret = brcmf_sdiod_send_pkt(bus->sdiodev, pktq);
bus->sdcnt.f2txdata++;

@@ -2330,7 +2349,8 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
/* In poll mode, need to check for other events */
if (!bus->intr) {
/* Check device status, signal pending interrupt */
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
intstatus = brcmf_sdiod_readl(bus->sdiodev,
intstat_addr, &ret);
sdio_release_host(bus->sdiodev->func1);
@@ -2442,7 +2462,7 @@ static void brcmf_sdio_bus_stop(struct device *dev)
}

if (sdiodev->state != BRCMF_SDIOD_NOMEDIUM) {
- sdio_claim_host(sdiodev->func1);
+ sdio_claim_host_with_descr(sdiodev->func1, __func__);

/* Enable clock for device interrupts */
brcmf_sdio_bus_sleep(bus, false, false);
@@ -2552,7 +2572,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)

brcmf_dbg(SDIO, "Enter\n");

- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);

/* If waiting for HTAVAIL, check status */
if (!bus->sr_enabled && bus->clkstate == CLK_PENDING) {
@@ -2658,7 +2678,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)

if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) &&
data_ok(bus)) {
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);
if (bus->ctrl_frame_stat) {
err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf,
bus->ctrl_frame_len);
@@ -2682,7 +2702,8 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
brcmf_err("failed backplane access over SDIO, halting operation\n");
atomic_set(&bus->intstatus, 0);
if (bus->ctrl_frame_stat) {
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
if (bus->ctrl_frame_stat) {
bus->ctrl_frame_err = -ENODEV;
wmb();
@@ -2904,7 +2925,7 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
CTL_DONE_TIMEOUT);
ret = 0;
if (bus->ctrl_frame_stat) {
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);
if (bus->ctrl_frame_stat) {
brcmf_dbg(SDIO, "ctrl_frame timeout\n");
bus->ctrl_frame_stat = false;
@@ -3048,7 +3069,7 @@ static int brcmf_sdio_assert_info(struct seq_file *seq, struct brcmf_sdio *bus,
return 0;
}

- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);
if (sh->assert_file_addr != 0) {
error = brcmf_sdiod_ramrw(bus->sdiodev, false,
sh->assert_file_addr, (u8 *)file, 80);
@@ -3340,7 +3361,7 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus,
int bcmerror;
u32 rstvec;

- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);
brcmf_sdio_clkctl(bus, CLK_AVAIL, false);

rstvec = get_unaligned_le32(fw->data);
@@ -3564,7 +3585,7 @@ static int brcmf_sdio_bus_get_memdump(struct device *dev, void *data,

address = bus->ci->rambase;
offset = err = 0;
- sdio_claim_host(sdiodev->func1);
+ sdio_claim_host_with_descr(sdiodev->func1, __func__);
while (offset < mem_size) {
len = ((offset + MEMBLOCK) < mem_size) ? MEMBLOCK :
mem_size - offset;
@@ -3637,7 +3658,8 @@ static void brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
if (!bus->dpc_triggered) {
u8 devpend;

- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
devpend = brcmf_sdiod_func0_rb(bus->sdiodev,
SDIO_CCCR_INTx, NULL);
sdio_release_host(bus->sdiodev->func1);
@@ -3666,7 +3688,8 @@ static void brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
bus->console.count += jiffies_to_msecs(BRCMF_WD_POLL);
if (bus->console.count >= bus->console_interval) {
bus->console.count -= bus->console_interval;
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
/* Make sure backplane clock is on */
brcmf_sdio_bus_sleep(bus, false, false);
if (brcmf_sdio_readconsole(bus) < 0)
@@ -3685,7 +3708,8 @@ static void brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
bus->idlecount++;
if (bus->idlecount > bus->idletime) {
brcmf_dbg(SDIO, "idle\n");
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
brcmf_sdio_wd_timer(bus, false);
bus->idlecount = 0;
brcmf_sdio_bus_sleep(bus, true, false);
@@ -3903,7 +3927,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
u32 drivestrength;

sdiodev = bus->sdiodev;
- sdio_claim_host(sdiodev->func1);
+ sdio_claim_host_with_descr(sdiodev->func1, __func__);

pr_debug("F1 signature read @0x18000000=0x%4x\n",
brcmf_sdiod_readl(sdiodev, SI_ENUM_BASE, NULL));
@@ -4147,7 +4171,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
bus->sdcnt.tickcnt = 0;
brcmf_sdio_wd_timer(bus, true);

- sdio_claim_host(sdiod->func1);
+ sdio_claim_host_with_descr(sdiod->func1, __func__);

/* Make sure backplane clock is on, needed to generate F2 interrupt */
brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
@@ -4255,7 +4279,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
err = brcmf_attach(sdiod->dev, sdiod->settings);
if (err != 0) {
brcmf_err("brcmf_attach failed\n");
- sdio_claim_host(sdiod->func1);
+ sdio_claim_host_with_descr(sdiod->func1, __func__);
goto checkdied;
}

@@ -4361,7 +4385,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
bus->blocksize = bus->sdiodev->func2->cur_blksize;
bus->roundup = min(max_roundup, bus->blocksize);

- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);

/* Disable F2 to clear any intermediate frame state on the dongle */
sdio_disable_func(bus->sdiodev->func2);
@@ -4428,7 +4452,8 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)

if (bus->ci) {
if (bus->sdiodev->state != BRCMF_SDIOD_NOMEDIUM) {
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
brcmf_sdio_wd_timer(bus, false);
brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
/* Leave the device in state where it is
@@ -4485,7 +4510,7 @@ int brcmf_sdio_sleep(struct brcmf_sdio *bus, bool sleep)
{
int ret;

- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);
ret = brcmf_sdio_bus_sleep(bus, sleep, false);
sdio_release_host(bus->sdiodev->func1);

diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 43d0f0c496f6..6ccc76150f45 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -267,6 +267,7 @@ struct mmc_supply {
};

struct mmc_ctx {
+ const char *descr;
struct task_struct *task;
};

--
2.20.1


--SLDf9lqlvOQaIe6s--