mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-28 11:18:45 +07:00
brcmfmac: Fix kernel oops in failed chip_attach
When chip attach fails, brcmf_sdiod_intr_unregister is being called but that is too early as sdiodev->settings has not been set yet nor has brcmf_sdiod_intr_register been called. Change to use oob_irq_requested + newly created sd_irq_requested to decide on what to unregister at intr_unregister time. Steps to reproduce problem: - modprobe brcmfmac using buggy FW - rmmod brcmfmac - modprobe brcmfmac again. If done with a buggy firmware, brcm_chip_attach will fail on the 2nd modprobe triggering the call to intr_unregister and the kernel oops when attempting to de-reference sdiodev->settings->bus.sdio which has not yet been set. Signed-off-by: Christian Daudt <csd@broadcom.com> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
parent
83e41e7781
commit
b88a2e8039
@ -166,6 +166,7 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
|
||||
sdio_claim_irq(sdiodev->func[1], brcmf_sdiod_ib_irqhandler);
|
||||
sdio_claim_irq(sdiodev->func[2], brcmf_sdiod_dummy_irqhandler);
|
||||
sdio_release_host(sdiodev->func[1]);
|
||||
sdiodev->sd_irq_requested = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -173,27 +174,30 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
|
||||
|
||||
int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
struct brcmfmac_sdio_pd *pdata;
|
||||
|
||||
brcmf_dbg(SDIO, "Entering\n");
|
||||
brcmf_dbg(SDIO, "Entering oob=%d sd=%d\n",
|
||||
sdiodev->oob_irq_requested,
|
||||
sdiodev->sd_irq_requested);
|
||||
|
||||
pdata = &sdiodev->settings->bus.sdio;
|
||||
if (pdata->oob_irq_supported) {
|
||||
if (sdiodev->oob_irq_requested) {
|
||||
struct brcmfmac_sdio_pd *pdata;
|
||||
|
||||
pdata = &sdiodev->settings->bus.sdio;
|
||||
sdio_claim_host(sdiodev->func[1]);
|
||||
brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
|
||||
brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
|
||||
sdio_release_host(sdiodev->func[1]);
|
||||
|
||||
if (sdiodev->oob_irq_requested) {
|
||||
sdiodev->oob_irq_requested = false;
|
||||
if (sdiodev->irq_wake) {
|
||||
disable_irq_wake(pdata->oob_irq_nr);
|
||||
sdiodev->irq_wake = false;
|
||||
}
|
||||
free_irq(pdata->oob_irq_nr, &sdiodev->func[1]->dev);
|
||||
sdiodev->irq_en = false;
|
||||
sdiodev->oob_irq_requested = false;
|
||||
if (sdiodev->irq_wake) {
|
||||
disable_irq_wake(pdata->oob_irq_nr);
|
||||
sdiodev->irq_wake = false;
|
||||
}
|
||||
} else {
|
||||
free_irq(pdata->oob_irq_nr, &sdiodev->func[1]->dev);
|
||||
sdiodev->irq_en = false;
|
||||
}
|
||||
|
||||
if (sdiodev->sd_irq_requested) {
|
||||
sdio_claim_host(sdiodev->func[1]);
|
||||
sdio_release_irq(sdiodev->func[2]);
|
||||
sdio_release_irq(sdiodev->func[1]);
|
||||
|
@ -186,6 +186,7 @@ struct brcmf_sdio_dev {
|
||||
struct brcmf_bus *bus_if;
|
||||
struct brcmf_mp_device *settings;
|
||||
bool oob_irq_requested;
|
||||
bool sd_irq_requested;
|
||||
bool irq_en; /* irq enable flags */
|
||||
spinlock_t irq_en_lock;
|
||||
bool irq_wake; /* irq wake enable flags */
|
||||
|
Loading…
Reference in New Issue
Block a user