You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/06/20 18:33:24 UTC

[incubator-nuttx] branch master updated: wireless/bcm43xxx: add auto power saving support

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 04fcbb5cb8 wireless/bcm43xxx: add auto power saving support
04fcbb5cb8 is described below

commit 04fcbb5cb8fb3e1248682d3af531f31e1bfffed5
Author: chao.an <an...@xiaomi.com>
AuthorDate: Mon Jun 20 14:56:37 2022 +0800

    wireless/bcm43xxx: add auto power saving support
    
    switch firmware power mode between PM_MAX/PM_FAST
    
    Signed-off-by: chao.an <an...@xiaomi.com>
---
 drivers/wireless/ieee80211/bcm43xxx/Kconfig       |  16 ++++
 drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.c |  35 ++++++--
 drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.h |  12 ++-
 drivers/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)