mac80211: brcmfmac: really add early fw crash recovery
[openwrt/openwrt.git] / package / kernel / mac80211 / patches / 340-v5.2-0003-brcmfmac-reset-PCIe-bus-on-a-firmware-crash.patch
1 From 4684997d9eea29380000e062755aa6d368d789a3 Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
3 Date: Tue, 26 Feb 2019 14:11:19 +0100
4 Subject: [PATCH] brcmfmac: reset PCIe bus on a firmware crash
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 This includes bus reset & reloading a firmware. It should be sufficient
10 for a user space to (setup and) use a wireless device again.
11
12 Support for reset on USB & SDIO can be added later.
13
14 Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
15 Reviewed-by: Arend van Spriel <arend.vanspriel@broadcom.com>
16 Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
17 ---
18 .../broadcom/brcm80211/brcmfmac/bus.h | 10 ++++++
19 .../broadcom/brcm80211/brcmfmac/core.c | 12 +++++++
20 .../broadcom/brcm80211/brcmfmac/core.h | 2 ++
21 .../broadcom/brcm80211/brcmfmac/pcie.c | 35 +++++++++++++++++++
22 4 files changed, 59 insertions(+)
23
24 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
25 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
26 @@ -87,6 +87,7 @@ struct brcmf_bus_ops {
27 void (*wowl_config)(struct device *dev, bool enabled);
28 size_t (*get_ramsize)(struct device *dev);
29 int (*get_memdump)(struct device *dev, void *data, size_t len);
30 + int (*reset)(struct device *dev);
31 };
32
33
34 @@ -214,6 +215,15 @@ int brcmf_bus_get_memdump(struct brcmf_b
35 return bus->ops->get_memdump(bus->dev, data, len);
36 }
37
38 +static inline
39 +int brcmf_bus_reset(struct brcmf_bus *bus)
40 +{
41 + if (!bus->ops->reset)
42 + return -EOPNOTSUPP;
43 +
44 + return bus->ops->reset(bus->dev);
45 +}
46 +
47 /*
48 * interface functions from common layer
49 */
50 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
51 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
52 @@ -1080,6 +1080,14 @@ static int brcmf_revinfo_read(struct seq
53 return 0;
54 }
55
56 +static void brcmf_core_bus_reset(struct work_struct *work)
57 +{
58 + struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
59 + bus_reset);
60 +
61 + brcmf_bus_reset(drvr->bus_if);
62 +}
63 +
64 int brcmf_bus_started(struct device *dev)
65 {
66 int ret = -1;
67 @@ -1161,6 +1169,8 @@ int brcmf_bus_started(struct device *dev
68 #endif
69 #endif /* CONFIG_INET */
70
71 + INIT_WORK(&drvr->bus_reset, brcmf_core_bus_reset);
72 +
73 return 0;
74
75 fail:
76 @@ -1282,6 +1292,8 @@ void brcmf_fw_crashed(struct device *dev
77 bphy_err(drvr, "Firmware has halted or crashed\n");
78
79 brcmf_dev_coredump(dev);
80 +
81 + schedule_work(&drvr->bus_reset);
82 }
83
84 void brcmf_detach(struct device *dev)
85 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
86 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
87 @@ -146,6 +146,8 @@ struct brcmf_pub {
88 struct notifier_block inet6addr_notifier;
89 struct brcmf_mp_device *settings;
90
91 + struct work_struct bus_reset;
92 +
93 /* Pointer needed by OpenWrt due to backporting some fixes */
94 void *cfg80211_ops;
95 };
96 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
97 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
98 @@ -343,6 +343,8 @@ static const u32 brcmf_ring_itemsize[BRC
99 BRCMF_D2H_MSGRING_RX_COMPLETE_ITEMSIZE
100 };
101
102 +static void brcmf_pcie_setup(struct device *dev, const struct firmware *fw,
103 + void *nvram, u32 nvram_len);
104
105 static u32
106 brcmf_pcie_read_reg32(struct brcmf_pciedev_info *devinfo, u32 reg_offset)
107 @@ -1382,6 +1384,45 @@ static int brcmf_pcie_get_memdump(struct
108 }
109
110
111 +static int brcmf_pcie_reset(struct device *dev)
112 +{
113 + struct brcmf_bus *bus_if = dev_get_drvdata(dev);
114 + struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
115 + struct brcmf_pciedev_info *devinfo = buspub->devinfo;
116 + u16 domain_nr;
117 + u16 bus_nr;
118 + int err;
119 +
120 + brcmf_detach(dev);
121 +
122 + brcmf_pcie_release_irq(devinfo);
123 + brcmf_pcie_release_scratchbuffers(devinfo);
124 + brcmf_pcie_release_ringbuffers(devinfo);
125 + brcmf_pcie_reset_device(devinfo);
126 +
127 + err = brcmf_fw_map_chip_to_name(devinfo->ci->chip, devinfo->ci->chiprev,
128 + brcmf_pcie_fwnames,
129 + ARRAY_SIZE(brcmf_pcie_fwnames),
130 + devinfo->fw_name, devinfo->nvram_name);
131 + if (err) {
132 + dev_err(dev, "Failed to prepare FW request\n");
133 + return err;
134 + }
135 +
136 + domain_nr = pci_domain_nr(devinfo->pdev->bus) + 1;
137 + bus_nr = devinfo->pdev->bus->number;
138 + err = brcmf_fw_get_firmwares_pcie(bus_if->dev, BRCMF_FW_REQUEST_NVRAM |
139 + BRCMF_FW_REQ_NV_OPTIONAL,
140 + devinfo->fw_name, devinfo->nvram_name,
141 + brcmf_pcie_setup, domain_nr, bus_nr);
142 + if (err) {
143 + dev_err(dev, "Failed to prepare FW request\n");
144 + return err;
145 + }
146 +
147 + return err;
148 +}
149 +
150 static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
151 .txdata = brcmf_pcie_tx,
152 .stop = brcmf_pcie_down,
153 @@ -1390,6 +1431,7 @@ static const struct brcmf_bus_ops brcmf_
154 .wowl_config = brcmf_pcie_wowl_config,
155 .get_ramsize = brcmf_pcie_get_ramsize,
156 .get_memdump = brcmf_pcie_get_memdump,
157 + .reset = brcmf_pcie_reset,
158 };
159
160