mac80211: brcmfmac: really add early fw crash recovery

Previous commit backported USB fixes instead of firmware crash recovery
patches.

Fixes: eaef74279c ("mac80211: brcmfmac: early work on FullMAC firmware crash recovery")
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
(cherry picked from commit 2d2e615dee)
This commit is contained in:
Rafał Miłecki 2019-04-18 12:37:10 +02:00
parent eaef74279c
commit d3bab051cf
6 changed files with 271 additions and 0 deletions

View File

@ -0,0 +1,32 @@
From c9692820710f57c826b2e43a6fb1e4cd307508b0 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:16 +0100
Subject: [PATCH] brcmfmac: support repeated brcmf_fw_alloc_request() calls
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
During a normal brcmfmac lifetime brcmf_fw_alloc_request() is called
once only during the probe. It's safe to assume provided array is clear.
Further brcmfmac improvements may require calling it multiple times
though. This patch allows it by fixing invalid firmware paths like:
brcm/brcmfmac4366c-pcie.binbrcm/brcmfmac4366c-pcie.bin
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>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
@@ -582,6 +582,7 @@ int brcmf_fw_map_chip_to_name(u32 chip,
return -ENODEV;
}
+ fw_name[0] = '\0';
/* check if firmware path is provided by module parameter */
if (brcmf_mp_global.firmware_path[0] != '\0') {
strlcpy(fw_name, brcmf_mp_global.firmware_path,

View File

@ -0,0 +1,79 @@
From a2ec87ddbf1637f854ffcfff9d12d392fa30758b 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:18 +0100
Subject: [PATCH] brcmfmac: add a function designated for handling firmware
fails
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This improves handling PCIe firmware halts by printing a clear error
message and replaces a similar code in the SDIO bus support.
It will also allow further improvements like trying to recover from a
firmware crash.
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>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h | 2 ++
.../net/wireless/broadcom/brcm80211/brcmfmac/core.c | 10 ++++++++++
.../net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 2 +-
.../net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 4 ++--
4 files changed, 15 insertions(+), 3 deletions(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
@@ -233,6 +233,8 @@ void brcmf_dev_reset(struct device *dev)
void brcmf_txflowblock(struct device *dev, bool state);
/* Request from bus module to initiate a coredump */
void brcmf_dev_coredump(struct device *dev);
+/* Indication that firmware has halted or crashed */
+void brcmf_fw_crashed(struct device *dev);
/* Notify the bus has transferred the tx packet to firmware */
void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success);
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -1274,6 +1274,16 @@ void brcmf_dev_coredump(struct device *d
brcmf_dbg(TRACE, "failed to create coredump\n");
}
+void brcmf_fw_crashed(struct device *dev)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_pub *drvr = bus_if->drvr;
+
+ bphy_err(drvr, "Firmware has halted or crashed\n");
+
+ brcmf_dev_coredump(dev);
+}
+
void brcmf_detach(struct device *dev)
{
s32 i;
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -728,7 +728,7 @@ static void brcmf_pcie_handle_mb_data(st
}
if (dtoh_mb_data & BRCMF_D2H_DEV_FWHALT) {
brcmf_dbg(PCIE, "D2H_MB_DATA: FW HALT\n");
- brcmf_dev_coredump(&devinfo->pdev->dev);
+ brcmf_fw_crashed(&devinfo->pdev->dev);
}
}
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -1097,8 +1097,8 @@ static u32 brcmf_sdio_hostmail(struct br
/* dongle indicates the firmware has halted/crashed */
if (hmb_data & HMB_DATA_FWHALT) {
- brcmf_err("mailbox indicates firmware halted\n");
- brcmf_dev_coredump(&sdiod->func[1]->dev);
+ brcmf_dbg(SDIO, "mailbox indicates firmware halted\n");
+ brcmf_fw_crashed(&sdiod->func[1]->dev);
}
/* Dongle recomposed rx frames, accept them again */

View File

@ -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,
};