mac80211: brcmfmac: backport fixes for 4.7 and 4.8
[openwrt/svn-archive/archive.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 */