>From 496c4deaa3787bf619baff58493142e11cd6757f Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Sun, 26 May 2019 15:36:40 -0400 Subject: [PATCH] troubleshoot broadcom wireless lockup in 5.2rc1 Signed-off-by: Brian Masney --- 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