]> www.infradead.org Git - users/hch/misc.git/commitdiff
wifi: brcmfmac: keep power during suspend if board requires it
authorMatthias Proske <email@matthias-proske.de>
Wed, 12 Feb 2025 18:59:35 +0000 (19:59 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 26 Feb 2025 14:11:50 +0000 (15:11 +0100)
After commit 92cadedd9d5f ("brcmfmac: Avoid keeping power to SDIO card
unless WOWL is used"), the wifi adapter by default is turned off on
suspend and then re-probed on resume.

This conflicts with some embedded boards that require to remain powered.
They will fail on resume with:

brcmfmac: brcmf_sdio_bus_rxctl: resumed on timeout
ieee80211 phy1: brcmf_bus_started: failed: -110
ieee80211 phy1: brcmf_attach: dongle is not responding: err=-110
brcmfmac: brcmf_sdio_firmware_callback: brcmf_attach failed

This commit checks for the Device Tree property 'cap-power-off-cards'.
If this property is not set, it means that we do not have the capability
to power off and should therefore remain powered.

Signed-off-by: Matthias Proske <email@matthias-proske.de>
Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
Link: https://patch.msgid.link/20250212185941.146958-2-email@matthias-proske.de
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c

index 60eb95fc19a5ae362281c011b44751da005ecabe..6bc107476a2a344bf8df01d4b4b56d194587475a 100644 (file)
@@ -1172,6 +1172,7 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
        struct brcmf_bus *bus_if;
        struct brcmf_sdio_dev *sdiodev;
        mmc_pm_flag_t sdio_flags;
+       bool cap_power_off;
        int ret = 0;
 
        func = container_of(dev, struct sdio_func, dev);
@@ -1179,19 +1180,23 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
        if (func->num != 1)
                return 0;
 
+       cap_power_off = !!(func->card->host->caps & MMC_CAP_POWER_OFF_CARD);
 
        bus_if = dev_get_drvdata(dev);
        sdiodev = bus_if->bus_priv.sdio;
 
-       if (sdiodev->wowl_enabled) {
+       if (sdiodev->wowl_enabled || !cap_power_off) {
                brcmf_sdiod_freezer_on(sdiodev);
                brcmf_sdio_wd_timer(sdiodev->bus, 0);
 
                sdio_flags = MMC_PM_KEEP_POWER;
-               if (sdiodev->settings->bus.sdio.oob_irq_supported)
-                       enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
-               else
-                       sdio_flags |= MMC_PM_WAKE_SDIO_IRQ;
+
+               if (sdiodev->wowl_enabled) {
+                       if (sdiodev->settings->bus.sdio.oob_irq_supported)
+                               enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
+                       else
+                               sdio_flags |= MMC_PM_WAKE_SDIO_IRQ;
+               }
 
                if (sdio_set_host_pm_flags(sdiodev->func1, sdio_flags))
                        brcmf_err("Failed to set pm_flags %x\n", sdio_flags);
@@ -1213,18 +1218,19 @@ static int brcmf_ops_sdio_resume(struct device *dev)
        struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
        struct sdio_func *func = container_of(dev, struct sdio_func, dev);
        int ret = 0;
+       bool cap_power_off = !!(func->card->host->caps & MMC_CAP_POWER_OFF_CARD);
 
        brcmf_dbg(SDIO, "Enter: F%d\n", func->num);
        if (func->num != 2)
                return 0;
 
-       if (!sdiodev->wowl_enabled) {
+       if (!sdiodev->wowl_enabled && cap_power_off) {
                /* bus was powered off and device removed, probe again */
                ret = brcmf_sdiod_probe(sdiodev);
                if (ret)
                        brcmf_err("Failed to probe device on resume\n");
        } else {
-               if (sdiodev->settings->bus.sdio.oob_irq_supported)
+               if (sdiodev->wowl_enabled && sdiodev->settings->bus.sdio.oob_irq_supported)
                        disable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
 
                brcmf_sdiod_freezer_off(sdiodev);