rpcd: iwinfo plugin fixes
[openwrt.git] / package / kernel / mac80211 / patches / 351-0003-brcmfmac-Fix-kernel-oops-in-failed-chip_attach.patch
1 From: Christian Daudt <csd@broadcom.com>
2 Date: Wed, 11 May 2016 15:06:48 -0700
3 Subject: [PATCH] brcmfmac: Fix kernel oops in failed chip_attach
4
5 When chip attach fails, brcmf_sdiod_intr_unregister is being called
6 but that is too early as sdiodev->settings has not been set yet
7 nor has brcmf_sdiod_intr_register been called.
8 Change to use oob_irq_requested + newly created sd_irq_requested
9 to decide on what to unregister at intr_unregister time.
10
11 Steps to reproduce problem:
12 - modprobe brcmfmac using buggy FW
13 - rmmod brcmfmac
14 - modprobe brcmfmac again.
15
16 If done with a buggy firmware, brcm_chip_attach will fail on the
17 2nd modprobe triggering the call to intr_unregister and the
18 kernel oops when attempting to de-reference sdiodev->settings->bus.sdio
19 which has not yet been set.
20
21 Signed-off-by: Christian Daudt <csd@broadcom.com>
22 Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
23 ---
24
25 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
26 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
27 @@ -166,6 +166,7 @@ int brcmf_sdiod_intr_register(struct brc
28                 sdio_claim_irq(sdiodev->func[1], brcmf_sdiod_ib_irqhandler);
29                 sdio_claim_irq(sdiodev->func[2], brcmf_sdiod_dummy_irqhandler);
30                 sdio_release_host(sdiodev->func[1]);
31 +               sdiodev->sd_irq_requested = true;
32         }
33  
34         return 0;
35 @@ -173,27 +174,30 @@ int brcmf_sdiod_intr_register(struct brc
36  
37  int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev)
38  {
39 -       struct brcmfmac_sdio_pd *pdata;
40  
41 -       brcmf_dbg(SDIO, "Entering\n");
42 +       brcmf_dbg(SDIO, "Entering oob=%d sd=%d\n",
43 +                 sdiodev->oob_irq_requested,
44 +                 sdiodev->sd_irq_requested);
45  
46 -       pdata = &sdiodev->settings->bus.sdio;
47 -       if (pdata->oob_irq_supported) {
48 +       if (sdiodev->oob_irq_requested) {
49 +               struct brcmfmac_sdio_pd *pdata;
50 +
51 +               pdata = &sdiodev->settings->bus.sdio;
52                 sdio_claim_host(sdiodev->func[1]);
53                 brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
54                 brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
55                 sdio_release_host(sdiodev->func[1]);
56  
57 -               if (sdiodev->oob_irq_requested) {
58 -                       sdiodev->oob_irq_requested = false;
59 -                       if (sdiodev->irq_wake) {
60 -                               disable_irq_wake(pdata->oob_irq_nr);
61 -                               sdiodev->irq_wake = false;
62 -                       }
63 -                       free_irq(pdata->oob_irq_nr, &sdiodev->func[1]->dev);
64 -                       sdiodev->irq_en = false;
65 +               sdiodev->oob_irq_requested = false;
66 +               if (sdiodev->irq_wake) {
67 +                       disable_irq_wake(pdata->oob_irq_nr);
68 +                       sdiodev->irq_wake = false;
69                 }
70 -       } else {
71 +               free_irq(pdata->oob_irq_nr, &sdiodev->func[1]->dev);
72 +               sdiodev->irq_en = false;
73 +       }
74 +
75 +       if (sdiodev->sd_irq_requested) {
76                 sdio_claim_host(sdiodev->func[1]);
77                 sdio_release_irq(sdiodev->func[2]);
78                 sdio_release_irq(sdiodev->func[1]);
79 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
80 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
81 @@ -186,6 +186,7 @@ struct brcmf_sdio_dev {
82         struct brcmf_bus *bus_if;
83         struct brcmf_mp_device *settings;
84         bool oob_irq_requested;
85 +       bool sd_irq_requested;
86         bool irq_en;                    /* irq enable flags */
87         spinlock_t irq_en_lock;
88         bool irq_wake;                  /* irq wake enable flags */