360-v5.2-0003-brcmfmac-reset-PCIe-bus-on-a-firmware-crash.patch 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. From 4684997d9eea29380000e062755aa6d368d789a3 Mon Sep 17 00:00:00 2001
  2. From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <[email protected]>
  3. Date: Tue, 26 Feb 2019 14:11:19 +0100
  4. Subject: [PATCH] brcmfmac: reset PCIe bus on a firmware crash
  5. MIME-Version: 1.0
  6. Content-Type: text/plain; charset=UTF-8
  7. Content-Transfer-Encoding: 8bit
  8. This includes bus reset & reloading a firmware. It should be sufficient
  9. for a user space to (setup and) use a wireless device again.
  10. Support for reset on USB & SDIO can be added later.
  11. Signed-off-by: Rafał Miłecki <[email protected]>
  12. Reviewed-by: Arend van Spriel <[email protected]>
  13. Signed-off-by: Kalle Valo <[email protected]>
  14. ---
  15. .../broadcom/brcm80211/brcmfmac/bus.h | 10 ++++++
  16. .../broadcom/brcm80211/brcmfmac/core.c | 12 +++++++
  17. .../broadcom/brcm80211/brcmfmac/core.h | 2 ++
  18. .../broadcom/brcm80211/brcmfmac/pcie.c | 35 +++++++++++++++++++
  19. 4 files changed, 59 insertions(+)
  20. --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
  21. +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
  22. @@ -91,6 +91,7 @@ struct brcmf_bus_ops {
  23. int (*get_fwname)(struct device *dev, const char *ext,
  24. unsigned char *fw_name);
  25. void (*debugfs_create)(struct device *dev);
  26. + int (*reset)(struct device *dev);
  27. };
  28. @@ -245,6 +246,15 @@ void brcmf_bus_debugfs_create(struct brc
  29. return bus->ops->debugfs_create(bus->dev);
  30. }
  31. +static inline
  32. +int brcmf_bus_reset(struct brcmf_bus *bus)
  33. +{
  34. + if (!bus->ops->reset)
  35. + return -EOPNOTSUPP;
  36. +
  37. + return bus->ops->reset(bus->dev);
  38. +}
  39. +
  40. /*
  41. * interface functions from common layer
  42. */
  43. --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
  44. +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
  45. @@ -1105,6 +1105,14 @@ static int brcmf_revinfo_read(struct seq
  46. return 0;
  47. }
  48. +static void brcmf_core_bus_reset(struct work_struct *work)
  49. +{
  50. + struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
  51. + bus_reset);
  52. +
  53. + brcmf_bus_reset(drvr->bus_if);
  54. +}
  55. +
  56. static int brcmf_bus_started(struct brcmf_pub *drvr, struct cfg80211_ops *ops)
  57. {
  58. int ret = -1;
  59. @@ -1176,6 +1184,8 @@ static int brcmf_bus_started(struct brcm
  60. #endif
  61. #endif /* CONFIG_INET */
  62. + INIT_WORK(&drvr->bus_reset, brcmf_core_bus_reset);
  63. +
  64. /* populate debugfs */
  65. brcmf_debugfs_add_entry(drvr, "revinfo", brcmf_revinfo_read);
  66. brcmf_feat_debugfs_create(drvr);
  67. @@ -1302,6 +1312,8 @@ void brcmf_fw_crashed(struct device *dev
  68. bphy_err(drvr, "Firmware has halted or crashed\n");
  69. brcmf_dev_coredump(dev);
  70. +
  71. + schedule_work(&drvr->bus_reset);
  72. }
  73. void brcmf_detach(struct device *dev)
  74. --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
  75. +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
  76. @@ -143,6 +143,8 @@ struct brcmf_pub {
  77. struct notifier_block inet6addr_notifier;
  78. struct brcmf_mp_device *settings;
  79. + struct work_struct bus_reset;
  80. +
  81. u8 clmver[BRCMF_DCMD_SMLEN];
  82. };
  83. --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
  84. +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
  85. @@ -345,6 +345,10 @@ static const u32 brcmf_ring_itemsize[BRC
  86. BRCMF_D2H_MSGRING_RX_COMPLETE_ITEMSIZE
  87. };
  88. +static void brcmf_pcie_setup(struct device *dev, int ret,
  89. + struct brcmf_fw_request *fwreq);
  90. +static struct brcmf_fw_request *
  91. +brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo);
  92. static u32
  93. brcmf_pcie_read_reg32(struct brcmf_pciedev_info *devinfo, u32 reg_offset)
  94. @@ -1409,6 +1413,36 @@ int brcmf_pcie_get_fwname(struct device
  95. return 0;
  96. }
  97. +static int brcmf_pcie_reset(struct device *dev)
  98. +{
  99. + struct brcmf_bus *bus_if = dev_get_drvdata(dev);
  100. + struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
  101. + struct brcmf_pciedev_info *devinfo = buspub->devinfo;
  102. + struct brcmf_fw_request *fwreq;
  103. + int err;
  104. +
  105. + brcmf_detach(dev);
  106. +
  107. + brcmf_pcie_release_irq(devinfo);
  108. + brcmf_pcie_release_scratchbuffers(devinfo);
  109. + brcmf_pcie_release_ringbuffers(devinfo);
  110. + brcmf_pcie_reset_device(devinfo);
  111. +
  112. + fwreq = brcmf_pcie_prepare_fw_request(devinfo);
  113. + if (!fwreq) {
  114. + dev_err(dev, "Failed to prepare FW request\n");
  115. + return -ENOMEM;
  116. + }
  117. +
  118. + err = brcmf_fw_get_firmwares(dev, fwreq, brcmf_pcie_setup);
  119. + if (err) {
  120. + dev_err(dev, "Failed to prepare FW request\n");
  121. + kfree(fwreq);
  122. + }
  123. +
  124. + return err;
  125. +}
  126. +
  127. static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
  128. .txdata = brcmf_pcie_tx,
  129. .stop = brcmf_pcie_down,
  130. @@ -1418,6 +1452,7 @@ static const struct brcmf_bus_ops brcmf_
  131. .get_ramsize = brcmf_pcie_get_ramsize,
  132. .get_memdump = brcmf_pcie_get_memdump,
  133. .get_fwname = brcmf_pcie_get_fwname,
  134. + .reset = brcmf_pcie_reset,
  135. };