diff --git a/drivers/wireless/ieee80211/bcm43xxx/Kconfig b/drivers/wireless/ieee80211/bcm43xxx/Kconfig index 2929a67313..8b229ba90c 100644 --- a/drivers/wireless/ieee80211/bcm43xxx/Kconfig +++ b/drivers/wireless/ieee80211/bcm43xxx/Kconfig @@ -156,6 +156,12 @@ config IEEE80211_BROADCOM_SCAN_RESULT_ENTRIES ---help--- This parameter should be set the bcmf escan result buffer entries +config IEEE80211_BROADCOM_PTA_PRIORITY + bool "Broadcom BCMF Packet Traffic Arbitration priority" + default n + ---help--- + This parameter should be enable the bcmf PTA priority feature + config IEEE80211_BROADCOM_LOWPOWER bool "Broadcom BCMF lower power" depends on IEEE80211_BROADCOM_FULLMAC diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.c b/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.c index e27730f500..fd1a3cf442 100644 --- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.c +++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.c @@ -419,6 +419,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 = OK; + + /* 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; +} + /**************************************************************************** * Name: bcmf_wl_active ****************************************************************************/ @@ -1714,13 +1742,23 @@ int bcmf_wl_get_bssid(FAR struct bcmf_dev_s *priv, struct iwreq *iwr) * Get the channel for the device ****************************************************************************/ -int bcmf_wl_get_channel(FAR struct bcmf_dev_s *priv, struct iwreq *iwr) +int bcmf_wl_get_channel(FAR struct bcmf_dev_s *priv, int interface) { channel_info_t ci; uint32_t out_len; - int interface; int ret; + out_len = sizeof(ci); + ret = bcmf_cdc_ioctl(priv, interface, false, + WLC_GET_CHANNEL, (uint8_t *)&ci, &out_len); + return ret == OK ? ci.target_channel : ret; +} + +int bcmf_wl_get_frequency(FAR struct bcmf_dev_s *priv, struct iwreq *iwr) +{ + int interface; + int channel; + interface = bcmf_wl_get_interface(priv, iwr); if (interface < 0) @@ -1728,15 +1766,15 @@ int bcmf_wl_get_channel(FAR struct bcmf_dev_s *priv, struct iwreq *iwr) return -EINVAL; } - out_len = sizeof(ci); - ret = bcmf_cdc_ioctl(priv, interface, false, - WLC_GET_CHANNEL, (FAR uint8_t *)&ci, &out_len); - if (ret == OK) + channel = bcmf_wl_get_channel(priv, interface); + if (channel < 0) { - iwr->u.freq.m = bcmf_wl_channel_to_frequency(ci.target_channel); + return channel; } - return ret; + iwr->u.freq.m = bcmf_wl_channel_to_frequency(channel); + + return OK; } /**************************************************************************** @@ -1827,10 +1865,8 @@ int bcmf_wl_get_txpower(FAR struct bcmf_dev_s *priv, struct iwreq *iwr) int bcmf_wl_get_iwrange(FAR struct bcmf_dev_s *priv, struct iwreq *iwr) { struct iw_range *range; - channel_info_t ci; - uint32_t out_len; int interface; - int ret; + int channel; interface = bcmf_wl_get_interface(priv, iwr); @@ -1848,16 +1884,16 @@ int bcmf_wl_get_iwrange(FAR struct bcmf_dev_s *priv, struct iwreq *iwr) memset(range, 0, sizeof(*range)); - out_len = sizeof(ci); - ret = bcmf_cdc_ioctl(priv, interface, false, - WLC_GET_CHANNEL, (FAR uint8_t *)&ci, &out_len); - if (ret == OK) + channel = bcmf_wl_get_channel(priv, interface); + if (channel < 0) { - range->num_frequency = 1; - range->freq[0].m = bcmf_wl_channel_to_frequency(ci.target_channel); - range->freq[0].i = ci.target_channel; + return channel; } + range->num_frequency = 1; + range->freq[0].m = bcmf_wl_channel_to_frequency(channel); + range->freq[0].i = channel; + return OK; } @@ -2193,3 +2229,61 @@ int bcmf_wl_set_dtim(FAR struct bcmf_dev_s *priv, } #endif + +#ifdef CONFIG_IEEE80211_BROADCOM_PTA_PRIORITY + +int bcmf_wl_get_pta(FAR struct bcmf_dev_s *priv, struct iwreq *iwr) +{ + iwr->u.param.value = priv->pta_priority; + return OK; +} + +int bcmf_wl_set_pta_priority(FAR struct bcmf_dev_s *priv, uint32_t prio) +{ + uint32_t out_len; + int ret; + + wl_pta_t pta_prio_map[IW_PTA_PRIORITY_WLAN_MAXIMIZED + 1] = + { + { 0, 50, }, + { 10, 50, }, + { 25, 50, }, + { 40, 50, }, + { 50, 50, }, + }; + + if (prio > IW_PTA_PRIORITY_WLAN_MAXIMIZED) + { + return -EINVAL; + } + + if (priv->pta_priority == prio) + { + return OK; + } + + + out_len = sizeof(wl_pta_t); + ret = bcmf_cdc_iovar_request(priv, CHIP_STA_INTERFACE, true, + IOVAR_STR_COEX_PARA, + (uint8_t *)&pta_prio_map[prio], + &out_len); + if (ret == OK) + { + priv->pta_priority = prio; + } + + return ret; +} + +int bcmf_wl_set_pta(FAR struct bcmf_dev_s *priv, struct iwreq *iwr) +{ + if (bcmf_wl_get_interface(priv, iwr) < 0) + { + return -EINVAL; + } + + return bcmf_wl_set_pta_priority(priv, iwr->u.param.value); +} + +#endif diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.h b/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.h index 580f9fe3db..eec2a25ada 100644 --- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.h +++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.h @@ -103,6 +103,9 @@ struct bcmf_dev_s int lp_dtim; /* Listen interval Delivery Traffic Indication Message */ sclock_t lp_ticks; /* Ticks of last tx time */ #endif +#ifdef CONFIG_IEEE80211_BROADCOM_PTA_PRIORITY + int pta_priority; /* Current priority of Packet Traffic Arbitration */ +#endif }; /* Default bus interface structure */ @@ -187,7 +190,7 @@ int bcmf_wl_get_ssid(FAR struct bcmf_dev_s *priv, FAR struct iwreq *iwr); int bcmf_wl_set_bssid(FAR struct bcmf_dev_s *priv, FAR struct iwreq *iwr); int bcmf_wl_get_bssid(FAR struct bcmf_dev_s *priv, FAR struct iwreq *iwr); -int bcmf_wl_get_channel(FAR struct bcmf_dev_s *priv, FAR struct iwreq *iwr); +int bcmf_wl_get_frequency(FAR struct bcmf_dev_s *priv, struct iwreq *iwr); int bcmf_wl_get_rate(FAR struct bcmf_dev_s *priv, FAR struct iwreq *iwr); @@ -200,4 +203,17 @@ int bcmf_wl_get_iwrange(FAR struct bcmf_dev_s *priv, FAR struct iwreq *iwr); int bcmf_wl_set_country(FAR struct bcmf_dev_s *priv, FAR struct iwreq *iwr); int bcmf_wl_get_country(FAR struct bcmf_dev_s *priv, FAR struct iwreq *iwr); +int bcmf_wl_get_channel(FAR struct bcmf_dev_s *priv, int interface); + +#ifdef CONFIG_IEEE80211_BROADCOM_PTA_PRIORITY +int bcmf_wl_get_pta(FAR struct bcmf_dev_s *priv, struct iwreq *iwr); +int bcmf_wl_set_pta(FAR struct bcmf_dev_s *priv, struct iwreq *iwr); + +int bcmf_wl_set_pta_priority(FAR struct bcmf_dev_s *priv, uint32_t prio); +#else +# define bcmf_wl_get_pta(...) +# define bcmf_wl_set_pta(...) +# define bcmf_wl_set_pta_priority(...) +#endif + #endif /* __DRIVERS_WIRELESS_IEEE80211_BCM43XXX_BCMF_DRIVER_H */ diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_ioctl.h b/drivers/wireless/ieee80211/bcm43xxx/bcmf_ioctl.h index c7bc9a4970..9f6b8f0c06 100644 --- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_ioctl.h +++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_ioctl.h @@ -873,6 +873,7 @@ end_packed_struct wlc_iov_trx_t; #define IOVAR_STR_CCGPIOIN "ccgpioin" #define IOVAR_STR_CCGPIOOUT "ccgpioout" #define IOVAR_STR_CCGPIOPUTEN "ccgpioputen" +#define IOVAR_STR_COEX_PARA "coex_para" #define WLC_IOCTL_MAGIC ( 0x14e46c77 ) #define WLC_IOCTL_VERSION ( 1 ) @@ -3025,6 +3026,14 @@ end_packed_struct; typedef struct edcf_acparam edcf_acparam_t; +/* Packet Traffic Arbitration */ + +typedef struct wl_pta +{ + uint16_t radio; + uint16_t duration; +} wl_pta_t; + /* Stop packing structures */ #pragma pack() diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_netdev.c b/drivers/wireless/ieee80211/bcm43xxx/bcmf_netdev.c index f71c364c1a..d9c066bc28 100644 --- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_netdev.c +++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_netdev.c @@ -652,6 +652,8 @@ static int bcmf_ifup(FAR struct net_driver_s *dev) bcmf_lowpower_poll(priv); #endif + bcmf_wl_set_pta_priority(priv, IW_PTA_PRIORITY_COEX_HIGH); + goto errout_in_critical_section; errout_in_wl_active: @@ -708,6 +710,8 @@ static int bcmf_ifdown(FAR struct net_driver_s *dev) } #endif + bcmf_wl_set_pta_priority(priv, IW_PTA_PRIORITY_COEX_MAXIMIZED); + bcmf_wl_enable(priv, false); bcmf_wl_active(priv, false); } @@ -1022,11 +1026,24 @@ static int bcmf_ioctl(FAR struct net_driver_s *dev, int cmd, switch (cmd) { case SIOCSIWSCAN: + bcmf_wl_set_pta_priority(priv, IW_PTA_PRIORITY_WLAN_MAXIMIZED); ret = bcmf_wl_start_scan(priv, (struct iwreq *)arg); + if (ret != OK) + { + bcmf_wl_set_pta_priority(priv, IFF_IS_RUNNING(dev->d_flags) ? + IW_PTA_PRIORITY_BALANCED : + IW_PTA_PRIORITY_COEX_HIGH); + } break; case SIOCGIWSCAN: ret = bcmf_wl_get_scan_results(priv, (struct iwreq *)arg); + if (ret != -EAGAIN) + { + bcmf_wl_set_pta_priority(priv, IFF_IS_RUNNING(dev->d_flags) ? + IW_PTA_PRIORITY_BALANCED : + IW_PTA_PRIORITY_COEX_HIGH); + } break; case SIOCSIFHWADDR: /* Set device MAC address */ @@ -1047,7 +1064,7 @@ static int bcmf_ioctl(FAR struct net_driver_s *dev, int cmd, break; case SIOCGIWFREQ: /* Get channel/frequency (Hz) */ - ret = bcmf_wl_get_channel(priv, (struct iwreq *)arg); + ret = bcmf_wl_get_frequency(priv, (struct iwreq *)arg); break; case SIOCSIWMODE: /* Set operation mode */ @@ -1067,7 +1084,19 @@ static int bcmf_ioctl(FAR struct net_driver_s *dev, int cmd, break; case SIOCSIWESSID: /* Set ESSID (network name) */ + bcmf_wl_set_pta_priority(priv, IW_PTA_PRIORITY_WLAN_MAXIMIZED); ret = bcmf_wl_set_ssid(priv, (struct iwreq *)arg); + if (ret != OK) + { + bcmf_wl_set_pta_priority(priv, IW_PTA_PRIORITY_COEX_HIGH); + } + else + { + bcmf_wl_set_pta_priority(priv, (bcmf_wl_get_channel(priv, + CHIP_STA_INTERFACE) > 14) ? + IW_PTA_PRIORITY_COEX_MAXIMIZED : + IW_PTA_PRIORITY_BALANCED); + } break; case SIOCGIWESSID: /* Get ESSID */ @@ -1108,6 +1137,16 @@ static int bcmf_ioctl(FAR struct net_driver_s *dev, int cmd, ret = bcmf_wl_get_country(priv, (struct iwreq *)arg); break; +#ifdef CONFIG_IEEE80211_BROADCOM_PTA_PRIORITY + case SIOCGIWPTAPRIO: /* Get Packet Traffic Arbitration */ + ret = bcmf_wl_get_pta(priv, (struct iwreq *)arg); + break; + + case SIOCSIWPTAPRIO: /* Set Packet Traffic Arbitration */ + ret = bcmf_wl_set_pta(priv, (struct iwreq *)arg); + break; +#endif + default: nerr("ERROR: Unrecognized IOCTL command: %x\n", cmd); ret = -ENOTTY; /* Special return value for this case */