wireless/bcm43xxx: enable power saving on netdev up/down

Move sdio/firmware de/initialize to ifup/down

Signed-off-by: chao.an <anchao@xiaomi.com>
This commit is contained in:
chao.an 2022-06-19 04:43:36 +08:00 committed by Xiang Xiao
parent 2827b2beb3
commit fa6ea23101
5 changed files with 193 additions and 131 deletions

View file

@ -433,13 +433,19 @@ int bcmf_driver_download_clm(FAR struct bcmf_dev_s *priv)
#endif
#endif /* CONFIG_IEEE80211_BROADCOM_HAVE_CLM */
int bcmf_driver_initialize(FAR struct bcmf_dev_s *priv)
int bcmf_wl_active(FAR struct bcmf_dev_s *priv, bool active)
{
int ret;
int interface = CHIP_STA_INTERFACE;
uint8_t tmp_buf[64];
uint32_t out_len;
uint32_t value;
uint8_t tmp_buf[64];
int interface = CHIP_STA_INTERFACE;
int ret;
ret = bcmf_bus_sdio_active(priv, active);
if (ret != OK || !active)
{
return ret;
}
#ifdef CONFIG_IEEE80211_BROADCOM_HAVE_CLM
/* Download CLM blob if needed */
@ -447,7 +453,7 @@ int bcmf_driver_initialize(FAR struct bcmf_dev_s *priv)
ret = bcmf_driver_download_clm(priv);
if (ret != OK)
{
return -EIO;
goto errout_in_sdio_active;
}
#endif
@ -460,7 +466,7 @@ int bcmf_driver_initialize(FAR struct bcmf_dev_s *priv)
&out_len);
if (ret != OK)
{
return -EIO;
goto errout_in_sdio_active;
}
/* FIXME disable power save mode */
@ -471,7 +477,7 @@ int bcmf_driver_initialize(FAR struct bcmf_dev_s *priv)
(uint8_t *)&value, &out_len);
if (ret != OK)
{
return ret;
goto errout_in_sdio_active;
}
/* Set the GMode to auto */
@ -482,7 +488,7 @@ int bcmf_driver_initialize(FAR struct bcmf_dev_s *priv)
(uint8_t *)&value, &out_len);
if (ret != OK)
{
return ret;
goto errout_in_sdio_active;
}
/* TODO configure roaming if needed. Disable for now */
@ -493,6 +499,10 @@ int bcmf_driver_initialize(FAR struct bcmf_dev_s *priv)
IOVAR_STR_ROAM_OFF,
(FAR uint8_t *)&value,
&out_len);
if (ret != OK)
{
goto errout_in_sdio_active;
}
/* TODO configure EAPOL version to default */
@ -500,11 +510,12 @@ int bcmf_driver_initialize(FAR struct bcmf_dev_s *priv)
((FAR uint32_t *)tmp_buf)[0] = interface;
((FAR uint32_t *)tmp_buf)[1] = (uint32_t)-1;
if (bcmf_cdc_iovar_request(priv, interface, true,
"bsscfg:"IOVAR_STR_SUP_WPA2_EAPVER, tmp_buf,
&out_len))
ret = bcmf_cdc_iovar_request(priv, interface, true,
"bsscfg:"IOVAR_STR_SUP_WPA2_EAPVER,
tmp_buf, &out_len);
if (ret != OK)
{
return -EIO;
goto errout_in_sdio_active;
}
/* Query firmware version string */
@ -515,7 +526,7 @@ int bcmf_driver_initialize(FAR struct bcmf_dev_s *priv)
&out_len);
if (ret != OK)
{
return -EIO;
goto errout_in_sdio_active;
}
tmp_buf[sizeof(tmp_buf)-1] = 0;
@ -530,11 +541,26 @@ int bcmf_driver_initialize(FAR struct bcmf_dev_s *priv)
wlinfo("fw version <%s>\n", tmp_buf);
ret = bcmf_event_push_config(priv);
errout_in_sdio_active:
if (ret != OK)
{
bcmf_bus_sdio_active(priv, false);
}
return ret;
}
int bcmf_driver_initialize(FAR struct bcmf_dev_s *priv)
{
int i;
/* FIXME Configure event mask to enable all asynchronous events */
for (ret = 0; ret < BCMF_EVENT_COUNT; ret++)
for (i = 0; i < BCMF_EVENT_COUNT; i++)
{
bcmf_event_register(priv, bcmf_wl_default_event_handler, ret);
bcmf_event_register(priv, bcmf_wl_default_event_handler, i);
}
/* Register radio event */
@ -568,11 +594,6 @@ int bcmf_driver_initialize(FAR struct bcmf_dev_s *priv)
bcmf_event_register(priv, bcmf_wl_auth_event_handler,
WLC_E_DISASSOC_IND);
if (bcmf_event_push_config(priv))
{
return -EIO;
}
/* Register network driver */
return bcmf_netdev_register(priv);

View file

@ -169,4 +169,6 @@ 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 */

View file

@ -637,20 +637,55 @@ void bcmf_netdev_notify_rx(FAR struct bcmf_dev_s *priv)
static int bcmf_ifup(FAR struct net_driver_s *dev)
{
FAR struct bcmf_dev_s *priv = (FAR struct bcmf_dev_s *)dev->d_private;
irqstate_t flags;
uint32_t out_len;
int ret;
#ifdef CONFIG_NET_IPv4
ninfo("Bringing up: %d.%d.%d.%d\n",
(int)(dev->d_ipaddr & 0xff),
(int)((dev->d_ipaddr >> 8) & 0xff),
(int)((dev->d_ipaddr >> 16) & 0xff),
(int)(dev->d_ipaddr >> 24));
#endif
#ifdef CONFIG_NET_IPv6
ninfo("Bringing up: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
dev->d_ipv6addr[0], dev->d_ipv6addr[1], dev->d_ipv6addr[2],
dev->d_ipv6addr[3], dev->d_ipv6addr[4], dev->d_ipv6addr[5],
dev->d_ipv6addr[6], dev->d_ipv6addr[7]);
#endif
/* Disable the hardware interrupt */
flags = enter_critical_section();
if (priv->bc_bifup)
{
goto errout_in_critical_section;
}
ret = bcmf_wl_active(priv, true);
if (ret != OK)
{
goto errout_in_critical_section;
}
/* Enable chip */
ret = bcmf_wl_enable(priv, true);
if (ret != OK)
{
goto errout_in_wl_active;
}
/* Set customized MAC address */
if (bcmf_board_etheraddr(&priv->bc_dev.d_mac.ether))
{
out_len = ETHER_ADDR_LEN;
bcmf_cdc_iovar_request(priv, CHIP_STA_INTERFACE, true,
IOVAR_STR_CUR_ETHERADDR,
priv->bc_dev.d_mac.ether.ether_addr_octet,
&out_len);
}
/* Query MAC address */
out_len = ETHER_ADDR_LEN;
ret = bcmf_cdc_iovar_request(priv, CHIP_STA_INTERFACE, false,
IOVAR_STR_CUR_ETHERADDR,
priv->bc_dev.d_mac.ether.ether_addr_octet,
&out_len);
if (ret != OK)
{
goto errout_in_wl_active;
}
/* Instantiate MAC address from priv->bc_dev.d_mac.ether.ether_addr_octet */
@ -663,6 +698,16 @@ static int bcmf_ifup(FAR struct net_driver_s *dev)
/* Enable the hardware interrupt */
priv->bc_bifup = true;
goto errout_in_critical_section;
errout_in_wl_active:
bcmf_wl_active(priv, false);
errout_in_critical_section:
leave_critical_section(flags);
return OK;
}
@ -690,17 +735,19 @@ static int bcmf_ifdown(FAR struct net_driver_s *dev)
/* Disable the hardware interrupt */
flags = enter_critical_section();
#warning Missing logic
/* Put the EMAC in its reset, non-operational state. This should be
* a known configuration that will guarantee the bcmf_ifup() always
* successfully brings the interface back up.
*/
if (priv->bc_bifup)
{
bcmf_wl_enable(priv, false);
bcmf_wl_active(priv, false);
/* Mark the device "down" */
/* Mark the device "down" */
priv->bc_bifup = false;
}
priv->bc_bifup = false;
leave_critical_section(flags);
return OK;
}
@ -883,8 +930,15 @@ static void bcmf_ipv6multicast(FAR struct bcmf_dev_s *priv)
static int bcmf_ioctl(FAR struct net_driver_s *dev, int cmd,
unsigned long arg)
{
int ret;
FAR struct bcmf_dev_s *priv = (FAR struct bcmf_dev_s *)dev->d_private;
int ret;
if (!priv->bc_bifup)
{
wlerr("ERROR: invaild state "
"(IFF_DOWN, unable to execute command: %x)\n", cmd);
return -EPERM;
}
/* Decode and dispatch the driver-specific IOCTL command */
@ -970,7 +1024,7 @@ static int bcmf_ioctl(FAR struct net_driver_s *dev, int cmd,
break;
default:
nerr("ERROR: Unrecognized IOCTL command: %d\n", cmd);
nerr("ERROR: Unrecognized IOCTL command: %x\n", cmd);
ret = -ENOTTY; /* Special return value for this case */
break;
}
@ -1001,8 +1055,6 @@ static int bcmf_ioctl(FAR struct net_driver_s *dev, int cmd,
int bcmf_netdev_register(FAR struct bcmf_dev_s *priv)
{
uint32_t out_len;
/* Initialize network driver structure */
memset(&priv->bc_dev, 0, sizeof(priv->bc_dev));
@ -1023,38 +1075,9 @@ int bcmf_netdev_register(FAR struct bcmf_dev_s *priv)
priv->cur_tx_frame = NULL;
priv->bc_dev.d_buf = NULL;
/* Put the interface in the down state. This usually amounts to resetting
* the device and/or calling bcmf_ifdown().
*/
/* Initialize MAC address */
/* Enable chip */
if (bcmf_wl_enable(priv, true) != OK)
{
return -EIO;
}
/* Set customized MAC address */
if (bcmf_board_etheraddr(&priv->bc_dev.d_mac.ether))
{
out_len = ETHER_ADDR_LEN;
bcmf_cdc_iovar_request(priv, CHIP_STA_INTERFACE, true,
IOVAR_STR_CUR_ETHERADDR,
priv->bc_dev.d_mac.ether.ether_addr_octet,
&out_len);
}
/* Query MAC address */
out_len = ETHER_ADDR_LEN;
if (bcmf_cdc_iovar_request(priv, CHIP_STA_INTERFACE, false,
IOVAR_STR_CUR_ETHERADDR,
priv->bc_dev.d_mac.ether.ether_addr_octet,
&out_len) != OK)
{
return -EIO;
}
bcmf_board_etheraddr(&priv->bc_dev.d_mac.ether);
/* Register the device with the OS so that socket IOCTLs can be performed */

View file

@ -456,6 +456,10 @@ int bcmf_bus_setup_interrupts(FAR struct bcmf_sdio_dev_s *sbus)
int bcmf_hwinitialize(FAR struct bcmf_sdio_dev_s *sbus)
{
/* Power device */
bcmf_board_power(sbus->minor, true);
/* Attach and prepare SDIO interrupts */
SDIO_ATTACH(sbus->sdio_dev);
@ -464,14 +468,9 @@ int bcmf_hwinitialize(FAR struct bcmf_sdio_dev_s *sbus)
SDIO_CLOCK(sbus->sdio_dev, CLOCK_IDMODE);
/* Configure hardware */
bcmf_board_initialize(sbus->minor);
/* Reset and power device */
/* Reset device */
bcmf_board_reset(sbus->minor, true);
bcmf_board_power(sbus->minor, true);
nxsig_usleep(BCMF_DEVICE_RESET_DELAY_MS * 1000);
bcmf_board_reset(sbus->minor, false);
@ -650,6 +649,67 @@ int bcmf_write_reg(FAR struct bcmf_sdio_dev_s *sbus, uint8_t function,
return bcmf_transfer_bytes(sbus, true, function, address, &reg, 1);
}
/****************************************************************************
* Name: bcmf_bus_sdio_active
****************************************************************************/
int bcmf_bus_sdio_active(FAR struct bcmf_dev_s *priv, bool active)
{
FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s *)priv->bus;
int ret = OK;
if (!active)
{
goto exit_uninit_hw;
}
/* Initialize device hardware */
ret = bcmf_hwinitialize(sbus);
if (ret != OK)
{
return ret;
}
/* Probe device */
ret = bcmf_probe(sbus);
if (ret != OK)
{
goto exit_uninit_hw;
}
/* Initialize device bus */
ret = bcmf_businitialize(sbus);
if (ret != OK)
{
goto exit_uninit_hw;
}
nxsig_usleep(100 * 1000);
sbus->ready = active;
ret = bcmf_bus_setup_interrupts(sbus);
if (ret != OK)
{
goto exit_uninit_hw;
}
ret = bcmf_sdio_sr_init(sbus);
if (ret == OK)
{
return ret;
}
exit_uninit_hw:
sbus->ready = false;
bcmf_hwuninitialize(sbus);
return ret;
}
/****************************************************************************
* Name: bcmf_bus_sdio_initialize
****************************************************************************/
@ -718,55 +778,14 @@ int bcmf_bus_sdio_initialize(FAR struct bcmf_dev_s *priv,
goto exit_free_bus;
}
/* Initialize device hardware */
/* Configure hardware */
ret = bcmf_hwinitialize(sbus);
if (ret != OK)
{
goto exit_free_bus;
}
/* Probe device */
ret = bcmf_probe(sbus);
if (ret != OK)
{
goto exit_uninit_hw;
}
/* Initialize device bus */
ret = bcmf_businitialize(sbus);
if (ret != OK)
{
goto exit_uninit_hw;
}
nxsig_usleep(100 * 1000);
sbus->ready = true;
ret = bcmf_bus_setup_interrupts(sbus);
if (ret != OK)
{
goto exit_uninit_hw;
}
ret = bcmf_sdio_sr_init(sbus);
if (ret != OK)
{
goto exit_uninit_hw;
}
bcmf_board_initialize(sbus->minor);
/* Register sdio bus */
priv->bus = &sbus->bus;
/* Start the waitdog timer */
wd_start(&sbus->waitdog, BCMF_WAITDOG_TIMEOUT_TICK,
bcmf_sdio_waitdog_timeout, (wdparm_t)priv);
/* Spawn bcmf daemon thread */
snprintf(arg1, sizeof(arg1), "%p", priv);
@ -780,18 +799,13 @@ int bcmf_bus_sdio_initialize(FAR struct bcmf_dev_s *priv,
{
wlerr("Cannot spawn bcmf thread\n");
ret = -EBADE;
goto exit_uninit_hw;
goto exit_free_bus;
}
sbus->thread_id = (pid_t)ret;
/* SDIO bus is up and running */
return OK;
exit_uninit_hw:
bcmf_hwuninitialize(sbus);
exit_free_bus:
kmm_free(sbus);
priv->bus = NULL;
@ -876,7 +890,7 @@ int bcmf_sdio_thread(int argc, char **argv)
nxsig_usleep(50 * 1000);
while (sbus->ready)
while (true)
{
/* Wait for event (device interrupt, user request or waitdog timer) */

View file

@ -141,6 +141,8 @@ struct bcmf_sdio_frame
int bcmf_bus_sdio_initialize(FAR struct bcmf_dev_s *priv,
int minor, FAR struct sdio_dev_s *dev);
int bcmf_bus_sdio_active(FAR struct bcmf_dev_s *priv, bool active);
/* FIXME: Low level bus data transfer function
* To avoid bus error, len will be aligned to:
* - upper power of 2 iflen is lesser than 64