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