mirror of https://gitee.com/openkylin/linux.git
brcmfmac: reset PCIe bus on a firmware crash
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>
This commit is contained in:
parent
a2ec87ddbf
commit
4684997d9e
|
@ -91,6 +91,7 @@ struct brcmf_bus_ops {
|
|||
int (*get_fwname)(struct device *dev, const char *ext,
|
||||
unsigned char *fw_name);
|
||||
void (*debugfs_create)(struct device *dev);
|
||||
int (*reset)(struct device *dev);
|
||||
};
|
||||
|
||||
|
||||
|
@ -245,6 +246,15 @@ void brcmf_bus_debugfs_create(struct brcmf_bus *bus)
|
|||
return bus->ops->debugfs_create(bus->dev);
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
|
|
|
@ -1084,6 +1084,14 @@ static int brcmf_revinfo_read(struct seq_file *s, void *data)
|
|||
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);
|
||||
}
|
||||
|
||||
static int brcmf_bus_started(struct brcmf_pub *drvr, struct cfg80211_ops *ops)
|
||||
{
|
||||
int ret = -1;
|
||||
|
@ -1155,6 +1163,8 @@ static int brcmf_bus_started(struct brcmf_pub *drvr, struct cfg80211_ops *ops)
|
|||
#endif
|
||||
#endif /* CONFIG_INET */
|
||||
|
||||
INIT_WORK(&drvr->bus_reset, brcmf_core_bus_reset);
|
||||
|
||||
/* populate debugfs */
|
||||
brcmf_debugfs_add_entry(drvr, "revinfo", brcmf_revinfo_read);
|
||||
brcmf_feat_debugfs_create(drvr);
|
||||
|
@ -1281,6 +1291,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)
|
||||
|
|
|
@ -143,6 +143,8 @@ struct brcmf_pub {
|
|||
struct notifier_block inet6addr_notifier;
|
||||
struct brcmf_mp_device *settings;
|
||||
|
||||
struct work_struct bus_reset;
|
||||
|
||||
u8 clmver[BRCMF_DCMD_SMLEN];
|
||||
};
|
||||
|
||||
|
|
|
@ -345,6 +345,10 @@ static const u32 brcmf_ring_itemsize[BRCMF_NROF_COMMON_MSGRINGS] = {
|
|||
BRCMF_D2H_MSGRING_RX_COMPLETE_ITEMSIZE
|
||||
};
|
||||
|
||||
static void brcmf_pcie_setup(struct device *dev, int ret,
|
||||
struct brcmf_fw_request *fwreq);
|
||||
static struct brcmf_fw_request *
|
||||
brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo);
|
||||
|
||||
static u32
|
||||
brcmf_pcie_read_reg32(struct brcmf_pciedev_info *devinfo, u32 reg_offset)
|
||||
|
@ -1409,6 +1413,36 @@ int brcmf_pcie_get_fwname(struct device *dev, const char *ext, u8 *fw_name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
struct brcmf_fw_request *fwreq;
|
||||
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);
|
||||
|
||||
fwreq = brcmf_pcie_prepare_fw_request(devinfo);
|
||||
if (!fwreq) {
|
||||
dev_err(dev, "Failed to prepare FW request\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
err = brcmf_fw_get_firmwares(dev, fwreq, brcmf_pcie_setup);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to prepare FW request\n");
|
||||
kfree(fwreq);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
|
||||
.txdata = brcmf_pcie_tx,
|
||||
.stop = brcmf_pcie_down,
|
||||
|
@ -1418,6 +1452,7 @@ static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
|
|||
.get_ramsize = brcmf_pcie_get_ramsize,
|
||||
.get_memdump = brcmf_pcie_get_memdump,
|
||||
.get_fwname = brcmf_pcie_get_fwname,
|
||||
.reset = brcmf_pcie_reset,
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue