From 0723f988d36b8476fb07fa0e5e00673a1d366416 Mon Sep 17 00:00:00 2001 From: JasonHuang Date: Fri, 11 Aug 2023 04:01:08 -0500 Subject: [PATCH 221/296] brcmfmac: OOB irq support on 43022 DS2 Issue: Observed bus is down when device is in ds2 with oob setting Root cause: 1) In the redownload fw flow, host will try to request_irq again. However, the irq already be registered in the beginning 2) If host readframe too early in the fw redownload flow, we will see "mmc0: Timeout waiting for hardware interrupt" which cause the OS hang or unstable. Fix: Ignore request_irq again. Add re_download_fw flag and some delay after brcmf_sdio_ulp_reinit_fw to make sure re-download fw done Signed-off-by: JasonHuang --- .../broadcom/brcm80211/brcmfmac/bcmsdh.c | 30 ++++++++++--------- .../broadcom/brcm80211/brcmfmac/core.c | 2 ++ .../broadcom/brcm80211/brcmfmac/sdio.c | 11 +++++-- .../broadcom/brcm80211/brcmfmac/sdio.h | 1 + 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index ca3c0ddeabbb..fb426cfd23ce 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -110,25 +110,27 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) if (pdata->oob_irq_supported) { brcmf_dbg(SDIO, "Enter, register OOB IRQ %d\n", pdata->oob_irq_nr); - spin_lock_init(&sdiodev->irq_en_lock); - sdiodev->irq_en = true; + if (!sdiodev->oob_irq_requested) { + spin_lock_init(&sdiodev->irq_en_lock); + sdiodev->irq_en = true; - ret = request_irq(pdata->oob_irq_nr, brcmf_sdiod_oob_irqhandler, + ret = request_irq(pdata->oob_irq_nr, + brcmf_sdiod_oob_irqhandler, pdata->oob_irq_flags, "brcmf_oob_intr", &sdiodev->func1->dev); - if (ret != 0) { - brcmf_err("request_irq failed %d\n", ret); - return ret; - } - sdiodev->oob_irq_requested = true; + if (ret != 0) { + brcmf_err("request_irq failed %d\n", ret); + return ret; + } + sdiodev->oob_irq_requested = true; - ret = enable_irq_wake(pdata->oob_irq_nr); - if (ret != 0) { - brcmf_err("enable_irq_wake failed %d\n", ret); - return ret; + ret = enable_irq_wake(pdata->oob_irq_nr); + if (ret != 0) { + brcmf_err("enable_irq_wake failed %d\n", ret); + return ret; + } + disable_irq_wake(pdata->oob_irq_nr); } - disable_irq_wake(pdata->oob_irq_nr); - sdio_claim_host(sdiodev->func1); if (sdiodev->bus_if->chip == BRCM_CC_43362_CHIP_ID) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index daf19761a479..96a444438006 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -682,6 +682,8 @@ static int brcmf_rx_hdrpull(struct brcmf_pub *drvr, struct sk_buff *skb, } skb->protocol = eth_type_trans(skb, (*ifp)->ndev); + brcmf_dbg(DATA, "protocol: 0x%04X\n", skb->protocol); + return 0; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index e35d4ed65033..47612b6c6ad7 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -3225,8 +3225,13 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) u32 hmb_data = 0; intstatus &= ~I_HMB_HOST_INT; intstatus |= brcmf_sdio_hostmail(bus, &hmb_data); - if (brcmf_sdio_ulp_pre_redownload_check(bus, hmb_data)) + if (brcmf_sdio_ulp_pre_redownload_check(bus, hmb_data)) { + /* Will toggle redownload_fw, after F2 enabled and + * register IRQ. + */ + sdiod->redownload_fw = true; brcmf_sdio_ulp_reinit_fw(bus); + } } sdio_release_host(bus->sdiodev->func1); @@ -3258,7 +3263,8 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) intstatus &= ~I_HMB_FRAME_IND; /* On frame indication, read available frames */ - if ((intstatus & I_HMB_FRAME_IND) && (bus->clkstate == CLK_AVAIL)) { + if ((intstatus & I_HMB_FRAME_IND) && bus->clkstate == CLK_AVAIL && + !sdiod->redownload_fw) { brcmf_sdio_readframes(bus, bus->rxbound); if (!bus->rxpending) intstatus &= ~I_HMB_FRAME_IND; @@ -5258,6 +5264,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, err = brcmf_sdiod_intr_register(sdiod); if (err != 0) brcmf_err("intr register failed:%d\n", err); + bus->sdiodev->redownload_fw = false; } /* If we didn't come up, turn off backplane clock */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h index 7c5fadd5cd03..c79f96ad391f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h @@ -261,6 +261,7 @@ struct brcmf_sdio_dev { const struct firmware *clm_fw; struct brcmf_ulp fmac_ulp; bool ulp; + bool redownload_fw; }; /* sdio core registers */ -- 2.25.1