From 5880dd48d58ec18c0d82bf2a18718639fd8c8d32 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 16 Sep 2019 08:04:27 +0200 Subject: [PATCH] mac80211: brcmfmac: backport the last 5.4 changes MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This makes brcmfmac use the same wiphy after PCIe reset to help user space handle corner cases (e.g. firmware crash). Signed-off-by: Rafał Miłecki (cherry picked from commit f39f4b2f6d4300995270f635261b07197e8cf61e) --- ...g80211_ops-pointer-to-another-struct.patch | 95 +++++++ ...rcmf_attach-and-brcmf_detach-functio.patch | 255 ++++++++++++++++++ ...on-t-realloc-wiphy-during-PCIe-reset.patch | 51 ++++ ...-register-wiphy-s-during-module_init.patch | 2 +- 4 files changed, 402 insertions(+), 1 deletion(-) create mode 100644 package/kernel/mac80211/patches/477-v5.4-0001-brcmfmac-move-cfg80211_ops-pointer-to-another-struct.patch create mode 100644 package/kernel/mac80211/patches/477-v5.4-0002-brcmfmac-split-brcmf_attach-and-brcmf_detach-functio.patch create mode 100644 package/kernel/mac80211/patches/477-v5.4-0003-brcmfmac-don-t-realloc-wiphy-during-PCIe-reset.patch diff --git a/package/kernel/mac80211/patches/477-v5.4-0001-brcmfmac-move-cfg80211_ops-pointer-to-another-struct.patch b/package/kernel/mac80211/patches/477-v5.4-0001-brcmfmac-move-cfg80211_ops-pointer-to-another-struct.patch new file mode 100644 index 0000000000..41bda31ae7 --- /dev/null +++ b/package/kernel/mac80211/patches/477-v5.4-0001-brcmfmac-move-cfg80211_ops-pointer-to-another-struct.patch @@ -0,0 +1,95 @@ +From ba76ff25ee64d5cfc86209d1fbb3c294b2c04412 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Tue, 3 Sep 2019 06:29:26 +0200 +Subject: [PATCH 1/3] brcmfmac: move "cfg80211_ops" pointer to another struct +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This moves "ops" pointer from "struct brcmf_cfg80211_info" to the +"struct brcmf_pub". This movement makes it possible to allocate wiphy +without attaching cfg80211 (brcmf_cfg80211_attach()). It's required for +later separation of wiphy allocation and driver initialization. + +While at it fix also an unlikely memory leak in the brcmf_attach(). + +Signed-off-by: Rafał Miłecki +Signed-off-by: Kalle Valo +--- + .../net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 1 - + .../net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h | 1 - + drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 9 ++++++--- + drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h | 1 + + 4 files changed, 7 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -7186,7 +7186,6 @@ void brcmf_cfg80211_detach(struct brcmf_ + brcmf_pno_detach(cfg); + brcmf_btcoex_detach(cfg); + wiphy_unregister(cfg->wiphy); +- kfree(cfg->ops); + wl_deinit_priv(cfg); + brcmf_free_wiphy(cfg->wiphy); + kfree(cfg); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +@@ -303,7 +303,6 @@ struct brcmf_cfg80211_wowl { + */ + struct brcmf_cfg80211_info { + struct wiphy *wiphy; +- struct cfg80211_ops *ops; + struct brcmf_cfg80211_conf *conf; + struct brcmf_p2p_info p2p; + struct brcmf_btcoex_info *btcoex; +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +@@ -1254,12 +1254,15 @@ int brcmf_attach(struct device *dev, str + return -ENOMEM; + + wiphy = wiphy_new(ops, sizeof(*drvr)); +- if (!wiphy) ++ if (!wiphy) { ++ kfree(ops); + return -ENOMEM; ++ } + + set_wiphy_dev(wiphy, dev); + drvr = wiphy_priv(wiphy); + drvr->wiphy = wiphy; ++ drvr->ops = ops; + + for (i = 0; i < ARRAY_SIZE(drvr->if2bss); i++) + drvr->if2bss[i] = BRCMF_BSSIDX_INVALID; +@@ -1292,12 +1295,10 @@ int brcmf_attach(struct device *dev, str + goto fail; + } + +- drvr->config->ops = ops; + return 0; + + fail: + brcmf_detach(dev); +- kfree(ops); + + return ret; + } +@@ -1383,6 +1384,8 @@ void brcmf_detach(struct device *dev) + + bus_if->drvr = NULL; + ++ kfree(drvr->ops); ++ + wiphy_free(drvr->wiphy); + } + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +@@ -108,6 +108,7 @@ struct brcmf_pub { + struct brcmf_bus *bus_if; + struct brcmf_proto *proto; + struct wiphy *wiphy; ++ struct cfg80211_ops *ops; + struct brcmf_cfg80211_info *config; + + /* Internal brcmf items */ diff --git a/package/kernel/mac80211/patches/477-v5.4-0002-brcmfmac-split-brcmf_attach-and-brcmf_detach-functio.patch b/package/kernel/mac80211/patches/477-v5.4-0002-brcmfmac-split-brcmf_attach-and-brcmf_detach-functio.patch new file mode 100644 index 0000000000..14688acba3 --- /dev/null +++ b/package/kernel/mac80211/patches/477-v5.4-0002-brcmfmac-split-brcmf_attach-and-brcmf_detach-functio.patch @@ -0,0 +1,255 @@ +From 450914c39f88d1adada26256360dea7050ff4e83 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Tue, 3 Sep 2019 06:29:27 +0200 +Subject: [PATCH 2/3] brcmfmac: split brcmf_attach() and brcmf_detach() + functions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Move code allocating/freeing wiphy out of above functions. This will +allow reinitializing the driver (e.g. on some error) without allocating +a new wiphy. + +Signed-off-by: Rafał Miłecki +Acked-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + .../broadcom/brcm80211/brcmfmac/bus.h | 4 ++- + .../broadcom/brcm80211/brcmfmac/core.c | 33 ++++++++++++++---- + .../broadcom/brcm80211/brcmfmac/pcie.c | 13 +++++-- + .../broadcom/brcm80211/brcmfmac/sdio.c | 15 ++++++-- + .../broadcom/brcm80211/brcmfmac/usb.c | 34 +++++++++++++++---- + 5 files changed, 80 insertions(+), 19 deletions(-) + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +@@ -254,10 +254,12 @@ void brcmf_rx_frame(struct device *dev, + /* Receive async event packet from firmware. Callee disposes of rxp. */ + void brcmf_rx_event(struct device *dev, struct sk_buff *rxp); + ++int brcmf_alloc(struct device *dev, struct brcmf_mp_device *settings); + /* Indication from bus module regarding presence/insertion of dongle. */ +-int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings); ++int brcmf_attach(struct device *dev); + /* Indication from bus module regarding removal/absence of dongle */ + void brcmf_detach(struct device *dev); ++void brcmf_free(struct device *dev); + /* Indication from bus module that dongle should be reset */ + void brcmf_dev_reset(struct device *dev); + /* Request from bus module to initiate a coredump */ +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +@@ -1239,13 +1239,11 @@ fail: + return ret; + } + +-int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings) ++int brcmf_alloc(struct device *dev, struct brcmf_mp_device *settings) + { + struct wiphy *wiphy; + struct cfg80211_ops *ops; + struct brcmf_pub *drvr = NULL; +- int ret = 0; +- int i; + + brcmf_dbg(TRACE, "Enter\n"); + +@@ -1263,6 +1261,21 @@ int brcmf_attach(struct device *dev, str + drvr = wiphy_priv(wiphy); + drvr->wiphy = wiphy; + drvr->ops = ops; ++ drvr->bus_if = dev_get_drvdata(dev); ++ drvr->bus_if->drvr = drvr; ++ drvr->settings = settings; ++ ++ return 0; ++} ++ ++int brcmf_attach(struct device *dev) ++{ ++ struct brcmf_bus *bus_if = dev_get_drvdata(dev); ++ struct brcmf_pub *drvr = bus_if->drvr; ++ int ret = 0; ++ int i; ++ ++ brcmf_dbg(TRACE, "Enter\n"); + + for (i = 0; i < ARRAY_SIZE(drvr->if2bss); i++) + drvr->if2bss[i] = BRCMF_BSSIDX_INVALID; +@@ -1271,9 +1284,6 @@ int brcmf_attach(struct device *dev, str + + /* Link to bus module */ + drvr->hdrlen = 0; +- drvr->bus_if = dev_get_drvdata(dev); +- drvr->bus_if->drvr = drvr; +- drvr->settings = settings; + + /* Attach and link in the protocol */ + ret = brcmf_proto_attach(drvr); +@@ -1289,7 +1299,7 @@ int brcmf_attach(struct device *dev, str + /* attach firmware event handler */ + brcmf_fweh_attach(drvr); + +- ret = brcmf_bus_started(drvr, ops); ++ ret = brcmf_bus_started(drvr, drvr->ops); + if (ret != 0) { + bphy_err(drvr, "dongle is not responding: err=%d\n", ret); + goto fail; +@@ -1381,6 +1391,15 @@ void brcmf_detach(struct device *dev) + brcmf_cfg80211_detach(drvr->config); + drvr->config = NULL; + } ++} ++ ++void brcmf_free(struct device *dev) ++{ ++ struct brcmf_bus *bus_if = dev_get_drvdata(dev); ++ struct brcmf_pub *drvr = bus_if->drvr; ++ ++ if (!drvr) ++ return; + + bus_if->drvr = NULL; + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -1440,6 +1440,7 @@ static int brcmf_pcie_reset(struct devic + brcmf_pcie_bus_console_read(devinfo, true); + + brcmf_detach(dev); ++ brcmf_free(dev); + + brcmf_pcie_release_irq(devinfo); + brcmf_pcie_release_scratchbuffers(devinfo); +@@ -1834,11 +1835,18 @@ static void brcmf_pcie_setup(struct devi + + brcmf_pcie_intr_enable(devinfo); + brcmf_pcie_hostready(devinfo); +- if (brcmf_attach(&devinfo->pdev->dev, devinfo->settings) == 0) +- return; ++ ++ ret = brcmf_alloc(&devinfo->pdev->dev, devinfo->settings); ++ if (ret) ++ goto fail; ++ ret = brcmf_attach(&devinfo->pdev->dev); ++ if (ret) ++ goto fail; + + brcmf_pcie_bus_console_read(devinfo, false); + ++ return; ++ + fail: + device_release_driver(dev); + } +@@ -1981,6 +1989,7 @@ brcmf_pcie_remove(struct pci_dev *pdev) + brcmf_pcie_intr_disable(devinfo); + + brcmf_detach(&pdev->dev); ++ brcmf_free(&pdev->dev); + + kfree(bus->bus_priv.pcie); + kfree(bus->msgbuf->flowrings); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +@@ -4140,10 +4140,17 @@ static void brcmf_sdio_firmware_callback + sdiod->bus_if->chip = bus->ci->chip; + sdiod->bus_if->chiprev = bus->ci->chiprev; + ++ err = brcmf_alloc(sdiod->dev, sdiod->settings); ++ if (err) { ++ brcmf_err("brcmf_alloc failed\n"); ++ goto fail; ++ } ++ + /* Attach to the common layer, reserve hdr space */ +- err = brcmf_attach(sdiod->dev, sdiod->settings); ++ err = brcmf_attach(sdiod->dev); + if (err != 0) { + brcmf_err("brcmf_attach failed\n"); ++ brcmf_free(sdiod->dev); + goto fail; + } + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +@@ -1191,8 +1191,12 @@ static void brcmf_usb_probe_phase2(struc + if (ret) + goto error; + ++ ret = brcmf_alloc(devinfo->dev, devinfo->settings); ++ if (ret) ++ goto error; ++ + /* Attach to the common driver interface */ +- ret = brcmf_attach(devinfo->dev, devinfo->settings); ++ ret = brcmf_attach(devinfo->dev); + if (ret) + goto error; + +@@ -1264,7 +1268,10 @@ static int brcmf_usb_probe_cb(struct brc + } + + if (!brcmf_usb_dlneeded(devinfo)) { +- ret = brcmf_attach(devinfo->dev, devinfo->settings); ++ ret = brcmf_alloc(devinfo->dev, devinfo->settings); ++ if (ret) ++ goto fail; ++ ret = brcmf_attach(devinfo->dev); + if (ret) + goto fail; + /* we are done */ +@@ -1292,6 +1299,7 @@ static int brcmf_usb_probe_cb(struct brc + + fail: + /* Release resources in reverse order */ ++ brcmf_free(devinfo->dev); + kfree(bus); + brcmf_usb_detach(devinfo); + return ret; +@@ -1305,6 +1313,7 @@ brcmf_usb_disconnect_cb(struct brcmf_usb + brcmf_dbg(USB, "Enter, bus_pub %p\n", devinfo); + + brcmf_detach(devinfo->dev); ++ brcmf_free(devinfo->dev); + kfree(devinfo->bus_pub.bus); + brcmf_usb_detach(devinfo); + } +@@ -1449,10 +1458,12 @@ static int brcmf_usb_suspend(struct usb_ + + brcmf_dbg(USB, "Enter\n"); + devinfo->bus_pub.state = BRCMFMAC_USB_STATE_SLEEP; +- if (devinfo->wowl_enabled) ++ if (devinfo->wowl_enabled) { + brcmf_cancel_all_urbs(devinfo); +- else ++ } else { + brcmf_detach(&usb->dev); ++ brcmf_free(&usb->dev); ++ } + return 0; + } + +@@ -1465,8 +1476,19 @@ static int brcmf_usb_resume(struct usb_i + struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev); + + brcmf_dbg(USB, "Enter\n"); +- if (!devinfo->wowl_enabled) +- return brcmf_attach(devinfo->dev, devinfo->settings); ++ if (!devinfo->wowl_enabled) { ++ int err; ++ ++ err = brcmf_alloc(&usb->dev, devinfo->settings); ++ if (err) ++ return err; ++ ++ err = brcmf_attach(devinfo->dev); ++ if (err) { ++ brcmf_free(devinfo->dev); ++ return err; ++ } ++ } + + devinfo->bus_pub.state = BRCMFMAC_USB_STATE_UP; + brcmf_usb_rx_fill_all(devinfo); diff --git a/package/kernel/mac80211/patches/477-v5.4-0003-brcmfmac-don-t-realloc-wiphy-during-PCIe-reset.patch b/package/kernel/mac80211/patches/477-v5.4-0003-brcmfmac-don-t-realloc-wiphy-during-PCIe-reset.patch new file mode 100644 index 0000000000..b0f81d7b99 --- /dev/null +++ b/package/kernel/mac80211/patches/477-v5.4-0003-brcmfmac-don-t-realloc-wiphy-during-PCIe-reset.patch @@ -0,0 +1,51 @@ +From a1f5aac1765afbeace9581afa27da34085f68e1d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Tue, 3 Sep 2019 06:29:28 +0200 +Subject: [PATCH 3/3] brcmfmac: don't realloc wiphy during PCIe reset +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Providing a new wiphy on every PCIe reset was confusing and was causing +configuration problems for some users (supplicant and authenticators). +Sticking to the existing wiphy should make error recovery much simpler +and more reliable. + +Signed-off-by: Rafał Miłecki +Acked-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -1440,7 +1440,6 @@ static int brcmf_pcie_reset(struct devic + brcmf_pcie_bus_console_read(devinfo, true); + + brcmf_detach(dev); +- brcmf_free(dev); + + brcmf_pcie_release_irq(devinfo); + brcmf_pcie_release_scratchbuffers(devinfo); +@@ -1836,9 +1835,6 @@ static void brcmf_pcie_setup(struct devi + brcmf_pcie_intr_enable(devinfo); + brcmf_pcie_hostready(devinfo); + +- ret = brcmf_alloc(&devinfo->pdev->dev, devinfo->settings); +- if (ret) +- goto fail; + ret = brcmf_attach(&devinfo->pdev->dev); + if (ret) + goto fail; +@@ -1941,6 +1937,10 @@ brcmf_pcie_probe(struct pci_dev *pdev, c + bus->wowl_supported = pci_pme_capable(pdev, PCI_D3hot); + dev_set_drvdata(&pdev->dev, bus); + ++ ret = brcmf_alloc(&devinfo->pdev->dev, devinfo->settings); ++ if (ret) ++ goto fail_bus; ++ + fwreq = brcmf_pcie_prepare_fw_request(devinfo); + if (!fwreq) { + ret = -ENOMEM; diff --git a/package/kernel/mac80211/patches/860-brcmfmac-register-wiphy-s-during-module_init.patch b/package/kernel/mac80211/patches/860-brcmfmac-register-wiphy-s-during-module_init.patch index c26468af0f..f640ae0748 100644 --- a/package/kernel/mac80211/patches/860-brcmfmac-register-wiphy-s-during-module_init.patch +++ b/package/kernel/mac80211/patches/860-brcmfmac-register-wiphy-s-during-module_init.patch @@ -13,7 +13,7 @@ Signed-off-by: Rafał Miłecki --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c -@@ -1459,6 +1459,7 @@ int __init brcmf_core_init(void) +@@ -1481,6 +1481,7 @@ int __init brcmf_core_init(void) { if (!schedule_work(&brcmf_driver_work)) return -EBUSY; -- 2.30.2