340-v5.2-0003-brcmfmac-reset-PCIe-bus-on-a-firmware-crash.patch 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. From 4684997d9eea29380000e062755aa6d368d789a3 Mon Sep 17 00:00:00 2001
  2. From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
  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 <rafal@milecki.pl>
  12. Reviewed-by: Arend van Spriel <arend.vanspriel@broadcom.com>
  13. Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
  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. @@ -87,6 +87,7 @@ struct brcmf_bus_ops {
  23. void (*wowl_config)(struct device *dev, bool enabled);
  24. size_t (*get_ramsize)(struct device *dev);
  25. int (*get_memdump)(struct device *dev, void *data, size_t len);
  26. + int (*reset)(struct device *dev);
  27. };
  28. @@ -214,6 +215,15 @@ int brcmf_bus_get_memdump(struct brcmf_b
  29. return bus->ops->get_memdump(bus->dev, data, len);
  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. @@ -1052,6 +1052,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. int brcmf_bus_started(struct device *dev)
  57. {
  58. int ret = -1;
  59. @@ -1133,6 +1141,8 @@ int brcmf_bus_started(struct device *dev
  60. #endif
  61. #endif /* CONFIG_INET */
  62. + INIT_WORK(&drvr->bus_reset, brcmf_core_bus_reset);
  63. +
  64. return 0;
  65. fail:
  66. @@ -1250,6 +1260,8 @@ void brcmf_fw_crashed(struct device *dev
  67. bphy_err(drvr, "Firmware has halted or crashed\n");
  68. brcmf_dev_coredump(dev);
  69. +
  70. + schedule_work(&drvr->bus_reset);
  71. }
  72. void brcmf_detach(struct device *dev)
  73. --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
  74. +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
  75. @@ -144,6 +144,8 @@ struct brcmf_pub {
  76. struct notifier_block inet6addr_notifier;
  77. struct brcmf_mp_device *settings;
  78. + struct work_struct bus_reset;
  79. +
  80. /* Pointer needed by OpenWrt due to backporting some fixes */
  81. void *cfg80211_ops;
  82. };
  83. --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
  84. +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
  85. @@ -343,6 +343,8 @@ static const u32 brcmf_ring_itemsize[BRC
  86. BRCMF_D2H_MSGRING_RX_COMPLETE_ITEMSIZE
  87. };
  88. +static void brcmf_pcie_setup(struct device *dev, const struct firmware *fw,
  89. + void *nvram, u32 nvram_len);
  90. static u32
  91. brcmf_pcie_read_reg32(struct brcmf_pciedev_info *devinfo, u32 reg_offset)
  92. @@ -1382,6 +1384,45 @@ static int brcmf_pcie_get_memdump(struct
  93. }
  94. +static int brcmf_pcie_reset(struct device *dev)
  95. +{
  96. + struct brcmf_bus *bus_if = dev_get_drvdata(dev);
  97. + struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
  98. + struct brcmf_pciedev_info *devinfo = buspub->devinfo;
  99. + u16 domain_nr;
  100. + u16 bus_nr;
  101. + int err;
  102. +
  103. + brcmf_detach(dev);
  104. +
  105. + brcmf_pcie_release_irq(devinfo);
  106. + brcmf_pcie_release_scratchbuffers(devinfo);
  107. + brcmf_pcie_release_ringbuffers(devinfo);
  108. + brcmf_pcie_reset_device(devinfo);
  109. +
  110. + err = brcmf_fw_map_chip_to_name(devinfo->ci->chip, devinfo->ci->chiprev,
  111. + brcmf_pcie_fwnames,
  112. + ARRAY_SIZE(brcmf_pcie_fwnames),
  113. + devinfo->fw_name, devinfo->nvram_name);
  114. + if (err) {
  115. + dev_err(dev, "Failed to prepare FW request\n");
  116. + return err;
  117. + }
  118. +
  119. + domain_nr = pci_domain_nr(devinfo->pdev->bus) + 1;
  120. + bus_nr = devinfo->pdev->bus->number;
  121. + err = brcmf_fw_get_firmwares_pcie(bus_if->dev, BRCMF_FW_REQUEST_NVRAM |
  122. + BRCMF_FW_REQ_NV_OPTIONAL,
  123. + devinfo->fw_name, devinfo->nvram_name,
  124. + brcmf_pcie_setup, domain_nr, bus_nr);
  125. + if (err) {
  126. + dev_err(dev, "Failed to prepare FW request\n");
  127. + return err;
  128. + }
  129. +
  130. + return err;
  131. +}
  132. +
  133. static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
  134. .txdata = brcmf_pcie_tx,
  135. .stop = brcmf_pcie_down,
  136. @@ -1390,6 +1431,7 @@ static const struct brcmf_bus_ops brcmf_
  137. .wowl_config = brcmf_pcie_wowl_config,
  138. .get_ramsize = brcmf_pcie_get_ramsize,
  139. .get_memdump = brcmf_pcie_get_memdump,
  140. + .reset = brcmf_pcie_reset,
  141. };