Return-path: Received: from mail-pa0-f44.google.com ([209.85.220.44]:33539 "EHLO mail-pa0-f44.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755224AbcEDXlg (ORCPT ); Wed, 4 May 2016 19:41:36 -0400 Received: by mail-pa0-f44.google.com with SMTP id xk12so29408899pac.0 for ; Wed, 04 May 2016 16:41:35 -0700 (PDT) From: Christian Daudt To: linux-wireless@vger.kernel.org Cc: Christian Daudt , brcm80211-dev-list@broadcom.com, Brett Rudley , Arend van Spriel , Franky Lin , Hante Meuleman Subject: [PATCH] brcmfmac: Fix 'did not remove int handler' warning Date: Wed, 4 May 2016 16:41:20 -0700 Message-Id: <1462405280-5947-1-git-send-email-csd@broadcom.com> (sfid-20160505_014147_438573_8E312409) Sender: linux-wireless-owner@vger.kernel.org List-ID: brcmf_sdiod_intr_unregister call that removes both func1 and func2 interrupt handlers only called when brcmf_ops_sdio_remove is called for func 1 (which is the 2nd call) but sdio is expecting it to be removed at the end of each sdio_remove call. This is causing 'rmmod bcmrfmac' on a 4356-sdio chip to complain with: WARNING: driver brcmfmac did not remove its interrupt handler! The modification makes calling brcmf_sdiod_intr_unregister multiple times harmless by clearing the variables that track if interrupt handlers have been installed, and then calls it on every brcmf_ops_sdio_remove call instead of just remove for func 1. Note: this needs to be applied on top of "[PATCH] Fix kernel oops in failed chip_attach" Signed-off-by: Christian Daudt --- .../net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 17 +++++++++++------ drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index 09635a9..590cd41 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -172,7 +172,7 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) return 0; } -int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev) +void brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev) { brcmf_dbg(SDIO, "Entering oob=%d sd=%d\n", @@ -195,6 +195,7 @@ int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev) } free_irq(pdata->oob_irq_nr, &sdiodev->func[1]->dev); sdiodev->irq_en = false; + sdiodev->oob_irq_requested = false; } if (sdiodev->sd_irq_requested) { @@ -202,9 +203,8 @@ int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev) sdio_release_irq(sdiodev->func[2]); sdio_release_irq(sdiodev->func[1]); sdio_release_host(sdiodev->func[1]); + sdiodev->sd_irq_requested = false; } - - return 0; } void brcmf_sdiod_change_state(struct brcmf_sdio_dev *sdiodev, @@ -1200,12 +1200,17 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func) brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device); brcmf_dbg(SDIO, "Function: %d\n", func->num); - if (func->num != 1) - return; - bus_if = dev_get_drvdata(&func->dev); if (bus_if) { sdiodev = bus_if->bus_priv.sdio; + + /* start by unregistering irqs */ + brcmf_sdiod_intr_unregister(sdiodev); + + if (func->num != 1) + return; + + /* only proceed with rest of cleanup if func 1 */ brcmf_sdiod_remove(sdiodev); dev_set_drvdata(&sdiodev->func[1]->dev, NULL); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h index c07ad25..f3da32f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h @@ -294,7 +294,7 @@ struct sdpcmd_regs { /* Register/deregister interrupt handler. */ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev); -int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev); +void brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev); /* sdio device register access interface */ u8 brcmf_sdiod_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret); -- 1.9.1