From 04fcbb5cb8fb3e1248682d3af531f31e1bfffed5 Mon Sep 17 00:00:00 2001 From: "chao.an" Date: Mon, 20 Jun 2022 14:56:37 +0800 Subject: [PATCH] wireless/bcm43xxx: add auto power saving support switch firmware power mode between PM_MAX/PM_FAST Signed-off-by: chao.an --- drivers/wireless/ieee80211/bcm43xxx/Kconfig | 16 +++ .../wireless/ieee80211/bcm43xxx/bcmf_driver.c | 35 +++++- .../wireless/ieee80211/bcm43xxx/bcmf_driver.h | 12 ++- .../wireless/ieee80211/bcm43xxx/bcmf_netdev.c | 100 ++++++++++++++++++ 4 files changed, 156 insertions(+), 7 deletions(-) diff --git a/drivers/wireless/ieee80211/bcm43xxx/Kconfig b/drivers/wireless/ieee80211/bcm43xxx/Kconfig index 8ad71116bb..fc4a504e3a 100644 --- a/drivers/wireless/ieee80211/bcm43xxx/Kconfig +++ b/drivers/wireless/ieee80211/bcm43xxx/Kconfig @@ -132,6 +132,22 @@ config IEEE80211_BROADCOM_SCAN_RESULT_ENTRIES ---help--- This parameter should be set the bcmf escan result buffer entries +config IEEE80211_BROADCOM_LOWPOWER + bool "Broadcom BCMF lower power" + default n + ---help--- + This parameter should be enable the bcmf lower power mode + +if IEEE80211_BROADCOM_LOWPOWER + +config IEEE80211_BROADCOM_LOWPOWER_TIMEOUT + int "Broadcom BCMF lower power timeout(second)" + default 10 + ---help--- + This parameter should be enable the bcmf lower power timeout + +endif # IEEE80211_BROADCOM_LOWPOWER + if IEEE80211_BROADCOM_FULLMAC config IEEE80211_BROADCOM_NINTERFACES diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.c b/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.c index 38ab340a76..a7b4a4a5ad 100644 --- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.c +++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.c @@ -426,6 +426,34 @@ int bcmf_driver_download_clm(FAR struct bcmf_dev_s *priv) #endif #endif /* CONFIG_IEEE80211_BROADCOM_HAVE_CLM */ +int bcmf_wl_set_pm(FAR struct bcmf_dev_s *priv, int mode) +{ + int interface = CHIP_STA_INTERFACE; + uint32_t out_len; + uint32_t value; + int ret; + + /* Set default power save mode */ + +#ifdef CONFIG_IEEE80211_BROADCOM_LOWPOWER + if (priv->lp_mode != mode) +#endif + { + out_len = 4; + value = mode; + ret = bcmf_cdc_ioctl(priv, interface, true, WLC_SET_PM, + (uint8_t *)&value, &out_len); +#ifdef CONFIG_IEEE80211_BROADCOM_LOWPOWER + if (ret == OK) + { + priv->lp_mode = mode; + } +#endif + } + + return ret; +} + int bcmf_wl_active(FAR struct bcmf_dev_s *priv, bool active) { int interface = CHIP_STA_INTERFACE; @@ -462,12 +490,9 @@ int bcmf_wl_active(FAR struct bcmf_dev_s *priv, bool active) goto errout_in_sdio_active; } - /* FIXME disable power save mode */ + /* Set default power save mode */ - out_len = 4; - value = 0; - ret = bcmf_cdc_ioctl(priv, interface, true, WLC_SET_PM, - (uint8_t *)&value, &out_len); + ret = bcmf_wl_set_pm(priv, PM_OFF); if (ret != OK) { goto errout_in_sdio_active; diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.h b/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.h index 692614e239..56c10f88f7 100644 --- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.h +++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.h @@ -94,6 +94,12 @@ struct bcmf_dev_s sem_t auth_signal; /* Authentication notification signal */ int auth_status; /* Authentication status */ + +#ifdef CONFIG_IEEE80211_BROADCOM_LOWPOWER + struct work_s lp_work; /* Low power work to work queue */ + int lp_mode; /* Low power mode */ + sclock_t lp_ticks; /* Ticks of last tx time */ +#endif }; /* Default bus interface structure */ @@ -138,6 +144,10 @@ int bcmf_wl_set_mac_address(FAR struct bcmf_dev_s *priv, struct ifreq *req); int bcmf_wl_enable(FAR struct bcmf_dev_s *priv, bool enable); +int bcmf_wl_active(FAR struct bcmf_dev_s *priv, bool active); + +int bcmf_wl_set_pm(FAR struct bcmf_dev_s *priv, int mode); + /* IOCTLs AP scan interface implementation */ int bcmf_wl_start_scan(FAR struct bcmf_dev_s *priv, struct iwreq *iwr); @@ -169,6 +179,4 @@ int bcmf_wl_get_rssi(FAR struct bcmf_dev_s *priv, struct iwreq *iwr); int bcmf_wl_get_iwrange(FAR struct bcmf_dev_s *priv, struct iwreq *iwr); -int bcmf_wl_active(FAR struct bcmf_dev_s *priv, bool active); - #endif /* __DRIVERS_WIRELESS_IEEE80211_BCM43XXX_BCMF_DRIVER_H */ diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_netdev.c b/drivers/wireless/ieee80211/bcm43xxx/bcmf_netdev.c index e0fa3031c3..a2476f1806 100644 --- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_netdev.c +++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_netdev.c @@ -127,6 +127,10 @@ static int bcmf_ioctl(FAR struct net_driver_s *dev, int cmd, unsigned long arg); #endif +#ifdef CONFIG_IEEE80211_BROADCOM_LOWPOWER +static void bcmf_lowpower_poll(FAR struct bcmf_dev_s *priv); +#endif + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -703,6 +707,10 @@ static int bcmf_ifup(FAR struct net_driver_s *dev) priv->bc_bifup = true; +#ifdef CONFIG_IEEE80211_BROADCOM_LOWPOWER + bcmf_lowpower_poll(priv); +#endif + goto errout_in_critical_section; errout_in_wl_active: @@ -742,6 +750,13 @@ static int bcmf_ifdown(FAR struct net_driver_s *dev) if (priv->bc_bifup) { +#ifdef CONFIG_IEEE80211_BROADCOM_LOWPOWER + if (!work_available(&priv->lp_work)) + { + work_cancel(LPWORK, &priv->lp_work); + } +#endif + bcmf_wl_enable(priv, false); bcmf_wl_active(priv, false); @@ -755,6 +770,84 @@ static int bcmf_ifdown(FAR struct net_driver_s *dev) return OK; } +/**************************************************************************** + * Name: bcmf_lowpower_work + * + * Description: + * Process low power saving dueto work timer expiration + * + * Input Parameters: + * arg - context of device to use + * + ****************************************************************************/ + +#ifdef CONFIG_IEEE80211_BROADCOM_LOWPOWER +static void bcmf_lowpower_work(FAR void *arg) +{ + FAR struct bcmf_dev_s *priv = (FAR struct bcmf_dev_s *)arg; + irqstate_t flags; + clock_t ticks; + clock_t timeout; + + if (priv->bc_bifup) + { + /* Disable the hardware interrupt */ + + flags = enter_critical_section(); + + ticks = clock_systime_ticks() - priv->lp_ticks; + timeout = SEC2TICK(CONFIG_IEEE80211_BROADCOM_LOWPOWER_TIMEOUT); + + if (ticks >= timeout) + { + leave_critical_section(flags); + bcmf_wl_set_pm(priv, PM_MAX); + } + else + { + work_queue(LPWORK, &priv->lp_work, bcmf_lowpower_work, + priv, timeout - ticks); + leave_critical_section(flags); + } + } +} + +/**************************************************************************** + * Name: bcmf_lowpower_poll + * + * Description: + * Polling low power + * + * Input Parameters: + * arg - context of device to use + * + ****************************************************************************/ + +static void bcmf_lowpower_poll(FAR struct bcmf_dev_s *priv) +{ + irqstate_t flags; + + if (priv->bc_bifup) + { + bcmf_wl_set_pm(priv, PM_FAST); + + /* Disable the hardware interrupt */ + + flags = enter_critical_section(); + + priv->lp_ticks = clock_systime_ticks(); + if (work_available(&priv->lp_work) && priv->lp_mode != PM_MAX) + { + work_queue(LPWORK, &priv->lp_work, bcmf_lowpower_work, priv, + SEC2TICK(CONFIG_IEEE80211_BROADCOM_LOWPOWER_TIMEOUT)); + } + + leave_critical_section(flags); + } +} + +#endif + /**************************************************************************** * Name: bcmf_txavail * @@ -778,6 +871,9 @@ static int bcmf_txavail(FAR struct net_driver_s *dev) { FAR struct bcmf_dev_s *priv = (FAR struct bcmf_dev_s *)dev->d_private; +#ifdef CONFIG_IEEE80211_BROADCOM_LOWPOWER + bcmf_lowpower_poll(priv); +#endif bcmf_netdev_notify_tx(priv); return OK; } @@ -944,6 +1040,10 @@ static int bcmf_ioctl(FAR struct net_driver_s *dev, int cmd, return -EPERM; } +#ifdef CONFIG_IEEE80211_BROADCOM_LOWPOWER + bcmf_lowpower_poll(priv); +#endif + /* Decode and dispatch the driver-specific IOCTL command */ switch (cmd)