diff options
Diffstat (limited to 'package/kernel/mac80211/patches/340-v5.2-0003-brcmfmac-reset-PCIe-bus-on-a-firmware-crash.patch')
-rw-r--r-- | package/kernel/mac80211/patches/340-v5.2-0003-brcmfmac-reset-PCIe-bus-on-a-firmware-crash.patch | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/340-v5.2-0003-brcmfmac-reset-PCIe-bus-on-a-firmware-crash.patch b/package/kernel/mac80211/patches/340-v5.2-0003-brcmfmac-reset-PCIe-bus-on-a-firmware-crash.patch new file mode 100644 index 0000000000..96692c99e5 --- /dev/null +++ b/package/kernel/mac80211/patches/340-v5.2-0003-brcmfmac-reset-PCIe-bus-on-a-firmware-crash.patch @@ -0,0 +1,160 @@ +From 4684997d9eea29380000e062755aa6d368d789a3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl> +Date: Tue, 26 Feb 2019 14:11:19 +0100 +Subject: [PATCH] brcmfmac: reset PCIe bus on a firmware crash +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This includes bus reset & reloading a firmware. It should be sufficient +for a user space to (setup and) use a wireless device again. + +Support for reset on USB & SDIO can be added later. + +Signed-off-by: Rafał Miłecki <rafal@milecki.pl> +Reviewed-by: Arend van Spriel <arend.vanspriel@broadcom.com> +Signed-off-by: Kalle Valo <kvalo@codeaurora.org> +--- + .../broadcom/brcm80211/brcmfmac/bus.h | 10 ++++++ + .../broadcom/brcm80211/brcmfmac/core.c | 12 +++++++ + .../broadcom/brcm80211/brcmfmac/core.h | 2 ++ + .../broadcom/brcm80211/brcmfmac/pcie.c | 35 +++++++++++++++++++ + 4 files changed, 59 insertions(+) + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +@@ -87,6 +87,7 @@ struct brcmf_bus_ops { + void (*wowl_config)(struct device *dev, bool enabled); + size_t (*get_ramsize)(struct device *dev); + int (*get_memdump)(struct device *dev, void *data, size_t len); ++ int (*reset)(struct device *dev); + }; + + +@@ -214,6 +215,15 @@ int brcmf_bus_get_memdump(struct brcmf_b + return bus->ops->get_memdump(bus->dev, data, len); + } + ++static inline ++int brcmf_bus_reset(struct brcmf_bus *bus) ++{ ++ if (!bus->ops->reset) ++ return -EOPNOTSUPP; ++ ++ return bus->ops->reset(bus->dev); ++} ++ + /* + * interface functions from common layer + */ +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +@@ -1080,6 +1080,14 @@ static int brcmf_revinfo_read(struct seq + return 0; + } + ++static void brcmf_core_bus_reset(struct work_struct *work) ++{ ++ struct brcmf_pub *drvr = container_of(work, struct brcmf_pub, ++ bus_reset); ++ ++ brcmf_bus_reset(drvr->bus_if); ++} ++ + int brcmf_bus_started(struct device *dev) + { + int ret = -1; +@@ -1161,6 +1169,8 @@ int brcmf_bus_started(struct device *dev + #endif + #endif /* CONFIG_INET */ + ++ INIT_WORK(&drvr->bus_reset, brcmf_core_bus_reset); ++ + return 0; + + fail: +@@ -1282,6 +1292,8 @@ void brcmf_fw_crashed(struct device *dev + bphy_err(drvr, "Firmware has halted or crashed\n"); + + brcmf_dev_coredump(dev); ++ ++ schedule_work(&drvr->bus_reset); + } + + void brcmf_detach(struct device *dev) +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +@@ -146,6 +146,8 @@ struct brcmf_pub { + struct notifier_block inet6addr_notifier; + struct brcmf_mp_device *settings; + ++ struct work_struct bus_reset; ++ + /* Pointer needed by OpenWrt due to backporting some fixes */ + void *cfg80211_ops; + }; +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -343,6 +343,8 @@ static const u32 brcmf_ring_itemsize[BRC + BRCMF_D2H_MSGRING_RX_COMPLETE_ITEMSIZE + }; + ++static void brcmf_pcie_setup(struct device *dev, const struct firmware *fw, ++ void *nvram, u32 nvram_len); + + static u32 + brcmf_pcie_read_reg32(struct brcmf_pciedev_info *devinfo, u32 reg_offset) +@@ -1382,6 +1384,45 @@ static int brcmf_pcie_get_memdump(struct + } + + ++static int brcmf_pcie_reset(struct device *dev) ++{ ++ struct brcmf_bus *bus_if = dev_get_drvdata(dev); ++ struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie; ++ struct brcmf_pciedev_info *devinfo = buspub->devinfo; ++ u16 domain_nr; ++ u16 bus_nr; ++ int err; ++ ++ brcmf_detach(dev); ++ ++ brcmf_pcie_release_irq(devinfo); ++ brcmf_pcie_release_scratchbuffers(devinfo); ++ brcmf_pcie_release_ringbuffers(devinfo); ++ brcmf_pcie_reset_device(devinfo); ++ ++ err = brcmf_fw_map_chip_to_name(devinfo->ci->chip, devinfo->ci->chiprev, ++ brcmf_pcie_fwnames, ++ ARRAY_SIZE(brcmf_pcie_fwnames), ++ devinfo->fw_name, devinfo->nvram_name); ++ if (err) { ++ dev_err(dev, "Failed to prepare FW request\n"); ++ return err; ++ } ++ ++ domain_nr = pci_domain_nr(devinfo->pdev->bus) + 1; ++ bus_nr = devinfo->pdev->bus->number; ++ err = brcmf_fw_get_firmwares_pcie(bus_if->dev, BRCMF_FW_REQUEST_NVRAM | ++ BRCMF_FW_REQ_NV_OPTIONAL, ++ devinfo->fw_name, devinfo->nvram_name, ++ brcmf_pcie_setup, domain_nr, bus_nr); ++ if (err) { ++ dev_err(dev, "Failed to prepare FW request\n"); ++ return err; ++ } ++ ++ return err; ++} ++ + static const struct brcmf_bus_ops brcmf_pcie_bus_ops = { + .txdata = brcmf_pcie_tx, + .stop = brcmf_pcie_down, +@@ -1390,6 +1431,7 @@ static const struct brcmf_bus_ops brcmf_ + .wowl_config = brcmf_pcie_wowl_config, + .get_ramsize = brcmf_pcie_get_ramsize, + .get_memdump = brcmf_pcie_get_memdump, ++ .reset = brcmf_pcie_reset, + }; + + |