Those changes are needed for backporting more recent crash fixes. There are quite many BCDC patches but it's hopefully a very well tested code by now. Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
161 lines
4.7 KiB
Diff
161 lines
4.7 KiB
Diff
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
|
|
@@ -1052,6 +1052,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;
|
|
@@ -1133,6 +1141,8 @@ int brcmf_bus_started(struct device *dev
|
|
#endif
|
|
#endif /* CONFIG_INET */
|
|
|
|
+ INIT_WORK(&drvr->bus_reset, brcmf_core_bus_reset);
|
|
+
|
|
return 0;
|
|
|
|
fail:
|
|
@@ -1250,6 +1260,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
|
|
@@ -144,6 +144,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,
|
|
};
|
|
|
|
|