2013-06-12 20:52:10 +03:00
/*
* Copyright ( c ) 2005 - 2011 Atheros Communications Inc .
* Copyright ( c ) 2011 - 2013 Qualcomm Atheros , Inc .
*
* Permission to use , copy , modify , and / or distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
*
* THE SOFTWARE IS PROVIDED " AS IS " AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS . IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL , DIRECT , INDIRECT , OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER IN AN
* ACTION OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS ACTION , ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
*/
# include "mac.h"
# include <net/mac80211.h>
# include <linux/etherdevice.h>
2013-07-16 09:38:54 +02:00
# include "hif.h"
2013-06-12 20:52:10 +03:00
# include "core.h"
# include "debug.h"
# include "wmi.h"
# include "htt.h"
# include "txrx.h"
2014-09-10 18:23:30 +03:00
# include "testmode.h"
2014-12-03 10:10:54 +02:00
# include "wmi.h"
# include "wmi-ops.h"
2015-03-23 17:32:53 +02:00
# include "wow.h"
2013-06-12 20:52:10 +03:00
/**********/
/* Crypto */
/**********/
static int ath10k_send_key ( struct ath10k_vif * arvif ,
struct ieee80211_key_conf * key ,
enum set_key_cmd cmd ,
2015-02-18 14:02:26 +01:00
const u8 * macaddr , u32 flags )
2013-06-12 20:52:10 +03:00
{
2014-08-25 12:09:38 +02:00
struct ath10k * ar = arvif - > ar ;
2013-06-12 20:52:10 +03:00
struct wmi_vdev_install_key_arg arg = {
. vdev_id = arvif - > vdev_id ,
. key_idx = key - > keyidx ,
. key_len = key - > keylen ,
. key_data = key - > key ,
2015-02-18 14:02:26 +01:00
. key_flags = flags ,
2013-06-12 20:52:10 +03:00
. macaddr = macaddr ,
} ;
2013-07-05 16:15:15 +03:00
lockdep_assert_held ( & arvif - > ar - > conf_mutex ) ;
2013-06-12 20:52:10 +03:00
switch ( key - > cipher ) {
case WLAN_CIPHER_SUITE_CCMP :
arg . key_cipher = WMI_CIPHER_AES_CCM ;
2015-01-24 12:14:53 +02:00
key - > flags | = IEEE80211_KEY_FLAG_GENERATE_IV_MGMT ;
2013-06-12 20:52:10 +03:00
break ;
case WLAN_CIPHER_SUITE_TKIP :
arg . key_cipher = WMI_CIPHER_TKIP ;
arg . key_txmic_len = 8 ;
arg . key_rxmic_len = 8 ;
break ;
case WLAN_CIPHER_SUITE_WEP40 :
case WLAN_CIPHER_SUITE_WEP104 :
arg . key_cipher = WMI_CIPHER_WEP ;
break ;
2015-01-22 21:38:45 +01:00
case WLAN_CIPHER_SUITE_AES_CMAC :
2015-03-10 14:32:19 +01:00
WARN_ON ( 1 ) ;
return - EINVAL ;
2013-06-12 20:52:10 +03:00
default :
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " cipher %d is not supported \n " , key - > cipher ) ;
2013-06-12 20:52:10 +03:00
return - EOPNOTSUPP ;
}
if ( cmd = = DISABLE_KEY ) {
arg . key_cipher = WMI_CIPHER_NONE ;
arg . key_data = NULL ;
}
return ath10k_wmi_vdev_install_key ( arvif - > ar , & arg ) ;
}
static int ath10k_install_key ( struct ath10k_vif * arvif ,
struct ieee80211_key_conf * key ,
enum set_key_cmd cmd ,
2015-02-18 14:02:26 +01:00
const u8 * macaddr , u32 flags )
2013-06-12 20:52:10 +03:00
{
struct ath10k * ar = arvif - > ar ;
int ret ;
2013-07-05 16:15:15 +03:00
lockdep_assert_held ( & ar - > conf_mutex ) ;
2013-11-14 14:32:02 -08:00
reinit_completion ( & ar - > install_key_done ) ;
2013-06-12 20:52:10 +03:00
2015-02-18 14:02:26 +01:00
ret = ath10k_send_key ( arvif , key , cmd , macaddr , flags ) ;
2013-06-12 20:52:10 +03:00
if ( ret )
return ret ;
ret = wait_for_completion_timeout ( & ar - > install_key_done , 3 * HZ ) ;
if ( ret = = 0 )
return - ETIMEDOUT ;
return 0 ;
}
static int ath10k_install_peer_wep_keys ( struct ath10k_vif * arvif ,
const u8 * addr )
{
struct ath10k * ar = arvif - > ar ;
struct ath10k_peer * peer ;
int ret ;
int i ;
2015-02-18 14:02:26 +01:00
u32 flags ;
2013-06-12 20:52:10 +03:00
lockdep_assert_held ( & ar - > conf_mutex ) ;
spin_lock_bh ( & ar - > data_lock ) ;
peer = ath10k_peer_find ( ar , arvif - > vdev_id , addr ) ;
spin_unlock_bh ( & ar - > data_lock ) ;
if ( ! peer )
return - ENOENT ;
for ( i = 0 ; i < ARRAY_SIZE ( arvif - > wep_keys ) ; i + + ) {
if ( arvif - > wep_keys [ i ] = = NULL )
continue ;
2015-02-18 14:02:26 +01:00
flags = 0 ;
flags | = WMI_KEY_PAIRWISE ;
2015-01-29 13:50:38 +02:00
/* set TX_USAGE flag for default key id */
if ( arvif - > def_wep_key_idx = = i )
2015-02-18 14:02:26 +01:00
flags | = WMI_KEY_TX_USAGE ;
2013-06-12 20:52:10 +03:00
ret = ath10k_install_key ( arvif , arvif - > wep_keys [ i ] , SET_KEY ,
2015-02-18 14:02:26 +01:00
addr , flags ) ;
2013-06-12 20:52:10 +03:00
if ( ret )
return ret ;
2014-11-25 11:46:59 +05:30
spin_lock_bh ( & ar - > data_lock ) ;
2013-06-12 20:52:10 +03:00
peer - > keys [ i ] = arvif - > wep_keys [ i ] ;
2014-11-25 11:46:59 +05:30
spin_unlock_bh ( & ar - > data_lock ) ;
2013-06-12 20:52:10 +03:00
}
return 0 ;
}
static int ath10k_clear_peer_keys ( struct ath10k_vif * arvif ,
const u8 * addr )
{
struct ath10k * ar = arvif - > ar ;
struct ath10k_peer * peer ;
int first_errno = 0 ;
int ret ;
int i ;
2015-02-18 14:02:26 +01:00
u32 flags = 0 ;
2013-06-12 20:52:10 +03:00
lockdep_assert_held ( & ar - > conf_mutex ) ;
spin_lock_bh ( & ar - > data_lock ) ;
peer = ath10k_peer_find ( ar , arvif - > vdev_id , addr ) ;
spin_unlock_bh ( & ar - > data_lock ) ;
if ( ! peer )
return - ENOENT ;
for ( i = 0 ; i < ARRAY_SIZE ( peer - > keys ) ; i + + ) {
if ( peer - > keys [ i ] = = NULL )
continue ;
2015-01-29 13:50:38 +02:00
/* key flags are not required to delete the key */
2013-06-12 20:52:10 +03:00
ret = ath10k_install_key ( arvif , peer - > keys [ i ] ,
2015-02-18 14:02:26 +01:00
DISABLE_KEY , addr , flags ) ;
2013-06-12 20:52:10 +03:00
if ( ret & & first_errno = = 0 )
first_errno = ret ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to remove peer wep key %d: %d \n " ,
2013-06-12 20:52:10 +03:00
i , ret ) ;
2014-11-25 11:46:59 +05:30
spin_lock_bh ( & ar - > data_lock ) ;
2013-06-12 20:52:10 +03:00
peer - > keys [ i ] = NULL ;
2014-11-25 11:46:59 +05:30
spin_unlock_bh ( & ar - > data_lock ) ;
2013-06-12 20:52:10 +03:00
}
return first_errno ;
}
2014-11-25 11:46:58 +05:30
bool ath10k_mac_is_peer_wep_key_set ( struct ath10k * ar , const u8 * addr ,
u8 keyidx )
{
struct ath10k_peer * peer ;
int i ;
lockdep_assert_held ( & ar - > data_lock ) ;
/* We don't know which vdev this peer belongs to,
* since WMI doesn ' t give us that information .
*
* FIXME : multi - bss needs to be handled .
*/
peer = ath10k_peer_find ( ar , 0 , addr ) ;
if ( ! peer )
return false ;
for ( i = 0 ; i < ARRAY_SIZE ( peer - > keys ) ; i + + ) {
if ( peer - > keys [ i ] & & peer - > keys [ i ] - > keyidx = = keyidx )
return true ;
}
return false ;
}
2013-06-12 20:52:10 +03:00
static int ath10k_clear_vdev_key ( struct ath10k_vif * arvif ,
struct ieee80211_key_conf * key )
{
struct ath10k * ar = arvif - > ar ;
struct ath10k_peer * peer ;
u8 addr [ ETH_ALEN ] ;
int first_errno = 0 ;
int ret ;
int i ;
2015-02-18 14:02:26 +01:00
u32 flags = 0 ;
2013-06-12 20:52:10 +03:00
lockdep_assert_held ( & ar - > conf_mutex ) ;
for ( ; ; ) {
/* since ath10k_install_key we can't hold data_lock all the
* time , so we try to remove the keys incrementally */
spin_lock_bh ( & ar - > data_lock ) ;
i = 0 ;
list_for_each_entry ( peer , & ar - > peers , list ) {
for ( i = 0 ; i < ARRAY_SIZE ( peer - > keys ) ; i + + ) {
if ( peer - > keys [ i ] = = key ) {
2014-09-14 12:50:49 +03:00
ether_addr_copy ( addr , peer - > addr ) ;
2013-06-12 20:52:10 +03:00
peer - > keys [ i ] = NULL ;
break ;
}
}
if ( i < ARRAY_SIZE ( peer - > keys ) )
break ;
}
spin_unlock_bh ( & ar - > data_lock ) ;
if ( i = = ARRAY_SIZE ( peer - > keys ) )
break ;
2015-01-29 13:50:38 +02:00
/* key flags are not required to delete the key */
2015-02-18 14:02:26 +01:00
ret = ath10k_install_key ( arvif , key , DISABLE_KEY , addr , flags ) ;
2013-06-12 20:52:10 +03:00
if ( ret & & first_errno = = 0 )
first_errno = ret ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to remove key for %pM: %d \n " ,
2014-03-25 14:18:51 +02:00
addr , ret ) ;
2013-06-12 20:52:10 +03:00
}
return first_errno ;
}
2015-02-18 14:02:26 +01:00
static int ath10k_mac_vif_sta_fix_wep_key ( struct ath10k_vif * arvif )
{
struct ath10k * ar = arvif - > ar ;
enum nl80211_iftype iftype = arvif - > vif - > type ;
struct ieee80211_key_conf * key ;
u32 flags = 0 ;
int num = 0 ;
int i ;
int ret ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
if ( iftype ! = NL80211_IFTYPE_STATION )
return 0 ;
for ( i = 0 ; i < ARRAY_SIZE ( arvif - > wep_keys ) ; i + + ) {
if ( arvif - > wep_keys [ i ] ) {
key = arvif - > wep_keys [ i ] ;
+ + num ;
}
}
if ( num ! = 1 )
return 0 ;
flags | = WMI_KEY_PAIRWISE ;
flags | = WMI_KEY_TX_USAGE ;
ret = ath10k_install_key ( arvif , key , SET_KEY , arvif - > bssid , flags ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to install key %i on vdev %i: %d \n " ,
key - > keyidx , arvif - > vdev_id , ret ) ;
return ret ;
}
return 0 ;
}
2015-02-18 14:02:27 +01:00
static int ath10k_mac_vif_update_wep_key ( struct ath10k_vif * arvif ,
struct ieee80211_key_conf * key )
{
struct ath10k * ar = arvif - > ar ;
struct ath10k_peer * peer ;
int ret ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
list_for_each_entry ( peer , & ar - > peers , list ) {
if ( ! memcmp ( peer - > addr , arvif - > vif - > addr , ETH_ALEN ) )
continue ;
if ( ! memcmp ( peer - > addr , arvif - > bssid , ETH_ALEN ) )
continue ;
if ( peer - > keys [ key - > keyidx ] = = key )
continue ;
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac vif vdev %i update key %i needs update \n " ,
arvif - > vdev_id , key - > keyidx ) ;
ret = ath10k_install_peer_wep_keys ( arvif , peer - > addr ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to update wep keys on vdev %i for peer %pM: %d \n " ,
arvif - > vdev_id , peer - > addr , ret ) ;
return ret ;
}
}
return 0 ;
}
2013-06-12 20:52:10 +03:00
/*********************/
/* General utilities */
/*********************/
static inline enum wmi_phy_mode
chan_to_phymode ( const struct cfg80211_chan_def * chandef )
{
enum wmi_phy_mode phymode = MODE_UNKNOWN ;
switch ( chandef - > chan - > band ) {
case IEEE80211_BAND_2GHZ :
switch ( chandef - > width ) {
case NL80211_CHAN_WIDTH_20_NOHT :
2014-12-18 10:13:00 -08:00
if ( chandef - > chan - > flags & IEEE80211_CHAN_NO_OFDM )
phymode = MODE_11B ;
else
phymode = MODE_11G ;
2013-06-12 20:52:10 +03:00
break ;
case NL80211_CHAN_WIDTH_20 :
phymode = MODE_11NG_HT20 ;
break ;
case NL80211_CHAN_WIDTH_40 :
phymode = MODE_11NG_HT40 ;
break ;
2013-06-27 13:50:09 -04:00
case NL80211_CHAN_WIDTH_5 :
case NL80211_CHAN_WIDTH_10 :
2013-06-12 20:52:10 +03:00
case NL80211_CHAN_WIDTH_80 :
case NL80211_CHAN_WIDTH_80P80 :
case NL80211_CHAN_WIDTH_160 :
phymode = MODE_UNKNOWN ;
break ;
}
break ;
case IEEE80211_BAND_5GHZ :
switch ( chandef - > width ) {
case NL80211_CHAN_WIDTH_20_NOHT :
phymode = MODE_11A ;
break ;
case NL80211_CHAN_WIDTH_20 :
phymode = MODE_11NA_HT20 ;
break ;
case NL80211_CHAN_WIDTH_40 :
phymode = MODE_11NA_HT40 ;
break ;
case NL80211_CHAN_WIDTH_80 :
phymode = MODE_11AC_VHT80 ;
break ;
2013-06-27 13:50:09 -04:00
case NL80211_CHAN_WIDTH_5 :
case NL80211_CHAN_WIDTH_10 :
2013-06-12 20:52:10 +03:00
case NL80211_CHAN_WIDTH_80P80 :
case NL80211_CHAN_WIDTH_160 :
phymode = MODE_UNKNOWN ;
break ;
}
break ;
default :
break ;
}
WARN_ON ( phymode = = MODE_UNKNOWN ) ;
return phymode ;
}
static u8 ath10k_parse_mpdudensity ( u8 mpdudensity )
{
/*
* 802.11 n D2 .0 defined values for " Minimum MPDU Start Spacing " :
* 0 for no restriction
* 1 for 1 / 4 us
* 2 for 1 / 2 us
* 3 for 1 us
* 4 for 2 us
* 5 for 4 us
* 6 for 8 us
* 7 for 16 us
*/
switch ( mpdudensity ) {
case 0 :
return 0 ;
case 1 :
case 2 :
case 3 :
/* Our lower layer calculations limit our precision to
1 microsecond */
return 1 ;
case 4 :
return 2 ;
case 5 :
return 4 ;
case 6 :
return 8 ;
case 7 :
return 16 ;
default :
return 0 ;
}
}
static int ath10k_peer_create ( struct ath10k * ar , u32 vdev_id , const u8 * addr )
{
int ret ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
2014-11-25 15:16:05 +01:00
if ( ar - > num_peers > = ar - > max_num_peers )
return - ENOBUFS ;
2013-06-12 20:52:10 +03:00
ret = ath10k_wmi_peer_create ( ar , vdev_id , addr ) ;
2013-11-04 09:19:34 -08:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to create wmi peer %pM on vdev %i: %i \n " ,
2014-02-27 18:50:00 +02:00
addr , vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
return ret ;
2013-11-04 09:19:34 -08:00
}
2013-06-12 20:52:10 +03:00
ret = ath10k_wait_for_peer_created ( ar , vdev_id , addr ) ;
2013-11-04 09:19:34 -08:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to wait for created wmi peer %pM on vdev %i: %i \n " ,
2014-02-27 18:50:00 +02:00
addr , vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
return ret ;
2013-11-04 09:19:34 -08:00
}
2014-11-25 15:16:04 +01:00
2014-01-02 14:38:33 +01:00
ar - > num_peers + + ;
2013-06-12 20:52:10 +03:00
return 0 ;
}
2014-01-20 11:01:46 +02:00
static int ath10k_mac_set_kickout ( struct ath10k_vif * arvif )
{
struct ath10k * ar = arvif - > ar ;
u32 param ;
int ret ;
param = ar - > wmi . pdev_param - > sta_kickout_th ;
ret = ath10k_wmi_pdev_set_param ( ar , param ,
ATH10K_KICKOUT_THRESHOLD ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set kickout threshold on vdev %i: %d \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2014-01-20 11:01:46 +02:00
return ret ;
}
param = ar - > wmi . vdev_param - > ap_keepalive_min_idle_inactive_time_secs ;
ret = ath10k_wmi_vdev_set_param ( ar , arvif - > vdev_id , param ,
ATH10K_KEEPALIVE_MIN_IDLE ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set keepalive minimum idle time on vdev %i: %d \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2014-01-20 11:01:46 +02:00
return ret ;
}
param = ar - > wmi . vdev_param - > ap_keepalive_max_idle_inactive_time_secs ;
ret = ath10k_wmi_vdev_set_param ( ar , arvif - > vdev_id , param ,
ATH10K_KEEPALIVE_MAX_IDLE ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set keepalive maximum idle time on vdev %i: %d \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2014-01-20 11:01:46 +02:00
return ret ;
}
param = ar - > wmi . vdev_param - > ap_keepalive_max_unresponsive_time_secs ;
ret = ath10k_wmi_vdev_set_param ( ar , arvif - > vdev_id , param ,
ATH10K_KEEPALIVE_MAX_UNRESPONSIVE ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set keepalive maximum unresponsive time on vdev %i: %d \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2014-01-20 11:01:46 +02:00
return ret ;
}
return 0 ;
}
2014-11-26 09:06:12 +02:00
static int ath10k_mac_set_rts ( struct ath10k_vif * arvif , u32 value )
2013-07-22 14:13:31 +02:00
{
2013-09-26 17:47:15 +02:00
struct ath10k * ar = arvif - > ar ;
u32 vdev_param ;
vdev_param = ar - > wmi . vdev_param - > rts_threshold ;
return ath10k_wmi_vdev_set_param ( ar , arvif - > vdev_id , vdev_param , value ) ;
2013-07-22 14:13:31 +02:00
}
static int ath10k_mac_set_frag ( struct ath10k_vif * arvif , u32 value )
{
2013-09-26 17:47:15 +02:00
struct ath10k * ar = arvif - > ar ;
u32 vdev_param ;
2013-07-22 14:13:31 +02:00
if ( value ! = 0xFFFFFFFF )
value = clamp_t ( u32 , arvif - > ar - > hw - > wiphy - > frag_threshold ,
ATH10K_FRAGMT_THRESHOLD_MIN ,
ATH10K_FRAGMT_THRESHOLD_MAX ) ;
2013-09-26 17:47:15 +02:00
vdev_param = ar - > wmi . vdev_param - > fragmentation_threshold ;
return ath10k_wmi_vdev_set_param ( ar , arvif - > vdev_id , vdev_param , value ) ;
2013-07-22 14:13:31 +02:00
}
2013-06-12 20:52:10 +03:00
static int ath10k_peer_delete ( struct ath10k * ar , u32 vdev_id , const u8 * addr )
{
int ret ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
ret = ath10k_wmi_peer_delete ( ar , vdev_id , addr ) ;
if ( ret )
return ret ;
ret = ath10k_wait_for_peer_deleted ( ar , vdev_id , addr ) ;
if ( ret )
return ret ;
2014-01-02 14:38:33 +01:00
ar - > num_peers - - ;
2013-06-12 20:52:10 +03:00
return 0 ;
}
static void ath10k_peer_cleanup ( struct ath10k * ar , u32 vdev_id )
{
struct ath10k_peer * peer , * tmp ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
spin_lock_bh ( & ar - > data_lock ) ;
list_for_each_entry_safe ( peer , tmp , & ar - > peers , list ) {
if ( peer - > vdev_id ! = vdev_id )
continue ;
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " removing stale peer %pM from vdev_id %d \n " ,
2013-06-12 20:52:10 +03:00
peer - > addr , vdev_id ) ;
list_del ( & peer - > list ) ;
kfree ( peer ) ;
2014-01-02 14:38:33 +01:00
ar - > num_peers - - ;
2013-06-12 20:52:10 +03:00
}
spin_unlock_bh ( & ar - > data_lock ) ;
}
2013-07-16 09:38:56 +02:00
static void ath10k_peer_cleanup_all ( struct ath10k * ar )
{
struct ath10k_peer * peer , * tmp ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
spin_lock_bh ( & ar - > data_lock ) ;
list_for_each_entry_safe ( peer , tmp , & ar - > peers , list ) {
list_del ( & peer - > list ) ;
kfree ( peer ) ;
}
spin_unlock_bh ( & ar - > data_lock ) ;
2014-11-25 15:16:04 +01:00
ar - > num_peers = 0 ;
2014-11-25 15:16:05 +01:00
ar - > num_stations = 0 ;
2013-07-16 09:38:56 +02:00
}
2013-06-12 20:52:10 +03:00
/************************/
/* Interface management */
/************************/
2014-09-18 11:18:02 +03:00
void ath10k_mac_vif_beacon_free ( struct ath10k_vif * arvif )
{
struct ath10k * ar = arvif - > ar ;
lockdep_assert_held ( & ar - > data_lock ) ;
if ( ! arvif - > beacon )
return ;
if ( ! arvif - > beacon_buf )
dma_unmap_single ( ar - > dev , ATH10K_SKB_CB ( arvif - > beacon ) - > paddr ,
arvif - > beacon - > len , DMA_TO_DEVICE ) ;
2015-01-29 14:29:52 +02:00
if ( WARN_ON ( arvif - > beacon_state ! = ATH10K_BEACON_SCHEDULED & &
arvif - > beacon_state ! = ATH10K_BEACON_SENT ) )
return ;
2014-09-18 11:18:02 +03:00
dev_kfree_skb_any ( arvif - > beacon ) ;
arvif - > beacon = NULL ;
2015-01-29 14:29:52 +02:00
arvif - > beacon_state = ATH10K_BEACON_SCHEDULED ;
2014-09-18 11:18:02 +03:00
}
static void ath10k_mac_vif_beacon_cleanup ( struct ath10k_vif * arvif )
{
struct ath10k * ar = arvif - > ar ;
lockdep_assert_held ( & ar - > data_lock ) ;
ath10k_mac_vif_beacon_free ( arvif ) ;
if ( arvif - > beacon_buf ) {
dma_free_coherent ( ar - > dev , IEEE80211_MAX_FRAME_LEN ,
arvif - > beacon_buf , arvif - > beacon_paddr ) ;
arvif - > beacon_buf = NULL ;
}
}
2013-06-12 20:52:10 +03:00
static inline int ath10k_vdev_setup_sync ( struct ath10k * ar )
{
int ret ;
2013-07-05 16:15:15 +03:00
lockdep_assert_held ( & ar - > conf_mutex ) ;
2014-10-28 10:34:38 +01:00
if ( test_bit ( ATH10K_FLAG_CRASH_FLUSH , & ar - > dev_flags ) )
return - ESHUTDOWN ;
2013-06-12 20:52:10 +03:00
ret = wait_for_completion_timeout ( & ar - > vdev_setup_done ,
ATH10K_VDEV_SETUP_TIMEOUT_HZ ) ;
if ( ret = = 0 )
return - ETIMEDOUT ;
return 0 ;
}
2014-04-08 09:45:47 +03:00
static int ath10k_monitor_vdev_start ( struct ath10k * ar , int vdev_id )
2013-06-12 20:52:10 +03:00
{
2014-01-23 11:38:25 +01:00
struct cfg80211_chan_def * chandef = & ar - > chandef ;
struct ieee80211_channel * channel = chandef - > chan ;
2013-06-12 20:52:10 +03:00
struct wmi_vdev_start_request_arg arg = { } ;
int ret = 0 ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
arg . vdev_id = vdev_id ;
arg . channel . freq = channel - > center_freq ;
2014-01-23 11:38:25 +01:00
arg . channel . band_center_freq1 = chandef - > center_freq1 ;
2013-06-12 20:52:10 +03:00
/* TODO setup this dynamically, what in case we
don ' t have any vifs ? */
2014-01-23 11:38:25 +01:00
arg . channel . mode = chan_to_phymode ( chandef ) ;
2013-11-20 09:59:47 +02:00
arg . channel . chan_radar =
! ! ( channel - > flags & IEEE80211_CHAN_RADAR ) ;
2013-06-12 20:52:10 +03:00
2013-10-23 04:02:13 -07:00
arg . channel . min_power = 0 ;
2013-10-23 04:02:14 -07:00
arg . channel . max_power = channel - > max_power * 2 ;
arg . channel . max_reg_power = channel - > max_reg_power * 2 ;
arg . channel . max_antenna_gain = channel - > max_antenna_gain * 2 ;
2013-06-12 20:52:10 +03:00
2014-10-28 10:34:38 +01:00
reinit_completion ( & ar - > vdev_setup_done ) ;
2013-06-12 20:52:10 +03:00
ret = ath10k_wmi_vdev_start ( ar , & arg ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to request monitor vdev %i start: %d \n " ,
2014-02-27 18:50:00 +02:00
vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
return ret ;
}
ret = ath10k_vdev_setup_sync ( ar ) ;
if ( ret ) {
2015-02-15 16:50:39 +02:00
ath10k_warn ( ar , " failed to synchronize setup for monitor vdev %i start: %d \n " ,
2014-02-27 18:50:00 +02:00
vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
return ret ;
}
ret = ath10k_wmi_vdev_up ( ar , vdev_id , 0 , ar - > mac_addr ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to put up monitor vdev %i: %d \n " ,
2014-02-27 18:50:00 +02:00
vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
goto vdev_stop ;
}
ar - > monitor_vdev_id = vdev_id ;
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac monitor vdev %i started \n " ,
2014-04-08 09:45:47 +03:00
ar - > monitor_vdev_id ) ;
2013-06-12 20:52:10 +03:00
return 0 ;
vdev_stop :
ret = ath10k_wmi_vdev_stop ( ar , ar - > monitor_vdev_id ) ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to stop monitor vdev %i after start failure: %d \n " ,
2014-02-27 18:50:00 +02:00
ar - > monitor_vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
return ret ;
}
2014-04-08 09:45:47 +03:00
static int ath10k_monitor_vdev_stop ( struct ath10k * ar )
2013-06-12 20:52:10 +03:00
{
int ret = 0 ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
2013-09-24 14:06:24 +02:00
ret = ath10k_wmi_vdev_down ( ar , ar - > monitor_vdev_id ) ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to put down monitor vdev %i: %d \n " ,
2014-02-27 18:50:00 +02:00
ar - > monitor_vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
2014-10-28 10:34:38 +01:00
reinit_completion ( & ar - > vdev_setup_done ) ;
2013-06-12 20:52:10 +03:00
ret = ath10k_wmi_vdev_stop ( ar , ar - > monitor_vdev_id ) ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to to request monitor vdev %i stop: %d \n " ,
2014-02-27 18:50:00 +02:00
ar - > monitor_vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
ret = ath10k_vdev_setup_sync ( ar ) ;
if ( ret )
2015-02-15 16:50:39 +02:00
ath10k_warn ( ar , " failed to synchronize monitor vdev %i stop: %d \n " ,
2014-02-27 18:50:00 +02:00
ar - > monitor_vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac monitor vdev %i stopped \n " ,
2014-04-08 09:45:47 +03:00
ar - > monitor_vdev_id ) ;
2013-06-12 20:52:10 +03:00
return ret ;
}
2014-04-08 09:45:47 +03:00
static int ath10k_monitor_vdev_create ( struct ath10k * ar )
2013-06-12 20:52:10 +03:00
{
int bit , ret = 0 ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
2014-08-12 11:02:19 +03:00
if ( ar - > free_vdev_map = = 0 ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to find free vdev id for monitor vdev \n " ) ;
2013-06-12 20:52:10 +03:00
return - ENOMEM ;
}
2014-09-23 14:17:16 -07:00
bit = __ffs64 ( ar - > free_vdev_map ) ;
2014-08-12 11:02:19 +03:00
2014-09-23 14:17:16 -07:00
ar - > monitor_vdev_id = bit ;
2013-06-12 20:52:10 +03:00
ret = ath10k_wmi_vdev_create ( ar , ar - > monitor_vdev_id ,
WMI_VDEV_TYPE_MONITOR ,
0 , ar - > mac_addr ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to request monitor vdev %i creation: %d \n " ,
2014-02-27 18:50:00 +02:00
ar - > monitor_vdev_id , ret ) ;
2014-08-12 11:02:19 +03:00
return ret ;
2013-06-12 20:52:10 +03:00
}
2014-09-23 14:17:16 -07:00
ar - > free_vdev_map & = ~ ( 1LL < < ar - > monitor_vdev_id ) ;
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac monitor vdev %d created \n " ,
2013-06-12 20:52:10 +03:00
ar - > monitor_vdev_id ) ;
return 0 ;
}
2014-04-08 09:45:47 +03:00
static int ath10k_monitor_vdev_delete ( struct ath10k * ar )
2013-06-12 20:52:10 +03:00
{
int ret = 0 ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
ret = ath10k_wmi_vdev_delete ( ar , ar - > monitor_vdev_id ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to request wmi monitor vdev %i removal: %d \n " ,
2014-02-27 18:50:00 +02:00
ar - > monitor_vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
return ret ;
}
2014-09-23 14:17:16 -07:00
ar - > free_vdev_map | = 1LL < < ar - > monitor_vdev_id ;
2013-06-12 20:52:10 +03:00
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac monitor vdev %d deleted \n " ,
2013-06-12 20:52:10 +03:00
ar - > monitor_vdev_id ) ;
return ret ;
}
2014-04-08 09:45:47 +03:00
static int ath10k_monitor_start ( struct ath10k * ar )
{
int ret ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
ret = ath10k_monitor_vdev_create ( ar ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to create monitor vdev: %d \n " , ret ) ;
2014-04-08 09:45:47 +03:00
return ret ;
}
ret = ath10k_monitor_vdev_start ( ar , ar - > monitor_vdev_id ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to start monitor vdev: %d \n " , ret ) ;
2014-04-08 09:45:47 +03:00
ath10k_monitor_vdev_delete ( ar ) ;
return ret ;
}
ar - > monitor_started = true ;
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac monitor started \n " ) ;
2014-04-08 09:45:47 +03:00
return 0 ;
}
2014-08-28 12:58:16 +02:00
static int ath10k_monitor_stop ( struct ath10k * ar )
2014-04-08 09:45:47 +03:00
{
int ret ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
ret = ath10k_monitor_vdev_stop ( ar ) ;
2014-08-28 12:58:16 +02:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to stop monitor vdev: %d \n " , ret ) ;
2014-08-28 12:58:16 +02:00
return ret ;
}
2014-04-08 09:45:47 +03:00
ret = ath10k_monitor_vdev_delete ( ar ) ;
2014-08-28 12:58:16 +02:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to delete monitor vdev: %d \n " , ret ) ;
2014-08-28 12:58:16 +02:00
return ret ;
}
2014-04-08 09:45:47 +03:00
ar - > monitor_started = false ;
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac monitor stopped \n " ) ;
2014-08-28 12:58:16 +02:00
return 0 ;
}
2015-03-02 17:45:28 +05:30
static bool ath10k_mac_should_disable_promisc ( struct ath10k * ar )
{
struct ath10k_vif * arvif ;
if ( ! ( ar - > filter_flags & FIF_PROMISC_IN_BSS ) )
return true ;
if ( ! ar - > num_started_vdevs )
return false ;
list_for_each_entry ( arvif , & ar - > arvifs , list )
if ( arvif - > vdev_type ! = WMI_VDEV_TYPE_AP )
return false ;
ath10k_dbg ( ar , ATH10K_DBG_MAC ,
" mac disabling promiscuous mode because vdev is started \n " ) ;
return true ;
}
2014-08-28 12:58:16 +02:00
static int ath10k_monitor_recalc ( struct ath10k * ar )
{
bool should_start ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
should_start = ar - > monitor | |
2015-03-09 14:20:55 +01:00
! ath10k_mac_should_disable_promisc ( ar ) | |
2014-08-28 12:58:16 +02:00
test_bit ( ATH10K_CAC_RUNNING , & ar - > dev_flags ) ;
ath10k_dbg ( ar , ATH10K_DBG_MAC ,
" mac monitor recalc started? %d should? %d \n " ,
ar - > monitor_started , should_start ) ;
if ( should_start = = ar - > monitor_started )
return 0 ;
if ( should_start )
return ath10k_monitor_start ( ar ) ;
2014-09-14 12:50:33 +03:00
return ath10k_monitor_stop ( ar ) ;
2014-04-08 09:45:47 +03:00
}
2014-03-11 12:58:00 +02:00
static int ath10k_recalc_rtscts_prot ( struct ath10k_vif * arvif )
{
struct ath10k * ar = arvif - > ar ;
u32 vdev_param , rts_cts = 0 ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
vdev_param = ar - > wmi . vdev_param - > enable_rtscts ;
2015-03-19 16:03:29 +02:00
rts_cts | = SM ( WMI_RTSCTS_ENABLED , WMI_RTSCTS_SET ) ;
2014-03-11 12:58:00 +02:00
if ( arvif - > num_legacy_stations > 0 )
rts_cts | = SM ( WMI_RTSCTS_ACROSS_SW_RETRIES ,
WMI_RTSCTS_PROFILE ) ;
2015-03-19 16:03:29 +02:00
else
rts_cts | = SM ( WMI_RTSCTS_FOR_SECOND_RATESERIES ,
WMI_RTSCTS_PROFILE ) ;
2014-03-11 12:58:00 +02:00
return ath10k_wmi_vdev_set_param ( ar , arvif - > vdev_id , vdev_param ,
rts_cts ) ;
}
2013-11-20 09:59:47 +02:00
static int ath10k_start_cac ( struct ath10k * ar )
{
int ret ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
set_bit ( ATH10K_CAC_RUNNING , & ar - > dev_flags ) ;
2014-08-28 12:58:16 +02:00
ret = ath10k_monitor_recalc ( ar ) ;
2013-11-20 09:59:47 +02:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to start monitor (cac): %d \n " , ret ) ;
2013-11-20 09:59:47 +02:00
clear_bit ( ATH10K_CAC_RUNNING , & ar - > dev_flags ) ;
return ret ;
}
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac cac start monitor vdev %d \n " ,
2013-11-20 09:59:47 +02:00
ar - > monitor_vdev_id ) ;
return 0 ;
}
static int ath10k_stop_cac ( struct ath10k * ar )
{
lockdep_assert_held ( & ar - > conf_mutex ) ;
/* CAC is not running - do nothing */
if ( ! test_bit ( ATH10K_CAC_RUNNING , & ar - > dev_flags ) )
return 0 ;
clear_bit ( ATH10K_CAC_RUNNING , & ar - > dev_flags ) ;
2014-04-08 09:45:47 +03:00
ath10k_monitor_stop ( ar ) ;
2013-11-20 09:59:47 +02:00
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac cac finished \n " ) ;
2013-11-20 09:59:47 +02:00
return 0 ;
}
2014-04-08 09:56:09 +03:00
static void ath10k_recalc_radar_detection ( struct ath10k * ar )
2013-11-20 09:59:47 +02:00
{
int ret ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
ath10k_stop_cac ( ar ) ;
2014-04-08 09:56:09 +03:00
if ( ! ar - > radar_enabled )
2013-11-20 09:59:47 +02:00
return ;
2014-04-08 09:56:09 +03:00
if ( ar - > num_started_vdevs > 0 )
2013-11-20 09:59:47 +02:00
return ;
ret = ath10k_start_cac ( ar ) ;
if ( ret ) {
/*
* Not possible to start CAC on current channel so starting
* radiation is not allowed , make this channel DFS_UNAVAILABLE
* by indicating that radar was detected .
*/
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to start CAC: %d \n " , ret ) ;
2013-11-20 09:59:47 +02:00
ieee80211_radar_detected ( ar - > hw ) ;
}
}
2015-03-02 17:45:27 +05:30
static int ath10k_vdev_stop ( struct ath10k_vif * arvif )
{
struct ath10k * ar = arvif - > ar ;
int ret ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
reinit_completion ( & ar - > vdev_setup_done ) ;
ret = ath10k_wmi_vdev_stop ( ar , arvif - > vdev_id ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to stop WMI vdev %i: %d \n " ,
arvif - > vdev_id , ret ) ;
return ret ;
}
ret = ath10k_vdev_setup_sync ( ar ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to syncronise setup for vdev %i: %d \n " ,
arvif - > vdev_id , ret ) ;
return ret ;
}
WARN_ON ( ar - > num_started_vdevs = = 0 ) ;
if ( ar - > num_started_vdevs ! = 0 ) {
ar - > num_started_vdevs - - ;
ath10k_recalc_radar_detection ( ar ) ;
}
return ret ;
}
2014-07-29 12:53:36 +03:00
static int ath10k_vdev_start_restart ( struct ath10k_vif * arvif , bool restart )
2014-04-08 09:56:09 +03:00
{
struct ath10k * ar = arvif - > ar ;
struct cfg80211_chan_def * chandef = & ar - > chandef ;
struct wmi_vdev_start_request_arg arg = { } ;
2015-03-02 17:45:28 +05:30
int ret = 0 , ret2 ;
2014-04-08 09:56:09 +03:00
lockdep_assert_held ( & ar - > conf_mutex ) ;
reinit_completion ( & ar - > vdev_setup_done ) ;
arg . vdev_id = arvif - > vdev_id ;
arg . dtim_period = arvif - > dtim_period ;
arg . bcn_intval = arvif - > beacon_interval ;
arg . channel . freq = chandef - > chan - > center_freq ;
arg . channel . band_center_freq1 = chandef - > center_freq1 ;
arg . channel . mode = chan_to_phymode ( chandef ) ;
arg . channel . min_power = 0 ;
arg . channel . max_power = chandef - > chan - > max_power * 2 ;
arg . channel . max_reg_power = chandef - > chan - > max_reg_power * 2 ;
arg . channel . max_antenna_gain = chandef - > chan - > max_antenna_gain * 2 ;
if ( arvif - > vdev_type = = WMI_VDEV_TYPE_AP ) {
arg . ssid = arvif - > u . ap . ssid ;
arg . ssid_len = arvif - > u . ap . ssid_len ;
arg . hidden_ssid = arvif - > u . ap . hidden_ssid ;
/* For now allow DFS for AP mode */
arg . channel . chan_radar =
! ! ( chandef - > chan - > flags & IEEE80211_CHAN_RADAR ) ;
} else if ( arvif - > vdev_type = = WMI_VDEV_TYPE_IBSS ) {
arg . ssid = arvif - > vif - > bss_conf . ssid ;
arg . ssid_len = arvif - > vif - > bss_conf . ssid_len ;
}
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC ,
2014-04-08 09:56:09 +03:00
" mac vdev %d start center_freq %d phymode %s \n " ,
arg . vdev_id , arg . channel . freq ,
ath10k_wmi_phymode_str ( arg . channel . mode ) ) ;
2014-07-29 12:53:36 +03:00
if ( restart )
ret = ath10k_wmi_vdev_restart ( ar , & arg ) ;
else
ret = ath10k_wmi_vdev_start ( ar , & arg ) ;
2014-04-08 09:56:09 +03:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to start WMI vdev %i: %d \n " ,
2014-04-08 09:56:09 +03:00
arg . vdev_id , ret ) ;
return ret ;
}
ret = ath10k_vdev_setup_sync ( ar ) ;
if ( ret ) {
2015-02-15 16:50:39 +02:00
ath10k_warn ( ar ,
" failed to synchronize setup for vdev %i restart %d: %d \n " ,
arg . vdev_id , restart , ret ) ;
2014-04-08 09:56:09 +03:00
return ret ;
}
2014-04-08 09:56:09 +03:00
ar - > num_started_vdevs + + ;
ath10k_recalc_radar_detection ( ar ) ;
2015-03-02 17:45:28 +05:30
ret = ath10k_monitor_recalc ( ar ) ;
if ( ret ) {
ath10k_warn ( ar , " mac failed to recalc monitor for vdev %i restart %d: %d \n " ,
arg . vdev_id , restart , ret ) ;
ret2 = ath10k_vdev_stop ( arvif ) ;
if ( ret2 )
ath10k_warn ( ar , " mac failed to stop vdev %i restart %d: %d \n " ,
arg . vdev_id , restart , ret2 ) ;
}
2014-04-08 09:56:09 +03:00
return ret ;
}
2014-07-29 12:53:36 +03:00
static int ath10k_vdev_start ( struct ath10k_vif * arvif )
{
return ath10k_vdev_start_restart ( arvif , false ) ;
}
static int ath10k_vdev_restart ( struct ath10k_vif * arvif )
{
return ath10k_vdev_start_restart ( arvif , true ) ;
}
2015-01-13 16:30:12 +02:00
static int ath10k_mac_setup_bcn_p2p_ie ( struct ath10k_vif * arvif ,
struct sk_buff * bcn )
{
struct ath10k * ar = arvif - > ar ;
struct ieee80211_mgmt * mgmt ;
const u8 * p2p_ie ;
int ret ;
if ( arvif - > vdev_type ! = WMI_VDEV_TYPE_AP )
return 0 ;
if ( arvif - > vdev_subtype ! = WMI_VDEV_SUBTYPE_P2P_GO )
return 0 ;
mgmt = ( void * ) bcn - > data ;
p2p_ie = cfg80211_find_vendor_ie ( WLAN_OUI_WFA , WLAN_OUI_TYPE_WFA_P2P ,
mgmt - > u . beacon . variable ,
bcn - > len - ( mgmt - > u . beacon . variable -
bcn - > data ) ) ;
if ( ! p2p_ie )
return - ENOENT ;
ret = ath10k_wmi_p2p_go_bcn_ie ( ar , arvif - > vdev_id , p2p_ie ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to submit p2p go bcn ie for vdev %i: %d \n " ,
arvif - > vdev_id , ret ) ;
return ret ;
}
return 0 ;
}
static int ath10k_mac_remove_vendor_ie ( struct sk_buff * skb , unsigned int oui ,
u8 oui_type , size_t ie_offset )
{
size_t len ;
const u8 * next ;
const u8 * end ;
u8 * ie ;
if ( WARN_ON ( skb - > len < ie_offset ) )
return - EINVAL ;
ie = ( u8 * ) cfg80211_find_vendor_ie ( oui , oui_type ,
skb - > data + ie_offset ,
skb - > len - ie_offset ) ;
if ( ! ie )
return - ENOENT ;
len = ie [ 1 ] + 2 ;
end = skb - > data + skb - > len ;
next = ie + len ;
if ( WARN_ON ( next > end ) )
return - EINVAL ;
memmove ( ie , next , end - next ) ;
skb_trim ( skb , skb - > len - len ) ;
return 0 ;
}
static int ath10k_mac_setup_bcn_tmpl ( struct ath10k_vif * arvif )
{
struct ath10k * ar = arvif - > ar ;
struct ieee80211_hw * hw = ar - > hw ;
struct ieee80211_vif * vif = arvif - > vif ;
struct ieee80211_mutable_offsets offs = { } ;
struct sk_buff * bcn ;
int ret ;
if ( ! test_bit ( WMI_SERVICE_BEACON_OFFLOAD , ar - > wmi . svc_map ) )
return 0 ;
2015-03-05 16:02:17 +02:00
if ( arvif - > vdev_type ! = WMI_VDEV_TYPE_AP & &
arvif - > vdev_type ! = WMI_VDEV_TYPE_IBSS )
return 0 ;
2015-01-13 16:30:12 +02:00
bcn = ieee80211_beacon_get_template ( hw , vif , & offs ) ;
if ( ! bcn ) {
ath10k_warn ( ar , " failed to get beacon template from mac80211 \n " ) ;
return - EPERM ;
}
ret = ath10k_mac_setup_bcn_p2p_ie ( arvif , bcn ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to setup p2p go bcn ie: %d \n " , ret ) ;
kfree_skb ( bcn ) ;
return ret ;
}
/* P2P IE is inserted by firmware automatically (as configured above)
* so remove it from the base beacon template to avoid duplicate P2P
* IEs in beacon frames .
*/
ath10k_mac_remove_vendor_ie ( bcn , WLAN_OUI_WFA , WLAN_OUI_TYPE_WFA_P2P ,
offsetof ( struct ieee80211_mgmt ,
u . beacon . variable ) ) ;
ret = ath10k_wmi_bcn_tmpl ( ar , arvif - > vdev_id , offs . tim_offset , bcn , 0 ,
0 , NULL , 0 ) ;
kfree_skb ( bcn ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to submit beacon template command: %d \n " ,
ret ) ;
return ret ;
}
return 0 ;
}
static int ath10k_mac_setup_prb_tmpl ( struct ath10k_vif * arvif )
{
struct ath10k * ar = arvif - > ar ;
struct ieee80211_hw * hw = ar - > hw ;
struct ieee80211_vif * vif = arvif - > vif ;
struct sk_buff * prb ;
int ret ;
if ( ! test_bit ( WMI_SERVICE_BEACON_OFFLOAD , ar - > wmi . svc_map ) )
return 0 ;
2015-03-05 16:02:17 +02:00
if ( arvif - > vdev_type ! = WMI_VDEV_TYPE_AP )
return 0 ;
2015-01-13 16:30:12 +02:00
prb = ieee80211_proberesp_get ( hw , vif ) ;
if ( ! prb ) {
ath10k_warn ( ar , " failed to get probe resp template from mac80211 \n " ) ;
return - EPERM ;
}
ret = ath10k_wmi_prb_tmpl ( ar , arvif - > vdev_id , prb ) ;
kfree_skb ( prb ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to submit probe resp template command: %d \n " ,
ret ) ;
return ret ;
}
return 0 ;
}
2013-06-12 20:52:10 +03:00
static void ath10k_control_beaconing ( struct ath10k_vif * arvif ,
2014-09-14 12:50:06 +03:00
struct ieee80211_bss_conf * info )
2013-06-12 20:52:10 +03:00
{
2014-08-25 12:09:38 +02:00
struct ath10k * ar = arvif - > ar ;
2013-06-12 20:52:10 +03:00
int ret = 0 ;
2013-07-05 16:15:15 +03:00
lockdep_assert_held ( & arvif - > ar - > conf_mutex ) ;
2013-06-12 20:52:10 +03:00
if ( ! info - > enable_beacon ) {
ath10k_vdev_stop ( arvif ) ;
2014-01-23 11:38:25 +01:00
arvif - > is_started = false ;
arvif - > is_up = false ;
2015-03-09 14:19:24 +01:00
spin_lock_bh ( & arvif - > ar - > data_lock ) ;
2014-09-18 11:18:02 +03:00
ath10k_mac_vif_beacon_free ( arvif ) ;
2014-01-23 12:48:21 +01:00
spin_unlock_bh ( & arvif - > ar - > data_lock ) ;
2013-06-12 20:52:10 +03:00
return ;
}
arvif - > tx_seq_no = 0x1000 ;
ret = ath10k_vdev_start ( arvif ) ;
if ( ret )
return ;
2014-01-23 11:38:25 +01:00
arvif - > aid = 0 ;
2014-09-14 12:50:49 +03:00
ether_addr_copy ( arvif - > bssid , info - > bssid ) ;
2014-01-23 11:38:25 +01:00
ret = ath10k_wmi_vdev_up ( arvif - > ar , arvif - > vdev_id , arvif - > aid ,
arvif - > bssid ) ;
2013-06-12 20:52:10 +03:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to bring up vdev %d: %i \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2014-01-23 11:38:25 +01:00
ath10k_vdev_stop ( arvif ) ;
2013-06-12 20:52:10 +03:00
return ;
}
2014-01-23 11:38:25 +01:00
arvif - > is_started = true ;
arvif - > is_up = true ;
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac vdev %d up \n " , arvif - > vdev_id ) ;
2013-06-12 20:52:10 +03:00
}
static void ath10k_control_ibss ( struct ath10k_vif * arvif ,
struct ieee80211_bss_conf * info ,
const u8 self_peer [ ETH_ALEN ] )
{
2014-08-25 12:09:38 +02:00
struct ath10k * ar = arvif - > ar ;
2013-09-26 17:47:15 +02:00
u32 vdev_param ;
2013-06-12 20:52:10 +03:00
int ret = 0 ;
2013-07-05 16:15:15 +03:00
lockdep_assert_held ( & arvif - > ar - > conf_mutex ) ;
2013-06-12 20:52:10 +03:00
if ( ! info - > ibss_joined ) {
ret = ath10k_peer_delete ( arvif - > ar , arvif - > vdev_id , self_peer ) ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to delete IBSS self peer %pM for vdev %d: %d \n " ,
2013-06-12 20:52:10 +03:00
self_peer , arvif - > vdev_id , ret ) ;
2014-01-23 11:38:25 +01:00
if ( is_zero_ether_addr ( arvif - > bssid ) )
2013-06-12 20:52:10 +03:00
return ;
2014-01-23 11:38:25 +01:00
memset ( arvif - > bssid , 0 , ETH_ALEN ) ;
2013-06-12 20:52:10 +03:00
return ;
}
ret = ath10k_peer_create ( arvif - > ar , arvif - > vdev_id , self_peer ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to create IBSS self peer %pM for vdev %d: %d \n " ,
2013-06-12 20:52:10 +03:00
self_peer , arvif - > vdev_id , ret ) ;
return ;
}
2013-09-26 17:47:15 +02:00
vdev_param = arvif - > ar - > wmi . vdev_param - > atim_window ;
ret = ath10k_wmi_vdev_set_param ( arvif - > ar , arvif - > vdev_id , vdev_param ,
2013-06-12 20:52:10 +03:00
ATH10K_DEFAULT_ATIM ) ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set IBSS ATIM for vdev %d: %d \n " ,
2013-06-12 20:52:10 +03:00
arvif - > vdev_id , ret ) ;
}
2014-12-12 12:41:36 +01:00
static int ath10k_mac_vif_recalc_ps_wake_threshold ( struct ath10k_vif * arvif )
{
struct ath10k * ar = arvif - > ar ;
u32 param ;
u32 value ;
int ret ;
lockdep_assert_held ( & arvif - > ar - > conf_mutex ) ;
if ( arvif - > u . sta . uapsd )
value = WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER ;
else
value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS ;
param = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD ;
ret = ath10k_wmi_set_sta_ps_param ( ar , arvif - > vdev_id , param , value ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to submit ps wake threshold %u on vdev %i: %d \n " ,
value , arvif - > vdev_id , ret ) ;
return ret ;
}
return 0 ;
}
static int ath10k_mac_vif_recalc_ps_poll_count ( struct ath10k_vif * arvif )
{
struct ath10k * ar = arvif - > ar ;
u32 param ;
u32 value ;
int ret ;
lockdep_assert_held ( & arvif - > ar - > conf_mutex ) ;
if ( arvif - > u . sta . uapsd )
value = WMI_STA_PS_PSPOLL_COUNT_UAPSD ;
else
value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX ;
param = WMI_STA_PS_PARAM_PSPOLL_COUNT ;
ret = ath10k_wmi_set_sta_ps_param ( ar , arvif - > vdev_id ,
param , value ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to submit ps poll count %u on vdev %i: %d \n " ,
value , arvif - > vdev_id , ret ) ;
return ret ;
}
return 0 ;
}
2015-02-13 13:30:16 +01:00
static int ath10k_mac_ps_vif_count ( struct ath10k * ar )
{
struct ath10k_vif * arvif ;
int num = 0 ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
list_for_each_entry ( arvif , & ar - > arvifs , list )
if ( arvif - > ps )
num + + ;
return num ;
}
2013-10-16 15:44:46 +03:00
static int ath10k_mac_vif_setup_ps ( struct ath10k_vif * arvif )
2013-06-12 20:52:10 +03:00
{
2013-10-16 15:44:46 +03:00
struct ath10k * ar = arvif - > ar ;
2014-12-12 12:41:37 +01:00
struct ieee80211_vif * vif = arvif - > vif ;
2013-10-16 15:44:46 +03:00
struct ieee80211_conf * conf = & ar - > hw - > conf ;
2013-06-12 20:52:10 +03:00
enum wmi_sta_powersave_param param ;
enum wmi_sta_ps_mode psmode ;
int ret ;
2014-12-12 12:41:37 +01:00
int ps_timeout ;
2015-02-13 13:30:16 +01:00
bool enable_ps ;
2013-06-12 20:52:10 +03:00
2013-07-05 16:15:15 +03:00
lockdep_assert_held ( & arvif - > ar - > conf_mutex ) ;
2013-10-16 15:44:46 +03:00
if ( arvif - > vif - > type ! = NL80211_IFTYPE_STATION )
return 0 ;
2013-06-12 20:52:10 +03:00
2015-02-13 13:30:16 +01:00
enable_ps = arvif - > ps ;
if ( enable_ps & & ath10k_mac_ps_vif_count ( ar ) > 1 & &
! test_bit ( ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT ,
ar - > fw_features ) ) {
ath10k_warn ( ar , " refusing to enable ps on vdev %i: not supported by fw \n " ,
arvif - > vdev_id ) ;
enable_ps = false ;
}
if ( enable_ps ) {
2013-06-12 20:52:10 +03:00
psmode = WMI_STA_PS_MODE_ENABLED ;
param = WMI_STA_PS_PARAM_INACTIVITY_TIME ;
2014-12-12 12:41:37 +01:00
ps_timeout = conf - > dynamic_ps_timeout ;
if ( ps_timeout = = 0 ) {
/* Firmware doesn't like 0 */
ps_timeout = ieee80211_tu_to_usec (
vif - > bss_conf . beacon_int ) / 1000 ;
}
2013-10-16 15:44:46 +03:00
ret = ath10k_wmi_set_sta_ps_param ( ar , arvif - > vdev_id , param ,
2014-12-12 12:41:37 +01:00
ps_timeout ) ;
2013-06-12 20:52:10 +03:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set inactivity time for vdev %d: %i \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2013-10-16 15:44:46 +03:00
return ret ;
2013-06-12 20:52:10 +03:00
}
} else {
psmode = WMI_STA_PS_MODE_DISABLED ;
}
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac vdev %d psmode %s \n " ,
2013-09-08 17:56:07 +03:00
arvif - > vdev_id , psmode ? " enable " : " disable " ) ;
2013-10-16 15:44:46 +03:00
ret = ath10k_wmi_set_psmode ( ar , arvif - > vdev_id , psmode ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set PS Mode %d for vdev %d: %d \n " ,
2014-03-25 14:18:51 +02:00
psmode , arvif - > vdev_id , ret ) ;
2013-10-16 15:44:46 +03:00
return ret ;
}
return 0 ;
2013-06-12 20:52:10 +03:00
}
2015-01-28 09:57:49 +02:00
static int ath10k_mac_vif_disable_keepalive ( struct ath10k_vif * arvif )
{
struct ath10k * ar = arvif - > ar ;
struct wmi_sta_keepalive_arg arg = { } ;
int ret ;
lockdep_assert_held ( & arvif - > ar - > conf_mutex ) ;
if ( arvif - > vdev_type ! = WMI_VDEV_TYPE_STA )
return 0 ;
if ( ! test_bit ( WMI_SERVICE_STA_KEEP_ALIVE , ar - > wmi . svc_map ) )
return 0 ;
/* Some firmware revisions have a bug and ignore the `enabled` field.
* Instead use the interval to disable the keepalive .
*/
arg . vdev_id = arvif - > vdev_id ;
arg . enabled = 1 ;
arg . method = WMI_STA_KEEPALIVE_METHOD_NULL_FRAME ;
arg . interval = WMI_STA_KEEPALIVE_INTERVAL_DISABLE ;
ret = ath10k_wmi_sta_keepalive ( ar , & arg ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to submit keepalive on vdev %i: %d \n " ,
arvif - > vdev_id , ret ) ;
return ret ;
}
return 0 ;
}
2015-03-05 16:02:17 +02:00
static void ath10k_mac_vif_ap_csa_count_down ( struct ath10k_vif * arvif )
{
struct ath10k * ar = arvif - > ar ;
struct ieee80211_vif * vif = arvif - > vif ;
int ret ;
2015-03-09 14:19:24 +01:00
lockdep_assert_held ( & arvif - > ar - > conf_mutex ) ;
if ( WARN_ON ( ! test_bit ( WMI_SERVICE_BEACON_OFFLOAD , ar - > wmi . svc_map ) ) )
return ;
2015-03-05 16:02:17 +02:00
if ( arvif - > vdev_type ! = WMI_VDEV_TYPE_AP )
return ;
if ( ! vif - > csa_active )
return ;
if ( ! arvif - > is_up )
return ;
if ( ! ieee80211_csa_is_complete ( vif ) ) {
ieee80211_csa_update_counter ( vif ) ;
ret = ath10k_mac_setup_bcn_tmpl ( arvif ) ;
if ( ret )
ath10k_warn ( ar , " failed to update bcn tmpl during csa: %d \n " ,
ret ) ;
ret = ath10k_mac_setup_prb_tmpl ( arvif ) ;
if ( ret )
ath10k_warn ( ar , " failed to update prb tmpl during csa: %d \n " ,
ret ) ;
} else {
ieee80211_csa_finish ( vif ) ;
}
}
static void ath10k_mac_vif_ap_csa_work ( struct work_struct * work )
{
struct ath10k_vif * arvif = container_of ( work , struct ath10k_vif ,
ap_csa_work ) ;
struct ath10k * ar = arvif - > ar ;
mutex_lock ( & ar - > conf_mutex ) ;
ath10k_mac_vif_ap_csa_count_down ( arvif ) ;
mutex_unlock ( & ar - > conf_mutex ) ;
}
2015-03-10 16:22:01 +02:00
static void ath10k_mac_handle_beacon_iter ( void * data , u8 * mac ,
struct ieee80211_vif * vif )
{
struct sk_buff * skb = data ;
struct ieee80211_mgmt * mgmt = ( void * ) skb - > data ;
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
if ( vif - > type ! = NL80211_IFTYPE_STATION )
return ;
if ( ! ether_addr_equal ( mgmt - > bssid , vif - > bss_conf . bssid ) )
return ;
cancel_delayed_work ( & arvif - > connection_loss_work ) ;
}
void ath10k_mac_handle_beacon ( struct ath10k * ar , struct sk_buff * skb )
{
ieee80211_iterate_active_interfaces_atomic ( ar - > hw ,
IEEE80211_IFACE_ITER_NORMAL ,
ath10k_mac_handle_beacon_iter ,
skb ) ;
}
static void ath10k_mac_handle_beacon_miss_iter ( void * data , u8 * mac ,
struct ieee80211_vif * vif )
{
u32 * vdev_id = data ;
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
struct ath10k * ar = arvif - > ar ;
struct ieee80211_hw * hw = ar - > hw ;
if ( arvif - > vdev_id ! = * vdev_id )
return ;
if ( ! arvif - > is_up )
return ;
ieee80211_beacon_loss ( vif ) ;
/* Firmware doesn't report beacon loss events repeatedly. If AP probe
* ( done by mac80211 ) succeeds but beacons do not resume then it
* doesn ' t make sense to continue operation . Queue connection loss work
* which can be cancelled when beacon is received .
*/
ieee80211_queue_delayed_work ( hw , & arvif - > connection_loss_work ,
ATH10K_CONNECTION_LOSS_HZ ) ;
}
void ath10k_mac_handle_beacon_miss ( struct ath10k * ar , u32 vdev_id )
{
ieee80211_iterate_active_interfaces_atomic ( ar - > hw ,
IEEE80211_IFACE_ITER_NORMAL ,
ath10k_mac_handle_beacon_miss_iter ,
& vdev_id ) ;
}
static void ath10k_mac_vif_sta_connection_loss_work ( struct work_struct * work )
{
struct ath10k_vif * arvif = container_of ( work , struct ath10k_vif ,
connection_loss_work . work ) ;
struct ieee80211_vif * vif = arvif - > vif ;
if ( ! arvif - > is_up )
return ;
ieee80211_connection_loss ( vif ) ;
}
2013-06-12 20:52:10 +03:00
/**********************/
/* Station management */
/**********************/
2014-10-21 10:10:29 +03:00
static u32 ath10k_peer_assoc_h_listen_intval ( struct ath10k * ar ,
struct ieee80211_vif * vif )
{
/* Some firmware revisions have unstable STA powersave when listen
* interval is set too high ( e . g . 5 ) . The symptoms are firmware doesn ' t
* generate NullFunc frames properly even if buffered frames have been
* indicated in Beacon TIM . Firmware would seldom wake up to pull
* buffered frames . Often pinging the device from AP would simply fail .
*
* As a workaround set it to 1.
*/
if ( vif - > type = = NL80211_IFTYPE_STATION )
return 1 ;
return ar - > hw - > conf . listen_interval ;
}
2013-06-12 20:52:10 +03:00
static void ath10k_peer_assoc_h_basic ( struct ath10k * ar ,
2014-10-21 10:10:29 +03:00
struct ieee80211_vif * vif ,
2013-06-12 20:52:10 +03:00
struct ieee80211_sta * sta ,
struct wmi_peer_assoc_complete_arg * arg )
{
2014-10-21 10:10:29 +03:00
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
2013-07-05 16:15:15 +03:00
lockdep_assert_held ( & ar - > conf_mutex ) ;
2014-09-14 12:50:49 +03:00
ether_addr_copy ( arg - > addr , sta - > addr ) ;
2013-06-12 20:52:10 +03:00
arg - > vdev_id = arvif - > vdev_id ;
arg - > peer_aid = sta - > aid ;
arg - > peer_flags | = WMI_PEER_AUTH ;
2014-10-21 10:10:29 +03:00
arg - > peer_listen_intval = ath10k_peer_assoc_h_listen_intval ( ar , vif ) ;
2013-06-12 20:52:10 +03:00
arg - > peer_num_spatial_streams = 1 ;
2014-10-21 10:10:29 +03:00
arg - > peer_caps = vif - > bss_conf . assoc_capability ;
2013-06-12 20:52:10 +03:00
}
static void ath10k_peer_assoc_h_crypto ( struct ath10k * ar ,
2014-10-21 10:10:29 +03:00
struct ieee80211_vif * vif ,
2013-06-12 20:52:10 +03:00
struct wmi_peer_assoc_complete_arg * arg )
{
struct ieee80211_bss_conf * info = & vif - > bss_conf ;
struct cfg80211_bss * bss ;
const u8 * rsnie = NULL ;
const u8 * wpaie = NULL ;
2013-07-05 16:15:15 +03:00
lockdep_assert_held ( & ar - > conf_mutex ) ;
2013-06-12 20:52:10 +03:00
bss = cfg80211_get_bss ( ar - > hw - > wiphy , ar - > hw - > conf . chandef . chan ,
2015-02-08 15:52:03 +02:00
info - > bssid , NULL , 0 , IEEE80211_BSS_TYPE_ANY ,
IEEE80211_PRIVACY_ANY ) ;
2013-06-12 20:52:10 +03:00
if ( bss ) {
const struct cfg80211_bss_ies * ies ;
rcu_read_lock ( ) ;
rsnie = ieee80211_bss_get_ie ( bss , WLAN_EID_RSN ) ;
ies = rcu_dereference ( bss - > ies ) ;
wpaie = cfg80211_find_vendor_ie ( WLAN_OUI_MICROSOFT ,
2014-09-14 12:50:06 +03:00
WLAN_OUI_TYPE_MICROSOFT_WPA ,
ies - > data ,
ies - > len ) ;
2013-06-12 20:52:10 +03:00
rcu_read_unlock ( ) ;
cfg80211_put_bss ( ar - > hw - > wiphy , bss ) ;
}
/* FIXME: base on RSN IE/WPA IE is a correct idea? */
if ( rsnie | | wpaie ) {
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_WMI , " %s: rsn ie found \n " , __func__ ) ;
2013-06-12 20:52:10 +03:00
arg - > peer_flags | = WMI_PEER_NEED_PTK_4_WAY ;
}
if ( wpaie ) {
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_WMI , " %s: wpa ie found \n " , __func__ ) ;
2013-06-12 20:52:10 +03:00
arg - > peer_flags | = WMI_PEER_NEED_GTK_2_WAY ;
}
}
static void ath10k_peer_assoc_h_rates ( struct ath10k * ar ,
struct ieee80211_sta * sta ,
struct wmi_peer_assoc_complete_arg * arg )
{
struct wmi_rate_set_arg * rateset = & arg - > peer_legacy_rates ;
const struct ieee80211_supported_band * sband ;
const struct ieee80211_rate * rates ;
u32 ratemask ;
int i ;
2013-07-05 16:15:15 +03:00
lockdep_assert_held ( & ar - > conf_mutex ) ;
2013-06-12 20:52:10 +03:00
sband = ar - > hw - > wiphy - > bands [ ar - > hw - > conf . chandef . chan - > band ] ;
ratemask = sta - > supp_rates [ ar - > hw - > conf . chandef . chan - > band ] ;
rates = sband - > bitrates ;
rateset - > num_rates = 0 ;
for ( i = 0 ; i < 32 ; i + + , ratemask > > = 1 , rates + + ) {
if ( ! ( ratemask & 1 ) )
continue ;
rateset - > rates [ rateset - > num_rates ] = rates - > hw_value ;
rateset - > num_rates + + ;
}
}
static void ath10k_peer_assoc_h_ht ( struct ath10k * ar ,
struct ieee80211_sta * sta ,
struct wmi_peer_assoc_complete_arg * arg )
{
const struct ieee80211_sta_ht_cap * ht_cap = & sta - > ht_cap ;
int i , n ;
2014-09-14 12:50:17 +03:00
u32 stbc ;
2013-06-12 20:52:10 +03:00
2013-07-05 16:15:15 +03:00
lockdep_assert_held ( & ar - > conf_mutex ) ;
2013-06-12 20:52:10 +03:00
if ( ! ht_cap - > ht_supported )
return ;
arg - > peer_flags | = WMI_PEER_HT ;
arg - > peer_max_mpdu = ( 1 < < ( IEEE80211_HT_MAX_AMPDU_FACTOR +
ht_cap - > ampdu_factor ) ) - 1 ;
arg - > peer_mpdu_density =
ath10k_parse_mpdudensity ( ht_cap - > ampdu_density ) ;
arg - > peer_ht_caps = ht_cap - > cap ;
arg - > peer_rate_caps | = WMI_RC_HT_FLAG ;
if ( ht_cap - > cap & IEEE80211_HT_CAP_LDPC_CODING )
arg - > peer_flags | = WMI_PEER_LDPC ;
if ( sta - > bandwidth > = IEEE80211_STA_RX_BW_40 ) {
arg - > peer_flags | = WMI_PEER_40MHZ ;
arg - > peer_rate_caps | = WMI_RC_CW40_FLAG ;
}
if ( ht_cap - > cap & IEEE80211_HT_CAP_SGI_20 )
arg - > peer_rate_caps | = WMI_RC_SGI_FLAG ;
if ( ht_cap - > cap & IEEE80211_HT_CAP_SGI_40 )
arg - > peer_rate_caps | = WMI_RC_SGI_FLAG ;
if ( ht_cap - > cap & IEEE80211_HT_CAP_TX_STBC ) {
arg - > peer_rate_caps | = WMI_RC_TX_STBC_FLAG ;
arg - > peer_flags | = WMI_PEER_STBC ;
}
if ( ht_cap - > cap & IEEE80211_HT_CAP_RX_STBC ) {
stbc = ht_cap - > cap & IEEE80211_HT_CAP_RX_STBC ;
stbc = stbc > > IEEE80211_HT_CAP_RX_STBC_SHIFT ;
stbc = stbc < < WMI_RC_RX_STBC_FLAG_S ;
arg - > peer_rate_caps | = stbc ;
arg - > peer_flags | = WMI_PEER_STBC ;
}
if ( ht_cap - > mcs . rx_mask [ 1 ] & & ht_cap - > mcs . rx_mask [ 2 ] )
arg - > peer_rate_caps | = WMI_RC_TS_FLAG ;
else if ( ht_cap - > mcs . rx_mask [ 1 ] )
arg - > peer_rate_caps | = WMI_RC_DS_FLAG ;
for ( i = 0 , n = 0 ; i < IEEE80211_HT_MCS_MASK_LEN * 8 ; i + + )
if ( ht_cap - > mcs . rx_mask [ i / 8 ] & ( 1 < < i % 8 ) )
arg - > peer_ht_rates . rates [ n + + ] = i ;
2014-02-10 13:12:55 +01:00
/*
* This is a workaround for HT - enabled STAs which break the spec
* and have no HT capabilities RX mask ( no HT RX MCS map ) .
*
* As per spec , in section 20.3 .5 Modulation and coding scheme ( MCS ) ,
* MCS 0 through 7 are mandatory in 20 MHz with 800 ns GI at all STAs .
*
* Firmware asserts if such situation occurs .
*/
if ( n = = 0 ) {
arg - > peer_ht_rates . num_rates = 8 ;
for ( i = 0 ; i < arg - > peer_ht_rates . num_rates ; i + + )
arg - > peer_ht_rates . rates [ i ] = i ;
} else {
arg - > peer_ht_rates . num_rates = n ;
arg - > peer_num_spatial_streams = sta - > rx_nss ;
}
2013-06-12 20:52:10 +03:00
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac ht peer %pM mcs cnt %d nss %d \n " ,
2013-09-08 17:56:07 +03:00
arg - > addr ,
2013-06-12 20:52:10 +03:00
arg - > peer_ht_rates . num_rates ,
arg - > peer_num_spatial_streams ) ;
}
2014-01-21 07:06:53 +01:00
static int ath10k_peer_assoc_qos_ap ( struct ath10k * ar ,
struct ath10k_vif * arvif ,
struct ieee80211_sta * sta )
2013-06-12 20:52:10 +03:00
{
u32 uapsd = 0 ;
u32 max_sp = 0 ;
2014-01-21 07:06:53 +01:00
int ret = 0 ;
2013-06-12 20:52:10 +03:00
2013-07-05 16:15:15 +03:00
lockdep_assert_held ( & ar - > conf_mutex ) ;
2013-06-12 20:52:10 +03:00
if ( sta - > wme & & sta - > uapsd_queues ) {
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac uapsd_queues 0x%x max_sp %d \n " ,
2013-06-12 20:52:10 +03:00
sta - > uapsd_queues , sta - > max_sp ) ;
if ( sta - > uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO )
uapsd | = WMI_AP_PS_UAPSD_AC3_DELIVERY_EN |
WMI_AP_PS_UAPSD_AC3_TRIGGER_EN ;
if ( sta - > uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI )
uapsd | = WMI_AP_PS_UAPSD_AC2_DELIVERY_EN |
WMI_AP_PS_UAPSD_AC2_TRIGGER_EN ;
if ( sta - > uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK )
uapsd | = WMI_AP_PS_UAPSD_AC1_DELIVERY_EN |
WMI_AP_PS_UAPSD_AC1_TRIGGER_EN ;
if ( sta - > uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE )
uapsd | = WMI_AP_PS_UAPSD_AC0_DELIVERY_EN |
WMI_AP_PS_UAPSD_AC0_TRIGGER_EN ;
if ( sta - > max_sp < MAX_WMI_AP_PS_PEER_PARAM_MAX_SP )
max_sp = sta - > max_sp ;
2014-01-21 07:06:53 +01:00
ret = ath10k_wmi_set_ap_ps_param ( ar , arvif - > vdev_id ,
sta - > addr ,
WMI_AP_PS_PEER_PARAM_UAPSD ,
uapsd ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set ap ps peer param uapsd for vdev %i: %d \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2014-01-21 07:06:53 +01:00
return ret ;
}
2013-06-12 20:52:10 +03:00
2014-01-21 07:06:53 +01:00
ret = ath10k_wmi_set_ap_ps_param ( ar , arvif - > vdev_id ,
sta - > addr ,
WMI_AP_PS_PEER_PARAM_MAX_SP ,
max_sp ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set ap ps peer param max sp for vdev %i: %d \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2014-01-21 07:06:53 +01:00
return ret ;
}
2013-06-12 20:52:10 +03:00
/* TODO setup this based on STA listen interval and
beacon interval . Currently we don ' t know
sta - > listen_interval - mac80211 patch required .
Currently use 10 seconds */
2014-01-21 07:06:53 +01:00
ret = ath10k_wmi_set_ap_ps_param ( ar , arvif - > vdev_id , sta - > addr ,
2014-09-14 12:50:06 +03:00
WMI_AP_PS_PEER_PARAM_AGEOUT_TIME ,
10 ) ;
2014-01-21 07:06:53 +01:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set ap ps peer param ageout time for vdev %i: %d \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2014-01-21 07:06:53 +01:00
return ret ;
}
2013-06-12 20:52:10 +03:00
}
2014-01-21 07:06:53 +01:00
return 0 ;
2013-06-12 20:52:10 +03:00
}
static void ath10k_peer_assoc_h_vht ( struct ath10k * ar ,
struct ieee80211_sta * sta ,
struct wmi_peer_assoc_complete_arg * arg )
{
const struct ieee80211_sta_vht_cap * vht_cap = & sta - > vht_cap ;
2013-10-07 19:51:57 -07:00
u8 ampdu_factor ;
2013-06-12 20:52:10 +03:00
if ( ! vht_cap - > vht_supported )
return ;
arg - > peer_flags | = WMI_PEER_VHT ;
2015-01-23 08:18:20 +08:00
if ( ar - > hw - > conf . chandef . chan - > band = = IEEE80211_BAND_2GHZ )
arg - > peer_flags | = WMI_PEER_VHT_2G ;
2013-06-12 20:52:10 +03:00
arg - > peer_vht_caps = vht_cap - > cap ;
2013-10-07 19:51:57 -07:00
ampdu_factor = ( vht_cap - > cap &
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK ) > >
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT ;
/* Workaround: Some Netgear/Linksys 11ac APs set Rx A-MPDU factor to
* zero in VHT IE . Using it would result in degraded throughput .
* arg - > peer_max_mpdu at this point contains HT max_mpdu so keep
* it if VHT max_mpdu is smaller . */
arg - > peer_max_mpdu = max ( arg - > peer_max_mpdu ,
( 1U < < ( IEEE80211_HT_MAX_AMPDU_FACTOR +
ampdu_factor ) ) - 1 ) ;
2013-06-12 20:52:10 +03:00
if ( sta - > bandwidth = = IEEE80211_STA_RX_BW_80 )
arg - > peer_flags | = WMI_PEER_80MHZ ;
arg - > peer_vht_rates . rx_max_rate =
__le16_to_cpu ( vht_cap - > vht_mcs . rx_highest ) ;
arg - > peer_vht_rates . rx_mcs_set =
__le16_to_cpu ( vht_cap - > vht_mcs . rx_mcs_map ) ;
arg - > peer_vht_rates . tx_max_rate =
__le16_to_cpu ( vht_cap - > vht_mcs . tx_highest ) ;
arg - > peer_vht_rates . tx_mcs_set =
__le16_to_cpu ( vht_cap - > vht_mcs . tx_mcs_map ) ;
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac vht peer %pM max_mpdu %d flags 0x%x \n " ,
2013-09-08 17:56:07 +03:00
sta - > addr , arg - > peer_max_mpdu , arg - > peer_flags ) ;
2013-06-12 20:52:10 +03:00
}
static void ath10k_peer_assoc_h_qos ( struct ath10k * ar ,
2014-10-21 10:10:29 +03:00
struct ieee80211_vif * vif ,
2013-06-12 20:52:10 +03:00
struct ieee80211_sta * sta ,
struct wmi_peer_assoc_complete_arg * arg )
{
2014-10-21 10:10:29 +03:00
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
2013-06-12 20:52:10 +03:00
switch ( arvif - > vdev_type ) {
case WMI_VDEV_TYPE_AP :
2014-01-21 07:06:53 +01:00
if ( sta - > wme )
arg - > peer_flags | = WMI_PEER_QOS ;
if ( sta - > wme & & sta - > uapsd_queues ) {
arg - > peer_flags | = WMI_PEER_APSD ;
arg - > peer_rate_caps | = WMI_RC_UAPSD_FLAG ;
}
2013-06-12 20:52:10 +03:00
break ;
case WMI_VDEV_TYPE_STA :
2014-10-21 10:10:29 +03:00
if ( vif - > bss_conf . qos )
2014-01-21 07:06:53 +01:00
arg - > peer_flags | = WMI_PEER_QOS ;
2013-06-12 20:52:10 +03:00
break ;
2014-12-17 12:29:54 +02:00
case WMI_VDEV_TYPE_IBSS :
if ( sta - > wme )
arg - > peer_flags | = WMI_PEER_QOS ;
break ;
2013-06-12 20:52:10 +03:00
default :
break ;
}
2014-12-17 12:29:54 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac peer %pM qos %d \n " ,
sta - > addr , ! ! ( arg - > peer_flags & WMI_PEER_QOS ) ) ;
2013-06-12 20:52:10 +03:00
}
2014-12-12 12:41:35 +01:00
static bool ath10k_mac_sta_has_11g_rates ( struct ieee80211_sta * sta )
{
/* First 4 rates in ath10k_rates are CCK (11b) rates. */
return sta - > supp_rates [ IEEE80211_BAND_2GHZ ] > > 4 ;
}
2013-06-12 20:52:10 +03:00
static void ath10k_peer_assoc_h_phymode ( struct ath10k * ar ,
2014-10-21 10:10:29 +03:00
struct ieee80211_vif * vif ,
2013-06-12 20:52:10 +03:00
struct ieee80211_sta * sta ,
struct wmi_peer_assoc_complete_arg * arg )
{
enum wmi_phy_mode phymode = MODE_UNKNOWN ;
switch ( ar - > hw - > conf . chandef . chan - > band ) {
case IEEE80211_BAND_2GHZ :
2015-01-23 08:18:20 +08:00
if ( sta - > vht_cap . vht_supported ) {
if ( sta - > bandwidth = = IEEE80211_STA_RX_BW_40 )
phymode = MODE_11AC_VHT40 ;
else
phymode = MODE_11AC_VHT20 ;
} else if ( sta - > ht_cap . ht_supported ) {
2013-06-12 20:52:10 +03:00
if ( sta - > bandwidth = = IEEE80211_STA_RX_BW_40 )
phymode = MODE_11NG_HT40 ;
else
phymode = MODE_11NG_HT20 ;
2014-12-12 12:41:35 +01:00
} else if ( ath10k_mac_sta_has_11g_rates ( sta ) ) {
2013-06-12 20:52:10 +03:00
phymode = MODE_11G ;
2014-12-12 12:41:35 +01:00
} else {
phymode = MODE_11B ;
2013-06-12 20:52:10 +03:00
}
break ;
case IEEE80211_BAND_5GHZ :
2013-09-08 18:19:55 +03:00
/*
* Check VHT first .
*/
if ( sta - > vht_cap . vht_supported ) {
if ( sta - > bandwidth = = IEEE80211_STA_RX_BW_80 )
phymode = MODE_11AC_VHT80 ;
else if ( sta - > bandwidth = = IEEE80211_STA_RX_BW_40 )
phymode = MODE_11AC_VHT40 ;
else if ( sta - > bandwidth = = IEEE80211_STA_RX_BW_20 )
phymode = MODE_11AC_VHT20 ;
} else if ( sta - > ht_cap . ht_supported ) {
2013-06-12 20:52:10 +03:00
if ( sta - > bandwidth = = IEEE80211_STA_RX_BW_40 )
phymode = MODE_11NA_HT40 ;
else
phymode = MODE_11NA_HT20 ;
} else {
phymode = MODE_11A ;
}
break ;
default :
break ;
}
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac peer %pM phymode %s \n " ,
2013-09-08 17:56:14 +03:00
sta - > addr , ath10k_wmi_phymode_str ( phymode ) ) ;
2013-09-08 17:56:07 +03:00
2013-06-12 20:52:10 +03:00
arg - > peer_phymode = phymode ;
WARN_ON ( phymode = = MODE_UNKNOWN ) ;
}
2013-10-16 15:44:46 +03:00
static int ath10k_peer_assoc_prepare ( struct ath10k * ar ,
2014-10-21 10:10:29 +03:00
struct ieee80211_vif * vif ,
2013-10-16 15:44:46 +03:00
struct ieee80211_sta * sta ,
struct wmi_peer_assoc_complete_arg * arg )
2013-06-12 20:52:10 +03:00
{
2013-07-05 16:15:15 +03:00
lockdep_assert_held ( & ar - > conf_mutex ) ;
2013-10-16 15:44:46 +03:00
memset ( arg , 0 , sizeof ( * arg ) ) ;
2013-06-12 20:52:10 +03:00
2014-10-21 10:10:29 +03:00
ath10k_peer_assoc_h_basic ( ar , vif , sta , arg ) ;
ath10k_peer_assoc_h_crypto ( ar , vif , arg ) ;
2013-10-16 15:44:46 +03:00
ath10k_peer_assoc_h_rates ( ar , sta , arg ) ;
ath10k_peer_assoc_h_ht ( ar , sta , arg ) ;
ath10k_peer_assoc_h_vht ( ar , sta , arg ) ;
2014-10-21 10:10:29 +03:00
ath10k_peer_assoc_h_qos ( ar , vif , sta , arg ) ;
ath10k_peer_assoc_h_phymode ( ar , vif , sta , arg ) ;
2013-06-12 20:52:10 +03:00
2013-10-16 15:44:46 +03:00
return 0 ;
2013-06-12 20:52:10 +03:00
}
2014-02-14 14:45:51 +01:00
static const u32 ath10k_smps_map [ ] = {
[ WLAN_HT_CAP_SM_PS_STATIC ] = WMI_PEER_SMPS_STATIC ,
[ WLAN_HT_CAP_SM_PS_DYNAMIC ] = WMI_PEER_SMPS_DYNAMIC ,
[ WLAN_HT_CAP_SM_PS_INVALID ] = WMI_PEER_SMPS_PS_NONE ,
[ WLAN_HT_CAP_SM_PS_DISABLED ] = WMI_PEER_SMPS_PS_NONE ,
} ;
static int ath10k_setup_peer_smps ( struct ath10k * ar , struct ath10k_vif * arvif ,
const u8 * addr ,
const struct ieee80211_sta_ht_cap * ht_cap )
{
int smps ;
if ( ! ht_cap - > ht_supported )
return 0 ;
smps = ht_cap - > cap & IEEE80211_HT_CAP_SM_PS ;
smps > > = IEEE80211_HT_CAP_SM_PS_SHIFT ;
if ( smps > = ARRAY_SIZE ( ath10k_smps_map ) )
return - EINVAL ;
return ath10k_wmi_peer_set_param ( ar , arvif - > vdev_id , addr ,
WMI_PEER_SMPS_STATE ,
ath10k_smps_map [ smps ] ) ;
}
2015-02-15 16:50:42 +02:00
static int ath10k_mac_vif_recalc_txbf ( struct ath10k * ar ,
struct ieee80211_vif * vif ,
struct ieee80211_sta_vht_cap vht_cap )
{
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
int ret ;
u32 param ;
u32 value ;
if ( ! ( ar - > vht_cap_info &
( IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE |
IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE ) ) )
return 0 ;
param = ar - > wmi . vdev_param - > txbf ;
value = 0 ;
if ( WARN_ON ( param = = WMI_VDEV_PARAM_UNSUPPORTED ) )
return 0 ;
/* The following logic is correct. If a remote STA advertises support
* for being a beamformer then we should enable us being a beamformee .
*/
if ( ar - > vht_cap_info &
( IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE ) ) {
if ( vht_cap . cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE )
value | = WMI_VDEV_PARAM_TXBF_SU_TX_BFEE ;
if ( vht_cap . cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE )
value | = WMI_VDEV_PARAM_TXBF_MU_TX_BFEE ;
}
if ( ar - > vht_cap_info &
( IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE ) ) {
if ( vht_cap . cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE )
value | = WMI_VDEV_PARAM_TXBF_SU_TX_BFER ;
if ( vht_cap . cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE )
value | = WMI_VDEV_PARAM_TXBF_MU_TX_BFER ;
}
if ( value & WMI_VDEV_PARAM_TXBF_MU_TX_BFEE )
value | = WMI_VDEV_PARAM_TXBF_SU_TX_BFEE ;
if ( value & WMI_VDEV_PARAM_TXBF_MU_TX_BFER )
value | = WMI_VDEV_PARAM_TXBF_SU_TX_BFER ;
ret = ath10k_wmi_vdev_set_param ( ar , arvif - > vdev_id , param , value ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to submit vdev param txbf 0x%x: %d \n " ,
value , ret ) ;
return ret ;
}
return 0 ;
}
2013-06-12 20:52:10 +03:00
/* can be called only in mac80211 callbacks due to `key_count` usage */
static void ath10k_bss_assoc ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif ,
struct ieee80211_bss_conf * bss_conf )
{
struct ath10k * ar = hw - > priv ;
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
2014-02-14 14:45:51 +01:00
struct ieee80211_sta_ht_cap ht_cap ;
2015-02-15 16:50:42 +02:00
struct ieee80211_sta_vht_cap vht_cap ;
2013-10-16 15:44:46 +03:00
struct wmi_peer_assoc_complete_arg peer_arg ;
2013-06-12 20:52:10 +03:00
struct ieee80211_sta * ap_sta ;
int ret ;
2013-07-05 16:15:15 +03:00
lockdep_assert_held ( & ar - > conf_mutex ) ;
2014-10-21 10:10:29 +03:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac vdev %i assoc bssid %pM aid %d \n " ,
arvif - > vdev_id , arvif - > bssid , arvif - > aid ) ;
2013-06-12 20:52:10 +03:00
rcu_read_lock ( ) ;
ap_sta = ieee80211_find_sta ( vif , bss_conf - > bssid ) ;
if ( ! ap_sta ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to find station entry for bss %pM vdev %i \n " ,
2014-02-27 18:50:00 +02:00
bss_conf - > bssid , arvif - > vdev_id ) ;
2013-06-12 20:52:10 +03:00
rcu_read_unlock ( ) ;
return ;
}
2014-02-14 14:45:51 +01:00
/* ap_sta must be accessed only within rcu section which must be left
* before calling ath10k_setup_peer_smps ( ) which might sleep . */
ht_cap = ap_sta - > ht_cap ;
2015-02-15 16:50:42 +02:00
vht_cap = ap_sta - > vht_cap ;
2014-02-14 14:45:51 +01:00
2014-10-21 10:10:29 +03:00
ret = ath10k_peer_assoc_prepare ( ar , vif , ap_sta , & peer_arg ) ;
2013-06-12 20:52:10 +03:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to prepare peer assoc for %pM vdev %i: %d \n " ,
2014-02-27 18:50:00 +02:00
bss_conf - > bssid , arvif - > vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
rcu_read_unlock ( ) ;
return ;
}
rcu_read_unlock ( ) ;
2013-10-16 15:44:46 +03:00
ret = ath10k_wmi_peer_assoc ( ar , & peer_arg ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to run peer assoc for %pM vdev %i: %d \n " ,
2014-02-27 18:50:00 +02:00
bss_conf - > bssid , arvif - > vdev_id , ret ) ;
2013-10-16 15:44:46 +03:00
return ;
}
2014-02-14 14:45:51 +01:00
ret = ath10k_setup_peer_smps ( ar , arvif , bss_conf - > bssid , & ht_cap ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to setup peer SMPS for vdev %i: %d \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2014-02-14 14:45:51 +01:00
return ;
}
2015-02-15 16:50:42 +02:00
ret = ath10k_mac_vif_recalc_txbf ( ar , vif , vht_cap ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to recalc txbf for vdev %i on bss %pM: %d \n " ,
arvif - > vdev_id , bss_conf - > bssid , ret ) ;
return ;
}
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC ,
2013-09-08 17:56:07 +03:00
" mac vdev %d up (associated) bssid %pM aid %d \n " ,
arvif - > vdev_id , bss_conf - > bssid , bss_conf - > aid ) ;
2014-10-21 10:10:29 +03:00
WARN_ON ( arvif - > is_up ) ;
2014-01-23 11:38:25 +01:00
arvif - > aid = bss_conf - > aid ;
2014-09-14 12:50:49 +03:00
ether_addr_copy ( arvif - > bssid , bss_conf - > bssid ) ;
2014-01-23 11:38:25 +01:00
ret = ath10k_wmi_vdev_up ( ar , arvif - > vdev_id , arvif - > aid , arvif - > bssid ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set vdev %d up: %d \n " ,
2013-06-12 20:52:10 +03:00
arvif - > vdev_id , ret ) ;
2014-01-23 11:38:25 +01:00
return ;
}
arvif - > is_up = true ;
2015-02-13 13:30:15 +01:00
/* Workaround: Some firmware revisions (tested with qca6174
* WLAN . RM .2 .0 - 00073 ) have buggy powersave state machine and must be
* poked with peer param command .
*/
ret = ath10k_wmi_peer_set_param ( ar , arvif - > vdev_id , arvif - > bssid ,
WMI_PEER_DUMMY_VAR , 1 ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to poke peer %pM param for ps workaround on vdev %i: %d \n " ,
arvif - > bssid , arvif - > vdev_id , ret ) ;
return ;
}
2013-06-12 20:52:10 +03:00
}
static void ath10k_bss_disassoc ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif )
{
struct ath10k * ar = hw - > priv ;
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
2015-02-15 16:50:42 +02:00
struct ieee80211_sta_vht_cap vht_cap = { } ;
2013-06-12 20:52:10 +03:00
int ret ;
2013-07-05 16:15:15 +03:00
lockdep_assert_held ( & ar - > conf_mutex ) ;
2014-10-21 10:10:29 +03:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac vdev %i disassoc bssid %pM \n " ,
arvif - > vdev_id , arvif - > bssid ) ;
2013-09-08 17:56:07 +03:00
2013-06-12 20:52:10 +03:00
ret = ath10k_wmi_vdev_down ( ar , arvif - > vdev_id ) ;
2014-10-21 10:10:29 +03:00
if ( ret )
ath10k_warn ( ar , " faield to down vdev %i: %d \n " ,
arvif - > vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
2015-01-29 13:50:38 +02:00
arvif - > def_wep_key_idx = - 1 ;
2015-02-15 16:50:42 +02:00
ret = ath10k_mac_vif_recalc_txbf ( ar , vif , vht_cap ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to recalc txbf for vdev %i: %d \n " ,
arvif - > vdev_id , ret ) ;
return ;
}
2014-01-23 11:38:25 +01:00
arvif - > is_up = false ;
2015-03-10 16:22:01 +02:00
cancel_delayed_work_sync ( & arvif - > connection_loss_work ) ;
2013-06-12 20:52:10 +03:00
}
2014-10-21 10:10:29 +03:00
static int ath10k_station_assoc ( struct ath10k * ar ,
struct ieee80211_vif * vif ,
struct ieee80211_sta * sta ,
bool reassoc )
2013-06-12 20:52:10 +03:00
{
2014-10-21 10:10:29 +03:00
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
2013-10-16 15:44:46 +03:00
struct wmi_peer_assoc_complete_arg peer_arg ;
2013-06-12 20:52:10 +03:00
int ret = 0 ;
2013-07-05 16:15:15 +03:00
lockdep_assert_held ( & ar - > conf_mutex ) ;
2014-10-21 10:10:29 +03:00
ret = ath10k_peer_assoc_prepare ( ar , vif , sta , & peer_arg ) ;
2013-10-16 15:44:46 +03:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to prepare WMI peer assoc for %pM vdev %i: %i \n " ,
2014-02-27 18:50:00 +02:00
sta - > addr , arvif - > vdev_id , ret ) ;
2013-10-16 15:44:46 +03:00
return ret ;
}
2014-03-07 10:19:30 +02:00
peer_arg . peer_reassoc = reassoc ;
2013-10-16 15:44:46 +03:00
ret = ath10k_wmi_peer_assoc ( ar , & peer_arg ) ;
2013-06-12 20:52:10 +03:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to run peer assoc for STA %pM vdev %i: %d \n " ,
2014-02-27 18:50:00 +02:00
sta - > addr , arvif - > vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
return ret ;
}
2014-10-21 10:10:29 +03:00
/* Re-assoc is run only to update supported rates for given station. It
* doesn ' t make much sense to reconfigure the peer completely .
*/
if ( ! reassoc ) {
ret = ath10k_setup_peer_smps ( ar , arvif , sta - > addr ,
& sta - > ht_cap ) ;
2014-03-11 12:58:00 +02:00
if ( ret ) {
2014-10-21 10:10:29 +03:00
ath10k_warn ( ar , " failed to setup peer SMPS for vdev %d: %d \n " ,
2014-03-11 12:58:00 +02:00
arvif - > vdev_id , ret ) ;
return ret ;
}
2014-10-21 10:10:29 +03:00
ret = ath10k_peer_assoc_qos_ap ( ar , arvif , sta ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to set qos params for STA %pM for vdev %i: %d \n " ,
sta - > addr , arvif - > vdev_id , ret ) ;
return ret ;
}
2013-06-12 20:52:10 +03:00
2014-10-21 10:10:29 +03:00
if ( ! sta - > wme ) {
arvif - > num_legacy_stations + + ;
ret = ath10k_recalc_rtscts_prot ( arvif ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to recalculate rts/cts prot for vdev %d: %d \n " ,
arvif - > vdev_id , ret ) ;
return ret ;
}
}
2015-01-29 13:50:38 +02:00
/* Plumb cached keys only for static WEP */
if ( arvif - > def_wep_key_idx ! = - 1 ) {
ret = ath10k_install_peer_wep_keys ( arvif , sta - > addr ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to install peer wep keys for vdev %i: %d \n " ,
arvif - > vdev_id , ret ) ;
return ret ;
}
2014-10-21 10:10:29 +03:00
}
2014-01-21 07:06:53 +01:00
}
2013-06-12 20:52:10 +03:00
return ret ;
}
2014-10-21 10:10:29 +03:00
static int ath10k_station_disassoc ( struct ath10k * ar ,
struct ieee80211_vif * vif ,
2013-06-12 20:52:10 +03:00
struct ieee80211_sta * sta )
{
2014-10-21 10:10:29 +03:00
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
2013-06-12 20:52:10 +03:00
int ret = 0 ;
2013-07-05 16:15:15 +03:00
lockdep_assert_held ( & ar - > conf_mutex ) ;
2014-03-11 12:58:00 +02:00
if ( ! sta - > wme ) {
arvif - > num_legacy_stations - - ;
ret = ath10k_recalc_rtscts_prot ( arvif ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to recalculate rts/cts prot for vdev %d: %d \n " ,
2014-03-11 12:58:00 +02:00
arvif - > vdev_id , ret ) ;
return ret ;
}
}
2013-06-12 20:52:10 +03:00
ret = ath10k_clear_peer_keys ( arvif , sta - > addr ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to clear all peer wep keys for vdev %i: %d \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
return ret ;
}
return ret ;
}
/**************/
/* Regulatory */
/**************/
static int ath10k_update_channel_list ( struct ath10k * ar )
{
struct ieee80211_hw * hw = ar - > hw ;
struct ieee80211_supported_band * * bands ;
enum ieee80211_band band ;
struct ieee80211_channel * channel ;
struct wmi_scan_chan_list_arg arg = { 0 } ;
struct wmi_channel_arg * ch ;
bool passive ;
int len ;
int ret ;
int i ;
2013-07-05 16:15:15 +03:00
lockdep_assert_held ( & ar - > conf_mutex ) ;
2013-06-12 20:52:10 +03:00
bands = hw - > wiphy - > bands ;
for ( band = 0 ; band < IEEE80211_NUM_BANDS ; band + + ) {
if ( ! bands [ band ] )
continue ;
for ( i = 0 ; i < bands [ band ] - > n_channels ; i + + ) {
if ( bands [ band ] - > channels [ i ] . flags &
IEEE80211_CHAN_DISABLED )
continue ;
arg . n_channels + + ;
}
}
len = sizeof ( struct wmi_channel_arg ) * arg . n_channels ;
arg . channels = kzalloc ( len , GFP_KERNEL ) ;
if ( ! arg . channels )
return - ENOMEM ;
ch = arg . channels ;
for ( band = 0 ; band < IEEE80211_NUM_BANDS ; band + + ) {
if ( ! bands [ band ] )
continue ;
for ( i = 0 ; i < bands [ band ] - > n_channels ; i + + ) {
channel = & bands [ band ] - > channels [ i ] ;
if ( channel - > flags & IEEE80211_CHAN_DISABLED )
continue ;
ch - > allow_ht = true ;
/* FIXME: when should we really allow VHT? */
ch - > allow_vht = true ;
ch - > allow_ibss =
2013-10-21 19:22:25 +02:00
! ( channel - > flags & IEEE80211_CHAN_NO_IR ) ;
2013-06-12 20:52:10 +03:00
ch - > ht40plus =
! ( channel - > flags & IEEE80211_CHAN_NO_HT40PLUS ) ;
2013-11-20 09:59:47 +02:00
ch - > chan_radar =
! ! ( channel - > flags & IEEE80211_CHAN_RADAR ) ;
2013-10-21 19:22:25 +02:00
passive = channel - > flags & IEEE80211_CHAN_NO_IR ;
2013-06-12 20:52:10 +03:00
ch - > passive = passive ;
ch - > freq = channel - > center_freq ;
2014-09-18 15:21:21 +02:00
ch - > band_center_freq1 = channel - > center_freq ;
2013-10-23 04:02:13 -07:00
ch - > min_power = 0 ;
2013-10-23 04:02:14 -07:00
ch - > max_power = channel - > max_power * 2 ;
ch - > max_reg_power = channel - > max_reg_power * 2 ;
ch - > max_antenna_gain = channel - > max_antenna_gain * 2 ;
2013-06-12 20:52:10 +03:00
ch - > reg_class_id = 0 ; /* FIXME */
/* FIXME: why use only legacy modes, why not any
* HT / VHT modes ? Would that even make any
* difference ? */
if ( channel - > band = = IEEE80211_BAND_2GHZ )
ch - > mode = MODE_11G ;
else
ch - > mode = MODE_11A ;
if ( WARN_ON_ONCE ( ch - > mode = = MODE_UNKNOWN ) )
continue ;
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_WMI ,
2013-09-08 17:56:07 +03:00
" mac channel [%zd/%d] freq %d maxpower %d regpower %d antenna %d mode %d \n " ,
ch - arg . channels , arg . n_channels ,
2013-06-12 20:52:10 +03:00
ch - > freq , ch - > max_power , ch - > max_reg_power ,
ch - > max_antenna_gain , ch - > mode ) ;
ch + + ;
}
}
ret = ath10k_wmi_scan_chan_list ( ar , & arg ) ;
kfree ( arg . channels ) ;
return ret ;
}
2014-03-21 17:46:57 +02:00
static enum wmi_dfs_region
ath10k_mac_get_dfs_region ( enum nl80211_dfs_regions dfs_region )
{
switch ( dfs_region ) {
case NL80211_DFS_UNSET :
return WMI_UNINIT_DFS_DOMAIN ;
case NL80211_DFS_FCC :
return WMI_FCC_DFS_DOMAIN ;
case NL80211_DFS_ETSI :
return WMI_ETSI_DFS_DOMAIN ;
case NL80211_DFS_JP :
return WMI_MKK4_DFS_DOMAIN ;
}
return WMI_UNINIT_DFS_DOMAIN ;
}
2013-07-16 09:38:52 +02:00
static void ath10k_regd_update ( struct ath10k * ar )
2013-06-12 20:52:10 +03:00
{
struct reg_dmn_pair_mapping * regpair ;
int ret ;
2014-03-21 17:46:57 +02:00
enum wmi_dfs_region wmi_dfs_reg ;
enum nl80211_dfs_regions nl_dfs_reg ;
2013-06-12 20:52:10 +03:00
2013-07-16 09:38:52 +02:00
lockdep_assert_held ( & ar - > conf_mutex ) ;
2013-06-12 20:52:10 +03:00
ret = ath10k_update_channel_list ( ar ) ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to update channel list: %d \n " , ret ) ;
2013-06-12 20:52:10 +03:00
regpair = ar - > ath_common . regulatory . regpair ;
2013-07-16 09:38:52 +02:00
2014-03-21 17:46:57 +02:00
if ( config_enabled ( CONFIG_ATH10K_DFS_CERTIFIED ) & & ar - > dfs_detector ) {
nl_dfs_reg = ar - > dfs_detector - > region ;
wmi_dfs_reg = ath10k_mac_get_dfs_region ( nl_dfs_reg ) ;
} else {
wmi_dfs_reg = WMI_UNINIT_DFS_DOMAIN ;
}
2013-06-12 20:52:10 +03:00
/* Target allows setting up per-band regdomain but ath_common provides
* a combined one only */
ret = ath10k_wmi_pdev_set_regdomain ( ar ,
2014-02-13 18:13:12 +02:00
regpair - > reg_domain ,
regpair - > reg_domain , /* 2ghz */
regpair - > reg_domain , /* 5ghz */
2013-06-12 20:52:10 +03:00
regpair - > reg_2ghz_ctl ,
2014-03-21 17:46:57 +02:00
regpair - > reg_5ghz_ctl ,
wmi_dfs_reg ) ;
2013-06-12 20:52:10 +03:00
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set pdev regdomain: %d \n " , ret ) ;
2013-07-16 09:38:52 +02:00
}
2013-07-05 16:15:15 +03:00
2013-07-16 09:38:52 +02:00
static void ath10k_reg_notifier ( struct wiphy * wiphy ,
struct regulatory_request * request )
{
struct ieee80211_hw * hw = wiphy_to_ieee80211_hw ( wiphy ) ;
struct ath10k * ar = hw - > priv ;
2013-11-20 09:59:41 +02:00
bool result ;
2013-07-16 09:38:52 +02:00
ath_reg_notifier_apply ( wiphy , request , & ar - > ath_common . regulatory ) ;
2013-11-20 09:59:41 +02:00
if ( config_enabled ( CONFIG_ATH10K_DFS_CERTIFIED ) & & ar - > dfs_detector ) {
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_REGULATORY , " dfs region 0x%x \n " ,
2013-11-20 09:59:41 +02:00
request - > dfs_region ) ;
result = ar - > dfs_detector - > set_dfs_domain ( ar - > dfs_detector ,
request - > dfs_region ) ;
if ( ! result )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " DFS region 0x%X not supported, will trigger radar for every pulse \n " ,
2013-11-20 09:59:41 +02:00
request - > dfs_region ) ;
}
2013-07-16 09:38:52 +02:00
mutex_lock ( & ar - > conf_mutex ) ;
if ( ar - > state = = ATH10K_STATE_ON )
ath10k_regd_update ( ar ) ;
2013-07-05 16:15:15 +03:00
mutex_unlock ( & ar - > conf_mutex ) ;
2013-06-12 20:52:10 +03:00
}
/***************/
/* TX handlers */
/***************/
2013-10-02 11:03:38 +02:00
static u8 ath10k_tx_h_get_tid ( struct ieee80211_hdr * hdr )
{
if ( ieee80211_is_mgmt ( hdr - > frame_control ) )
return HTT_DATA_TX_EXT_TID_MGMT ;
if ( ! ieee80211_is_data_qos ( hdr - > frame_control ) )
return HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST ;
if ( ! is_unicast_ether_addr ( ieee80211_get_DA ( hdr ) ) )
return HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST ;
return ieee80211_get_qos_ctl ( hdr ) [ 0 ] & IEEE80211_QOS_CTL_TID_MASK ;
}
2014-09-02 11:00:22 +03:00
static u8 ath10k_tx_h_get_vdev_id ( struct ath10k * ar , struct ieee80211_vif * vif )
2013-10-02 11:03:39 +02:00
{
2014-09-02 11:00:22 +03:00
if ( vif )
return ath10k_vif_to_arvif ( vif ) - > vdev_id ;
2013-10-02 11:03:39 +02:00
2014-04-08 09:45:47 +03:00
if ( ar - > monitor_started )
2013-10-02 11:03:39 +02:00
return ar - > monitor_vdev_id ;
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to resolve vdev id \n " ) ;
2013-10-02 11:03:39 +02:00
return 0 ;
}
2014-07-21 21:03:09 +03:00
/* HTT Tx uses Native Wifi tx mode which expects 802.11 frames without QoS
* Control in the header .
2013-06-12 20:52:10 +03:00
*/
2014-07-21 21:03:09 +03:00
static void ath10k_tx_h_nwifi ( struct ieee80211_hw * hw , struct sk_buff * skb )
2013-06-12 20:52:10 +03:00
{
struct ieee80211_hdr * hdr = ( void * ) skb - > data ;
2014-07-21 21:03:10 +03:00
struct ath10k_skb_cb * cb = ATH10K_SKB_CB ( skb ) ;
2013-06-12 20:52:10 +03:00
u8 * qos_ctl ;
if ( ! ieee80211_is_data_qos ( hdr - > frame_control ) )
return ;
qos_ctl = ieee80211_get_qos_ctl ( hdr ) ;
2013-07-22 14:25:28 +02:00
memmove ( skb - > data + IEEE80211_QOS_CTL_LEN ,
skb - > data , ( void * ) qos_ctl - ( void * ) skb - > data ) ;
skb_pull ( skb , IEEE80211_QOS_CTL_LEN ) ;
2014-07-21 21:03:10 +03:00
2015-03-11 14:25:26 +01:00
/* Some firmware revisions don't handle sending QoS NullFunc well.
* These frames are mainly used for CQM purposes so it doesn ' t really
* matter whether QoS NullFunc or NullFunc are sent .
2014-07-21 21:03:10 +03:00
*/
2015-01-24 12:14:51 +02:00
hdr = ( void * ) skb - > data ;
2015-03-11 14:25:26 +01:00
if ( ieee80211_is_qos_nullfunc ( hdr - > frame_control ) )
2014-07-21 21:03:10 +03:00
cb - > htt . tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST ;
2015-03-11 14:25:26 +01:00
hdr - > frame_control & = ~ __cpu_to_le16 ( IEEE80211_STYPE_QOS_DATA ) ;
2013-06-12 20:52:10 +03:00
}
2014-07-21 21:03:09 +03:00
static void ath10k_tx_h_add_p2p_noa_ie ( struct ath10k * ar ,
struct ieee80211_vif * vif ,
struct sk_buff * skb )
2013-06-12 20:52:10 +03:00
{
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) skb - > data ;
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
/* This is case only for P2P_GO */
if ( arvif - > vdev_type ! = WMI_VDEV_TYPE_AP | |
arvif - > vdev_subtype ! = WMI_VDEV_SUBTYPE_P2P_GO )
return ;
if ( unlikely ( ieee80211_is_probe_resp ( hdr - > frame_control ) ) ) {
spin_lock_bh ( & ar - > data_lock ) ;
if ( arvif - > u . ap . noa_data )
if ( ! pskb_expand_head ( skb , 0 , arvif - > u . ap . noa_len ,
GFP_ATOMIC ) )
memcpy ( skb_put ( skb , arvif - > u . ap . noa_len ) ,
arvif - > u . ap . noa_data ,
arvif - > u . ap . noa_len ) ;
spin_unlock_bh ( & ar - > data_lock ) ;
}
}
2014-11-24 14:58:31 +01:00
static bool ath10k_mac_need_offchan_tx_work ( struct ath10k * ar )
{
/* FIXME: Not really sure since when the behaviour changed. At some
* point new firmware stopped requiring creation of peer entries for
* offchannel tx ( and actually creating them causes issues with wmi - htc
* tx credit replenishment and reliability ) . Assuming it ' s at least 3.4
* because that ' s when the ` freq ` was introduced to TX_FRM HTT command .
*/
return ! ( ar - > htt . target_version_major > = 3 & &
ar - > htt . target_version_minor > = 4 ) ;
}
2013-06-12 20:52:10 +03:00
static void ath10k_tx_htt ( struct ath10k * ar , struct sk_buff * skb )
{
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) skb - > data ;
2013-09-26 17:47:12 +02:00
int ret = 0 ;
2013-06-12 20:52:10 +03:00
2013-08-09 10:13:34 +02:00
if ( ar - > htt . target_version_major > = 3 ) {
/* Since HTT 3.0 there is no separate mgmt tx command */
ret = ath10k_htt_tx ( & ar - > htt , skb ) ;
goto exit ;
}
2013-09-26 17:47:12 +02:00
if ( ieee80211_is_mgmt ( hdr - > frame_control ) ) {
if ( test_bit ( ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX ,
ar - > fw_features ) ) {
if ( skb_queue_len ( & ar - > wmi_mgmt_tx_queue ) > =
ATH10K_MAX_NUM_MGMT_PENDING ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " reached WMI management transmit queue limit \n " ) ;
2013-09-26 17:47:12 +02:00
ret = - EBUSY ;
goto exit ;
}
skb_queue_tail ( & ar - > wmi_mgmt_tx_queue , skb ) ;
ieee80211_queue_work ( ar - > hw , & ar - > wmi_mgmt_tx_work ) ;
} else {
ret = ath10k_htt_mgmt_tx ( & ar - > htt , skb ) ;
}
} else if ( ! test_bit ( ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX ,
ar - > fw_features ) & &
ieee80211_is_nullfunc ( hdr - > frame_control ) ) {
2013-06-12 20:52:10 +03:00
/* FW does not report tx status properly for NullFunc frames
* unless they are sent through mgmt tx path . mac80211 sends
2013-09-26 17:47:12 +02:00
* those frames when it detects link / beacon loss and depends
* on the tx status to be correct . */
2013-07-05 16:15:14 +03:00
ret = ath10k_htt_mgmt_tx ( & ar - > htt , skb ) ;
2013-09-26 17:47:12 +02:00
} else {
2013-07-05 16:15:14 +03:00
ret = ath10k_htt_tx ( & ar - > htt , skb ) ;
2013-09-26 17:47:12 +02:00
}
2013-06-12 20:52:10 +03:00
2013-08-09 10:13:34 +02:00
exit :
2013-06-12 20:52:10 +03:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to transmit packet, dropping: %d \n " ,
ret ) ;
2013-06-12 20:52:10 +03:00
ieee80211_free_txskb ( ar - > hw , skb ) ;
}
}
void ath10k_offchan_tx_purge ( struct ath10k * ar )
{
struct sk_buff * skb ;
for ( ; ; ) {
skb = skb_dequeue ( & ar - > offchan_tx_queue ) ;
if ( ! skb )
break ;
ieee80211_free_txskb ( ar - > hw , skb ) ;
}
}
void ath10k_offchan_tx_work ( struct work_struct * work )
{
struct ath10k * ar = container_of ( work , struct ath10k , offchan_tx_work ) ;
struct ath10k_peer * peer ;
struct ieee80211_hdr * hdr ;
struct sk_buff * skb ;
const u8 * peer_addr ;
int vdev_id ;
int ret ;
/* FW requirement: We must create a peer before FW will send out
* an offchannel frame . Otherwise the frame will be stuck and
* never transmitted . We delete the peer upon tx completion .
* It is unlikely that a peer for offchannel tx will already be
* present . However it may be in some rare cases so account for that .
* Otherwise we might remove a legitimate peer and break stuff . */
for ( ; ; ) {
skb = skb_dequeue ( & ar - > offchan_tx_queue ) ;
if ( ! skb )
break ;
mutex_lock ( & ar - > conf_mutex ) ;
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac offchannel skb %p \n " ,
2013-06-12 20:52:10 +03:00
skb ) ;
hdr = ( struct ieee80211_hdr * ) skb - > data ;
peer_addr = ieee80211_get_DA ( hdr ) ;
2013-09-26 17:47:12 +02:00
vdev_id = ATH10K_SKB_CB ( skb ) - > vdev_id ;
2013-06-12 20:52:10 +03:00
spin_lock_bh ( & ar - > data_lock ) ;
peer = ath10k_peer_find ( ar , vdev_id , peer_addr ) ;
spin_unlock_bh ( & ar - > data_lock ) ;
if ( peer )
2013-09-08 17:56:07 +03:00
/* FIXME: should this use ath10k_warn()? */
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " peer %pM on vdev %d already present \n " ,
2013-06-12 20:52:10 +03:00
peer_addr , vdev_id ) ;
if ( ! peer ) {
ret = ath10k_peer_create ( ar , vdev_id , peer_addr ) ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to create peer %pM on vdev %d: %d \n " ,
2013-06-12 20:52:10 +03:00
peer_addr , vdev_id , ret ) ;
}
spin_lock_bh ( & ar - > data_lock ) ;
2013-11-14 14:32:02 -08:00
reinit_completion ( & ar - > offchan_tx_completed ) ;
2013-06-12 20:52:10 +03:00
ar - > offchan_tx_skb = skb ;
spin_unlock_bh ( & ar - > data_lock ) ;
ath10k_tx_htt ( ar , skb ) ;
ret = wait_for_completion_timeout ( & ar - > offchan_tx_completed ,
3 * HZ ) ;
2015-01-08 13:27:34 +01:00
if ( ret = = 0 )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " timed out waiting for offchannel skb %p \n " ,
2013-06-12 20:52:10 +03:00
skb ) ;
if ( ! peer ) {
ret = ath10k_peer_delete ( ar , vdev_id , peer_addr ) ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to delete peer %pM on vdev %d: %d \n " ,
2013-06-12 20:52:10 +03:00
peer_addr , vdev_id , ret ) ;
}
mutex_unlock ( & ar - > conf_mutex ) ;
}
}
2013-09-26 17:47:12 +02:00
void ath10k_mgmt_over_wmi_tx_purge ( struct ath10k * ar )
{
struct sk_buff * skb ;
for ( ; ; ) {
skb = skb_dequeue ( & ar - > wmi_mgmt_tx_queue ) ;
if ( ! skb )
break ;
ieee80211_free_txskb ( ar - > hw , skb ) ;
}
}
void ath10k_mgmt_over_wmi_tx_work ( struct work_struct * work )
{
struct ath10k * ar = container_of ( work , struct ath10k , wmi_mgmt_tx_work ) ;
struct sk_buff * skb ;
int ret ;
for ( ; ; ) {
skb = skb_dequeue ( & ar - > wmi_mgmt_tx_queue ) ;
if ( ! skb )
break ;
ret = ath10k_wmi_mgmt_tx ( ar , skb ) ;
2013-10-28 07:18:13 +01:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to transmit management frame via WMI: %d \n " ,
2014-03-25 14:18:51 +02:00
ret ) ;
2013-10-28 07:18:13 +01:00
ieee80211_free_txskb ( ar - > hw , skb ) ;
}
2013-09-26 17:47:12 +02:00
}
}
2013-06-12 20:52:10 +03:00
/************/
/* Scanning */
/************/
2014-08-05 14:54:44 +02:00
void __ath10k_scan_finish ( struct ath10k * ar )
2013-06-12 20:52:10 +03:00
{
2014-08-05 14:54:44 +02:00
lockdep_assert_held ( & ar - > data_lock ) ;
2013-06-12 20:52:10 +03:00
2014-08-05 14:54:44 +02:00
switch ( ar - > scan . state ) {
case ATH10K_SCAN_IDLE :
break ;
case ATH10K_SCAN_RUNNING :
if ( ar - > scan . is_roc )
ieee80211_remain_on_channel_expired ( ar - > hw ) ;
2015-01-12 16:07:02 -05:00
/* fall through */
2014-11-24 14:58:33 +01:00
case ATH10K_SCAN_ABORTING :
if ( ! ar - > scan . is_roc )
2014-08-05 14:54:44 +02:00
ieee80211_scan_completed ( ar - > hw ,
( ar - > scan . state = =
ATH10K_SCAN_ABORTING ) ) ;
/* fall through */
case ATH10K_SCAN_STARTING :
ar - > scan . state = ATH10K_SCAN_IDLE ;
ar - > scan_channel = NULL ;
ath10k_offchan_tx_purge ( ar ) ;
cancel_delayed_work ( & ar - > scan . timeout ) ;
complete_all ( & ar - > scan . completed ) ;
break ;
2013-06-12 20:52:10 +03:00
}
2014-08-05 14:54:44 +02:00
}
2013-06-12 20:52:10 +03:00
2014-08-05 14:54:44 +02:00
void ath10k_scan_finish ( struct ath10k * ar )
{
spin_lock_bh ( & ar - > data_lock ) ;
__ath10k_scan_finish ( ar ) ;
2013-06-12 20:52:10 +03:00
spin_unlock_bh ( & ar - > data_lock ) ;
}
2014-08-05 14:54:44 +02:00
static int ath10k_scan_stop ( struct ath10k * ar )
2013-06-12 20:52:10 +03:00
{
struct wmi_stop_scan_arg arg = {
. req_id = 1 , /* FIXME */
. req_type = WMI_SCAN_STOP_ONE ,
. u . scan_id = ATH10K_SCAN_ID ,
} ;
int ret ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
ret = ath10k_wmi_stop_scan ( ar , & arg ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to stop wmi scan: %d \n " , ret ) ;
2014-08-05 14:54:44 +02:00
goto out ;
2013-06-12 20:52:10 +03:00
}
ret = wait_for_completion_timeout ( & ar - > scan . completed , 3 * HZ ) ;
2014-08-05 14:54:44 +02:00
if ( ret = = 0 ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to receive scan abortion completion: timed out \n " ) ;
2014-08-05 14:54:44 +02:00
ret = - ETIMEDOUT ;
} else if ( ret > 0 ) {
ret = 0 ;
}
2013-06-12 20:52:10 +03:00
2014-08-05 14:54:44 +02:00
out :
/* Scan state should be updated upon scan completion but in case
* firmware fails to deliver the event ( for whatever reason ) it is
* desired to clean up scan state anyway . Firmware may have just
* dropped the scan completion event delivery due to transport pipe
* being overflown with data and / or it can recover on its own before
* next scan request is submitted .
*/
spin_lock_bh ( & ar - > data_lock ) ;
if ( ar - > scan . state ! = ATH10K_SCAN_IDLE )
__ath10k_scan_finish ( ar ) ;
spin_unlock_bh ( & ar - > data_lock ) ;
return ret ;
}
static void ath10k_scan_abort ( struct ath10k * ar )
{
int ret ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
2013-06-12 20:52:10 +03:00
spin_lock_bh ( & ar - > data_lock ) ;
2014-08-05 14:54:44 +02:00
switch ( ar - > scan . state ) {
case ATH10K_SCAN_IDLE :
/* This can happen if timeout worker kicked in and called
* abortion while scan completion was being processed .
*/
break ;
case ATH10K_SCAN_STARTING :
case ATH10K_SCAN_ABORTING :
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " refusing scan abortion due to invalid scan state: %s (%d) \n " ,
2014-08-05 14:54:44 +02:00
ath10k_scan_state_str ( ar - > scan . state ) ,
ar - > scan . state ) ;
break ;
case ATH10K_SCAN_RUNNING :
ar - > scan . state = ATH10K_SCAN_ABORTING ;
spin_unlock_bh ( & ar - > data_lock ) ;
ret = ath10k_scan_stop ( ar ) ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to abort scan: %d \n " , ret ) ;
2014-08-05 14:54:44 +02:00
spin_lock_bh ( & ar - > data_lock ) ;
break ;
2013-06-12 20:52:10 +03:00
}
2014-08-05 14:54:44 +02:00
2013-06-12 20:52:10 +03:00
spin_unlock_bh ( & ar - > data_lock ) ;
2014-08-05 14:54:44 +02:00
}
2013-06-12 20:52:10 +03:00
2014-08-05 14:54:44 +02:00
void ath10k_scan_timeout_work ( struct work_struct * work )
{
struct ath10k * ar = container_of ( work , struct ath10k ,
scan . timeout . work ) ;
mutex_lock ( & ar - > conf_mutex ) ;
ath10k_scan_abort ( ar ) ;
mutex_unlock ( & ar - > conf_mutex ) ;
2013-06-12 20:52:10 +03:00
}
static int ath10k_start_scan ( struct ath10k * ar ,
const struct wmi_start_scan_arg * arg )
{
int ret ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
ret = ath10k_wmi_start_scan ( ar , arg ) ;
if ( ret )
return ret ;
ret = wait_for_completion_timeout ( & ar - > scan . started , 1 * HZ ) ;
if ( ret = = 0 ) {
2014-08-05 14:54:44 +02:00
ret = ath10k_scan_stop ( ar ) ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to stop scan: %d \n " , ret ) ;
2014-08-05 14:54:44 +02:00
return - ETIMEDOUT ;
2013-06-12 20:52:10 +03:00
}
2015-02-15 16:50:38 +02:00
/* If we failed to start the scan, return error code at
* this point . This is probably due to some issue in the
* firmware , but no need to wedge the driver due to that . . .
*/
spin_lock_bh ( & ar - > data_lock ) ;
if ( ar - > scan . state = = ATH10K_SCAN_IDLE ) {
spin_unlock_bh ( & ar - > data_lock ) ;
return - EINVAL ;
}
spin_unlock_bh ( & ar - > data_lock ) ;
2014-08-05 14:54:44 +02:00
/* Add a 200ms margin to account for event/command processing */
ieee80211_queue_delayed_work ( ar - > hw , & ar - > scan . timeout ,
msecs_to_jiffies ( arg - > max_scan_time + 200 ) ) ;
2013-06-12 20:52:10 +03:00
return 0 ;
}
/**********************/
/* mac80211 callbacks */
/**********************/
static void ath10k_tx ( struct ieee80211_hw * hw ,
struct ieee80211_tx_control * control ,
struct sk_buff * skb )
{
2014-07-21 21:03:09 +03:00
struct ath10k * ar = hw - > priv ;
2013-06-12 20:52:10 +03:00
struct ieee80211_tx_info * info = IEEE80211_SKB_CB ( skb ) ;
2014-07-21 21:03:09 +03:00
struct ieee80211_vif * vif = info - > control . vif ;
2013-06-12 20:52:10 +03:00
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) skb - > data ;
/* We should disable CCK RATE due to P2P */
if ( info - > flags & IEEE80211_TX_CTL_NO_CCK_RATE )
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " IEEE80211_TX_CTL_NO_CCK_RATE \n " ) ;
2013-06-12 20:52:10 +03:00
2014-07-21 21:03:09 +03:00
ATH10K_SKB_CB ( skb ) - > htt . is_offchan = false ;
ATH10K_SKB_CB ( skb ) - > htt . tid = ath10k_tx_h_get_tid ( hdr ) ;
2014-09-02 11:00:22 +03:00
ATH10K_SKB_CB ( skb ) - > vdev_id = ath10k_tx_h_get_vdev_id ( ar , vif ) ;
2013-06-12 20:52:10 +03:00
2013-07-16 11:04:54 +02:00
/* it makes no sense to process injected frames like that */
2014-07-21 21:03:09 +03:00
if ( vif & & vif - > type ! = NL80211_IFTYPE_MONITOR ) {
ath10k_tx_h_nwifi ( hw , skb ) ;
ath10k_tx_h_add_p2p_noa_ie ( ar , vif , skb ) ;
ath10k_tx_h_seq_no ( vif , skb ) ;
2013-07-16 11:04:54 +02:00
}
2013-06-12 20:52:10 +03:00
if ( info - > flags & IEEE80211_TX_CTL_TX_OFFCHAN ) {
spin_lock_bh ( & ar - > data_lock ) ;
2014-11-24 14:58:31 +01:00
ATH10K_SKB_CB ( skb ) - > htt . freq = ar - > scan . roc_freq ;
2013-09-26 17:47:12 +02:00
ATH10K_SKB_CB ( skb ) - > vdev_id = ar - > scan . vdev_id ;
2013-06-12 20:52:10 +03:00
spin_unlock_bh ( & ar - > data_lock ) ;
2014-11-24 14:58:31 +01:00
if ( ath10k_mac_need_offchan_tx_work ( ar ) ) {
ATH10K_SKB_CB ( skb ) - > htt . freq = 0 ;
ATH10K_SKB_CB ( skb ) - > htt . is_offchan = true ;
2013-06-12 20:52:10 +03:00
2014-11-24 14:58:31 +01:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " queued offchannel skb %p \n " ,
skb ) ;
skb_queue_tail ( & ar - > offchan_tx_queue , skb ) ;
ieee80211_queue_work ( hw , & ar - > offchan_tx_work ) ;
return ;
}
2013-06-12 20:52:10 +03:00
}
ath10k_tx_htt ( ar , skb ) ;
}
2014-05-26 12:46:03 +03:00
/* Must not be called with conf_mutex held as workers can use that also. */
2014-10-28 10:34:38 +01:00
void ath10k_drain_tx ( struct ath10k * ar )
2014-05-26 12:46:03 +03:00
{
/* make sure rcu-protected mac80211 tx path itself is drained */
synchronize_net ( ) ;
ath10k_offchan_tx_purge ( ar ) ;
ath10k_mgmt_over_wmi_tx_purge ( ar ) ;
cancel_work_sync ( & ar - > offchan_tx_work ) ;
cancel_work_sync ( & ar - > wmi_mgmt_tx_work ) ;
}
2013-07-16 09:54:35 +02:00
void ath10k_halt ( struct ath10k * ar )
2013-07-16 09:38:57 +02:00
{
2014-04-23 19:30:06 +03:00
struct ath10k_vif * arvif ;
2013-07-16 09:38:57 +02:00
lockdep_assert_held ( & ar - > conf_mutex ) ;
2014-08-28 12:58:16 +02:00
clear_bit ( ATH10K_CAC_RUNNING , & ar - > dev_flags ) ;
ar - > filter_flags = 0 ;
ar - > monitor = false ;
if ( ar - > monitor_started )
2014-04-08 09:45:47 +03:00
ath10k_monitor_stop ( ar ) ;
2014-08-28 12:58:16 +02:00
ar - > monitor_started = false ;
2014-04-08 09:45:47 +03:00
2014-08-05 14:54:44 +02:00
ath10k_scan_finish ( ar ) ;
2013-07-16 09:38:57 +02:00
ath10k_peer_cleanup_all ( ar ) ;
ath10k_core_stop ( ar ) ;
ath10k_hif_power_down ( ar ) ;
spin_lock_bh ( & ar - > data_lock ) ;
2014-09-18 11:18:02 +03:00
list_for_each_entry ( arvif , & ar - > arvifs , list )
ath10k_mac_vif_beacon_cleanup ( arvif ) ;
2013-07-16 09:38:57 +02:00
spin_unlock_bh ( & ar - > data_lock ) ;
}
2014-05-16 17:15:38 +03:00
static int ath10k_get_antenna ( struct ieee80211_hw * hw , u32 * tx_ant , u32 * rx_ant )
{
struct ath10k * ar = hw - > priv ;
mutex_lock ( & ar - > conf_mutex ) ;
if ( ar - > cfg_tx_chainmask ) {
* tx_ant = ar - > cfg_tx_chainmask ;
* rx_ant = ar - > cfg_rx_chainmask ;
} else {
* tx_ant = ar - > supp_tx_chainmask ;
* rx_ant = ar - > supp_rx_chainmask ;
}
mutex_unlock ( & ar - > conf_mutex ) ;
return 0 ;
}
2014-11-24 16:22:10 +02:00
static void ath10k_check_chain_mask ( struct ath10k * ar , u32 cm , const char * dbg )
{
/* It is not clear that allowing gaps in chainmask
* is helpful . Probably it will not do what user
* is hoping for , so warn in that case .
*/
if ( cm = = 15 | | cm = = 7 | | cm = = 3 | | cm = = 1 | | cm = = 0 )
return ;
ath10k_warn ( ar , " mac %s antenna chainmask may be invalid: 0x%x. Suggested values: 15, 7, 3, 1 or 0. \n " ,
dbg , cm ) ;
}
2014-05-16 17:15:38 +03:00
static int __ath10k_set_antenna ( struct ath10k * ar , u32 tx_ant , u32 rx_ant )
{
int ret ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
2014-11-24 16:22:10 +02:00
ath10k_check_chain_mask ( ar , tx_ant , " tx " ) ;
ath10k_check_chain_mask ( ar , rx_ant , " rx " ) ;
2014-05-16 17:15:38 +03:00
ar - > cfg_tx_chainmask = tx_ant ;
ar - > cfg_rx_chainmask = rx_ant ;
if ( ( ar - > state ! = ATH10K_STATE_ON ) & &
( ar - > state ! = ATH10K_STATE_RESTARTED ) )
return 0 ;
ret = ath10k_wmi_pdev_set_param ( ar , ar - > wmi . pdev_param - > tx_chain_mask ,
tx_ant ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set tx-chainmask: %d, req 0x%x \n " ,
2014-05-16 17:15:38 +03:00
ret , tx_ant ) ;
return ret ;
}
ret = ath10k_wmi_pdev_set_param ( ar , ar - > wmi . pdev_param - > rx_chain_mask ,
rx_ant ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set rx-chainmask: %d, req 0x%x \n " ,
2014-05-16 17:15:38 +03:00
ret , rx_ant ) ;
return ret ;
}
return 0 ;
}
static int ath10k_set_antenna ( struct ieee80211_hw * hw , u32 tx_ant , u32 rx_ant )
{
struct ath10k * ar = hw - > priv ;
int ret ;
mutex_lock ( & ar - > conf_mutex ) ;
ret = __ath10k_set_antenna ( ar , tx_ant , rx_ant ) ;
mutex_unlock ( & ar - > conf_mutex ) ;
return ret ;
}
2013-06-12 20:52:10 +03:00
static int ath10k_start ( struct ieee80211_hw * hw )
{
struct ath10k * ar = hw - > priv ;
2013-07-16 09:38:57 +02:00
int ret = 0 ;
2013-06-12 20:52:10 +03:00
2014-05-26 12:46:03 +03:00
/*
* This makes sense only when restarting hw . It is harmless to call
* uncoditionally . This is necessary to make sure no HTT / WMI tx
* commands will be submitted while restarting .
*/
ath10k_drain_tx ( ar ) ;
2013-07-05 16:15:15 +03:00
mutex_lock ( & ar - > conf_mutex ) ;
2014-05-26 12:46:03 +03:00
switch ( ar - > state ) {
case ATH10K_STATE_OFF :
ar - > state = ATH10K_STATE_ON ;
break ;
case ATH10K_STATE_RESTARTING :
ath10k_halt ( ar ) ;
ar - > state = ATH10K_STATE_RESTARTED ;
break ;
case ATH10K_STATE_ON :
case ATH10K_STATE_RESTARTED :
case ATH10K_STATE_WEDGED :
WARN_ON ( 1 ) ;
2013-07-16 09:38:57 +02:00
ret = - EINVAL ;
2014-05-26 12:46:02 +03:00
goto err ;
2014-09-10 18:23:30 +03:00
case ATH10K_STATE_UTF :
ret = - EBUSY ;
goto err ;
2013-07-16 09:38:57 +02:00
}
ret = ath10k_hif_power_up ( ar ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_err ( ar , " Could not init hif: %d \n " , ret ) ;
2014-05-26 12:46:02 +03:00
goto err_off ;
2013-07-16 09:38:57 +02:00
}
2014-09-10 18:23:30 +03:00
ret = ath10k_core_start ( ar , ATH10K_FIRMWARE_MODE_NORMAL ) ;
2013-07-16 09:38:57 +02:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_err ( ar , " Could not init core: %d \n " , ret ) ;
2014-05-26 12:46:02 +03:00
goto err_power_down ;
2013-07-16 09:38:57 +02:00
}
2013-09-26 17:47:16 +02:00
ret = ath10k_wmi_pdev_set_param ( ar , ar - > wmi . pdev_param - > pmf_qos , 1 ) ;
2014-05-26 12:46:02 +03:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to enable PMF QOS: %d \n " , ret ) ;
2014-05-26 12:46:02 +03:00
goto err_core_stop ;
}
2013-06-12 20:52:10 +03:00
2013-11-13 11:05:10 +01:00
ret = ath10k_wmi_pdev_set_param ( ar , ar - > wmi . pdev_param - > dynamic_bw , 1 ) ;
2014-05-26 12:46:02 +03:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to enable dynamic BW: %d \n " , ret ) ;
2014-05-26 12:46:02 +03:00
goto err_core_stop ;
}
2013-06-12 20:52:10 +03:00
2014-05-16 17:15:38 +03:00
if ( ar - > cfg_tx_chainmask )
__ath10k_set_antenna ( ar , ar - > cfg_tx_chainmask ,
ar - > cfg_rx_chainmask ) ;
2014-01-29 15:03:31 +02:00
/*
* By default FW set ARP frames ac to voice ( 6 ) . In that case ARP
* exchange is not working properly for UAPSD enabled AP . ARP requests
* which arrives with access category 0 are processed by network stack
* and send back with access category 0 , but FW changes access category
* to 6. Set ARP frames access category to best effort ( 0 ) solves
* this problem .
*/
ret = ath10k_wmi_pdev_set_param ( ar ,
ar - > wmi . pdev_param - > arp_ac_override , 0 ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set arp ac override parameter: %d \n " ,
2014-01-29 15:03:31 +02:00
ret ) ;
2014-05-26 12:46:02 +03:00
goto err_core_stop ;
2014-01-29 15:03:31 +02:00
}
2015-03-19 16:37:59 +05:30
ret = ath10k_wmi_pdev_set_param ( ar ,
ar - > wmi . pdev_param - > ani_enable , 1 ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to enable ani by default: %d \n " ,
ret ) ;
goto err_core_stop ;
}
2015-03-19 16:38:00 +05:30
ar - > ani_enabled = true ;
2014-04-08 09:56:09 +03:00
ar - > num_started_vdevs = 0 ;
2013-07-16 09:38:52 +02:00
ath10k_regd_update ( ar ) ;
2014-08-02 09:12:54 +03:00
ath10k_spectral_start ( ar ) ;
2015-03-15 20:36:22 +05:30
ath10k_thermal_set_throttling ( ar ) ;
2014-08-02 09:12:54 +03:00
2014-05-26 12:46:02 +03:00
mutex_unlock ( & ar - > conf_mutex ) ;
return 0 ;
err_core_stop :
ath10k_core_stop ( ar ) ;
err_power_down :
ath10k_hif_power_down ( ar ) ;
err_off :
ar - > state = ATH10K_STATE_OFF ;
err :
2013-07-05 16:15:15 +03:00
mutex_unlock ( & ar - > conf_mutex ) ;
2014-01-29 07:26:31 +01:00
return ret ;
2013-06-12 20:52:10 +03:00
}
static void ath10k_stop ( struct ieee80211_hw * hw )
{
struct ath10k * ar = hw - > priv ;
2014-05-26 12:46:03 +03:00
ath10k_drain_tx ( ar ) ;
2013-07-05 16:15:15 +03:00
mutex_lock ( & ar - > conf_mutex ) ;
2014-05-26 12:46:03 +03:00
if ( ar - > state ! = ATH10K_STATE_OFF ) {
2013-07-16 09:38:57 +02:00
ath10k_halt ( ar ) ;
2014-05-26 12:46:03 +03:00
ar - > state = ATH10K_STATE_OFF ;
}
2013-07-05 16:15:15 +03:00
mutex_unlock ( & ar - > conf_mutex ) ;
2014-08-05 14:54:44 +02:00
cancel_delayed_work_sync ( & ar - > scan . timeout ) ;
2013-07-16 09:54:35 +02:00
cancel_work_sync ( & ar - > restart_work ) ;
2013-06-12 20:52:10 +03:00
}
2013-10-16 15:44:46 +03:00
static int ath10k_config_ps ( struct ath10k * ar )
2013-06-12 20:52:10 +03:00
{
2013-10-16 15:44:46 +03:00
struct ath10k_vif * arvif ;
int ret = 0 ;
2013-07-16 09:54:35 +02:00
lockdep_assert_held ( & ar - > conf_mutex ) ;
2013-10-16 15:44:46 +03:00
list_for_each_entry ( arvif , & ar - > arvifs , list ) {
ret = ath10k_mac_vif_setup_ps ( arvif ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to setup powersave: %d \n " , ret ) ;
2013-10-16 15:44:46 +03:00
break ;
}
}
2013-07-16 09:54:35 +02:00
2013-10-16 15:44:46 +03:00
return ret ;
2013-07-16 09:54:35 +02:00
}
2014-01-23 11:38:25 +01:00
static const char * chandef_get_width ( enum nl80211_chan_width width )
{
switch ( width ) {
case NL80211_CHAN_WIDTH_20_NOHT :
return " 20 (noht) " ;
case NL80211_CHAN_WIDTH_20 :
return " 20 " ;
case NL80211_CHAN_WIDTH_40 :
return " 40 " ;
case NL80211_CHAN_WIDTH_80 :
return " 80 " ;
case NL80211_CHAN_WIDTH_80P80 :
return " 80+80 " ;
case NL80211_CHAN_WIDTH_160 :
return " 160 " ;
case NL80211_CHAN_WIDTH_5 :
return " 5 " ;
case NL80211_CHAN_WIDTH_10 :
return " 10 " ;
}
return " ? " ;
}
static void ath10k_config_chan ( struct ath10k * ar )
{
struct ath10k_vif * arvif ;
int ret ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC ,
2014-01-23 11:38:25 +01:00
" mac config channel to %dMHz (cf1 %dMHz cf2 %dMHz width %s) \n " ,
ar - > chandef . chan - > center_freq ,
ar - > chandef . center_freq1 ,
ar - > chandef . center_freq2 ,
chandef_get_width ( ar - > chandef . width ) ) ;
/* First stop monitor interface. Some FW versions crash if there's a
* lone monitor interface . */
2014-04-08 09:45:47 +03:00
if ( ar - > monitor_started )
2014-08-28 12:58:16 +02:00
ath10k_monitor_stop ( ar ) ;
2014-01-23 11:38:25 +01:00
list_for_each_entry ( arvif , & ar - > arvifs , list ) {
if ( ! arvif - > is_started )
continue ;
2014-07-29 12:53:36 +03:00
if ( ! arvif - > is_up )
continue ;
2014-01-23 11:38:25 +01:00
if ( arvif - > vdev_type = = WMI_VDEV_TYPE_MONITOR )
continue ;
2014-07-29 12:53:36 +03:00
ret = ath10k_wmi_vdev_down ( ar , arvif - > vdev_id ) ;
2014-01-23 11:38:25 +01:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to down vdev %d: %d \n " ,
2014-01-23 11:38:25 +01:00
arvif - > vdev_id , ret ) ;
continue ;
}
}
2014-07-29 12:53:36 +03:00
/* all vdevs are downed now - attempt to restart and re-up them */
2014-01-23 11:38:25 +01:00
list_for_each_entry ( arvif , & ar - > arvifs , list ) {
if ( ! arvif - > is_started )
continue ;
if ( arvif - > vdev_type = = WMI_VDEV_TYPE_MONITOR )
continue ;
2015-03-05 16:02:17 +02:00
ret = ath10k_mac_setup_bcn_tmpl ( arvif ) ;
if ( ret )
ath10k_warn ( ar , " failed to update bcn tmpl during csa: %d \n " ,
ret ) ;
ret = ath10k_mac_setup_prb_tmpl ( arvif ) ;
if ( ret )
ath10k_warn ( ar , " failed to update prb tmpl during csa: %d \n " ,
ret ) ;
2014-07-29 12:53:36 +03:00
ret = ath10k_vdev_restart ( arvif ) ;
2014-01-23 11:38:25 +01:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to restart vdev %d: %d \n " ,
2014-01-23 11:38:25 +01:00
arvif - > vdev_id , ret ) ;
continue ;
}
if ( ! arvif - > is_up )
continue ;
ret = ath10k_wmi_vdev_up ( arvif - > ar , arvif - > vdev_id , arvif - > aid ,
arvif - > bssid ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to bring vdev up %d: %d \n " ,
2014-01-23 11:38:25 +01:00
arvif - > vdev_id , ret ) ;
continue ;
}
}
2014-08-28 12:58:16 +02:00
ath10k_monitor_recalc ( ar ) ;
2014-01-23 11:38:25 +01:00
}
2014-10-21 10:40:15 +03:00
static int ath10k_mac_txpower_setup ( struct ath10k * ar , int txpower )
{
int ret ;
u32 param ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac txpower %d \n " , txpower ) ;
param = ar - > wmi . pdev_param - > txpower_limit2g ;
ret = ath10k_wmi_pdev_set_param ( ar , param , txpower * 2 ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to set 2g txpower %d: %d \n " ,
txpower , ret ) ;
return ret ;
}
param = ar - > wmi . pdev_param - > txpower_limit5g ;
ret = ath10k_wmi_pdev_set_param ( ar , param , txpower * 2 ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to set 5g txpower %d: %d \n " ,
txpower , ret ) ;
return ret ;
}
return 0 ;
}
static int ath10k_mac_txpower_recalc ( struct ath10k * ar )
{
struct ath10k_vif * arvif ;
int ret , txpower = - 1 ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
list_for_each_entry ( arvif , & ar - > arvifs , list ) {
WARN_ON ( arvif - > txpower < 0 ) ;
if ( txpower = = - 1 )
txpower = arvif - > txpower ;
else
txpower = min ( txpower , arvif - > txpower ) ;
}
if ( WARN_ON ( txpower = = - 1 ) )
return - EINVAL ;
ret = ath10k_mac_txpower_setup ( ar , txpower ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to setup tx power %d: %d \n " ,
txpower , ret ) ;
return ret ;
}
return 0 ;
}
2013-07-16 09:54:35 +02:00
static int ath10k_config ( struct ieee80211_hw * hw , u32 changed )
{
2013-06-12 20:52:10 +03:00
struct ath10k * ar = hw - > priv ;
struct ieee80211_conf * conf = & hw - > conf ;
int ret = 0 ;
mutex_lock ( & ar - > conf_mutex ) ;
if ( changed & IEEE80211_CONF_CHANGE_CHANNEL ) {
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC ,
2014-04-08 09:56:09 +03:00
" mac config channel %dMHz flags 0x%x radar %d \n " ,
2013-11-20 09:59:47 +02:00
conf - > chandef . chan - > center_freq ,
2014-04-08 09:56:09 +03:00
conf - > chandef . chan - > flags ,
conf - > radar_enabled ) ;
2013-11-20 09:59:47 +02:00
2013-06-12 20:52:10 +03:00
spin_lock_bh ( & ar - > data_lock ) ;
ar - > rx_channel = conf - > chandef . chan ;
spin_unlock_bh ( & ar - > data_lock ) ;
2013-11-20 09:59:47 +02:00
2014-04-08 09:56:09 +03:00
ar - > radar_enabled = conf - > radar_enabled ;
ath10k_recalc_radar_detection ( ar ) ;
2014-01-23 11:38:25 +01:00
if ( ! cfg80211_chandef_identical ( & ar - > chandef , & conf - > chandef ) ) {
ar - > chandef = conf - > chandef ;
ath10k_config_chan ( ar ) ;
}
2013-06-12 20:52:10 +03:00
}
2013-07-16 09:54:35 +02:00
if ( changed & IEEE80211_CONF_CHANGE_PS )
ath10k_config_ps ( ar ) ;
2013-06-12 20:52:10 +03:00
if ( changed & IEEE80211_CONF_CHANGE_MONITOR ) {
2014-08-28 12:58:16 +02:00
ar - > monitor = conf - > flags & IEEE80211_CONF_MONITOR ;
ret = ath10k_monitor_recalc ( ar ) ;
if ( ret )
ath10k_warn ( ar , " failed to recalc monitor: %d \n " , ret ) ;
2013-06-12 20:52:10 +03:00
}
mutex_unlock ( & ar - > conf_mutex ) ;
return ret ;
}
2014-11-24 16:22:10 +02:00
static u32 get_nss_from_chainmask ( u16 chain_mask )
{
if ( ( chain_mask & 0x15 ) = = 0x15 )
return 4 ;
else if ( ( chain_mask & 0x7 ) = = 0x7 )
return 3 ;
else if ( ( chain_mask & 0x3 ) = = 0x3 )
return 2 ;
return 1 ;
}
2013-06-12 20:52:10 +03:00
/*
* TODO :
* Figure out how to handle WMI_VDEV_SUBTYPE_P2P_DEVICE ,
* because we will send mgmt frames without CCK . This requirement
* for P2P_FIND / GO_NEG should be handled by checking CCK flag
* in the TX packet .
*/
static int ath10k_add_interface ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif )
{
struct ath10k * ar = hw - > priv ;
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
enum wmi_sta_powersave_param param ;
int ret = 0 ;
2014-01-20 11:01:46 +02:00
u32 value ;
2013-06-12 20:52:10 +03:00
int bit ;
2013-09-26 17:47:15 +02:00
u32 vdev_param ;
2013-06-12 20:52:10 +03:00
2014-11-11 12:48:42 +01:00
vif - > driver_flags | = IEEE80211_VIF_SUPPORTS_UAPSD ;
2013-06-12 20:52:10 +03:00
mutex_lock ( & ar - > conf_mutex ) ;
2013-07-31 10:55:14 +02:00
memset ( arvif , 0 , sizeof ( * arvif ) ) ;
2013-06-12 20:52:10 +03:00
arvif - > ar = ar ;
arvif - > vif = vif ;
2013-10-22 14:54:14 -07:00
INIT_LIST_HEAD ( & arvif - > list ) ;
2015-03-05 16:02:17 +02:00
INIT_WORK ( & arvif - > ap_csa_work , ath10k_mac_vif_ap_csa_work ) ;
2015-03-10 16:22:01 +02:00
INIT_DELAYED_WORK ( & arvif - > connection_loss_work ,
ath10k_mac_vif_sta_connection_loss_work ) ;
2013-10-16 15:44:45 +03:00
2014-08-12 11:02:19 +03:00
if ( ar - > free_vdev_map = = 0 ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " Free vdev map is empty, no more interfaces allowed. \n " ) ;
2013-06-12 20:52:10 +03:00
ret = - EBUSY ;
2013-10-16 15:44:45 +03:00
goto err ;
2013-06-12 20:52:10 +03:00
}
2014-09-23 14:17:16 -07:00
bit = __ffs64 ( ar - > free_vdev_map ) ;
2013-06-12 20:52:10 +03:00
2014-09-23 14:17:16 -07:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac create vdev %i map %llx \n " ,
bit , ar - > free_vdev_map ) ;
2013-06-12 20:52:10 +03:00
2014-09-23 14:17:16 -07:00
arvif - > vdev_id = bit ;
2013-06-12 20:52:10 +03:00
arvif - > vdev_subtype = WMI_VDEV_SUBTYPE_NONE ;
switch ( vif - > type ) {
2014-12-12 12:41:39 +01:00
case NL80211_IFTYPE_P2P_DEVICE :
arvif - > vdev_type = WMI_VDEV_TYPE_STA ;
arvif - > vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE ;
break ;
2013-06-12 20:52:10 +03:00
case NL80211_IFTYPE_UNSPECIFIED :
case NL80211_IFTYPE_STATION :
arvif - > vdev_type = WMI_VDEV_TYPE_STA ;
if ( vif - > p2p )
arvif - > vdev_subtype = WMI_VDEV_SUBTYPE_P2P_CLIENT ;
break ;
case NL80211_IFTYPE_ADHOC :
arvif - > vdev_type = WMI_VDEV_TYPE_IBSS ;
break ;
case NL80211_IFTYPE_AP :
arvif - > vdev_type = WMI_VDEV_TYPE_AP ;
if ( vif - > p2p )
arvif - > vdev_subtype = WMI_VDEV_SUBTYPE_P2P_GO ;
break ;
case NL80211_IFTYPE_MONITOR :
arvif - > vdev_type = WMI_VDEV_TYPE_MONITOR ;
break ;
default :
WARN_ON ( 1 ) ;
break ;
}
2014-09-18 11:18:02 +03:00
/* Some firmware revisions don't wait for beacon tx completion before
* sending another SWBA event . This could lead to hardware using old
* ( freed ) beacon data in some cases , e . g . tx credit starvation
* combined with missed TBTT . This is very very rare .
*
* On non - IOMMU - enabled hosts this could be a possible security issue
* because hw could beacon some random data on the air . On
* IOMMU - enabled hosts DMAR faults would occur in most cases and target
* device would crash .
*
* Since there are no beacon tx completions ( implicit nor explicit )
* propagated to host the only workaround for this is to allocate a
* DMA - coherent buffer for a lifetime of a vif and use it for all
* beacon tx commands . Worst case for this approach is some beacons may
* become corrupted , e . g . have garbled IEs or out - of - date TIM bitmap .
*/
if ( vif - > type = = NL80211_IFTYPE_ADHOC | |
vif - > type = = NL80211_IFTYPE_AP ) {
arvif - > beacon_buf = dma_zalloc_coherent ( ar - > dev ,
IEEE80211_MAX_FRAME_LEN ,
& arvif - > beacon_paddr ,
2014-10-10 17:38:27 +05:30
GFP_ATOMIC ) ;
2014-09-18 11:18:02 +03:00
if ( ! arvif - > beacon_buf ) {
ret = - ENOMEM ;
ath10k_warn ( ar , " failed to allocate beacon buffer: %d \n " ,
ret ) ;
goto err ;
}
}
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac vdev create %d (add interface) type %d subtype %d bcnmode %s \n " ,
arvif - > vdev_id , arvif - > vdev_type , arvif - > vdev_subtype ,
arvif - > beacon_buf ? " single-buf " : " per-skb " ) ;
2013-06-12 20:52:10 +03:00
ret = ath10k_wmi_vdev_create ( ar , arvif - > vdev_id , arvif - > vdev_type ,
arvif - > vdev_subtype , vif - > addr ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to create WMI vdev %i: %d \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2013-10-16 15:44:45 +03:00
goto err ;
2013-06-12 20:52:10 +03:00
}
2014-09-23 14:17:16 -07:00
ar - > free_vdev_map & = ~ ( 1LL < < arvif - > vdev_id ) ;
2013-10-16 15:44:45 +03:00
list_add ( & arvif - > list , & ar - > arvifs ) ;
2013-10-16 15:44:45 +03:00
2015-01-28 09:57:49 +02:00
/* It makes no sense to have firmware do keepalives. mac80211 already
* takes care of this with idle connection polling .
*/
ret = ath10k_mac_vif_disable_keepalive ( arvif ) ;
2013-10-16 15:44:45 +03:00
if ( ret ) {
2015-01-28 09:57:49 +02:00
ath10k_warn ( ar , " failed to disable keepalive on vdev %i: %d \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2013-10-16 15:44:45 +03:00
goto err_vdev_delete ;
}
2013-06-12 20:52:10 +03:00
2015-01-29 13:50:38 +02:00
arvif - > def_wep_key_idx = - 1 ;
2013-06-12 20:52:10 +03:00
2013-09-26 17:47:15 +02:00
vdev_param = ar - > wmi . vdev_param - > tx_encap_type ;
ret = ath10k_wmi_vdev_set_param ( ar , arvif - > vdev_id , vdev_param ,
2013-06-12 20:52:10 +03:00
ATH10K_HW_TXRX_NATIVE_WIFI ) ;
2013-10-15 09:26:20 +02:00
/* 10.X firmware does not support this VDEV parameter. Do not warn */
2013-10-16 15:44:45 +03:00
if ( ret & & ret ! = - EOPNOTSUPP ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set vdev %i TX encapsulation: %d \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2013-10-16 15:44:45 +03:00
goto err_vdev_delete ;
}
2013-06-12 20:52:10 +03:00
2014-11-24 16:22:10 +02:00
if ( ar - > cfg_tx_chainmask ) {
u16 nss = get_nss_from_chainmask ( ar - > cfg_tx_chainmask ) ;
vdev_param = ar - > wmi . vdev_param - > nss ;
ret = ath10k_wmi_vdev_set_param ( ar , arvif - > vdev_id , vdev_param ,
nss ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to set vdev %i chainmask 0x%x, nss %i: %d \n " ,
arvif - > vdev_id , ar - > cfg_tx_chainmask , nss ,
ret ) ;
goto err_vdev_delete ;
}
}
2013-06-12 20:52:10 +03:00
if ( arvif - > vdev_type = = WMI_VDEV_TYPE_AP ) {
ret = ath10k_peer_create ( ar , arvif - > vdev_id , vif - > addr ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to create vdev %i peer for AP: %d \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2013-10-16 15:44:45 +03:00
goto err_vdev_delete ;
2013-06-12 20:52:10 +03:00
}
2013-12-30 09:07:51 +01:00
2014-01-20 11:01:46 +02:00
ret = ath10k_mac_set_kickout ( arvif ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set vdev %i kickout parameters: %d \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2014-01-20 11:01:46 +02:00
goto err_peer_delete ;
}
2013-06-12 20:52:10 +03:00
}
if ( arvif - > vdev_type = = WMI_VDEV_TYPE_STA ) {
param = WMI_STA_PS_PARAM_RX_WAKE_POLICY ;
value = WMI_STA_PS_RX_WAKE_POLICY_WAKE ;
ret = ath10k_wmi_set_sta_ps_param ( ar , arvif - > vdev_id ,
param , value ) ;
2013-10-16 15:44:45 +03:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set vdev %i RX wake policy: %d \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2013-10-16 15:44:45 +03:00
goto err_peer_delete ;
}
2013-06-12 20:52:10 +03:00
2014-12-12 12:41:36 +01:00
ret = ath10k_mac_vif_recalc_ps_wake_threshold ( arvif ) ;
2013-10-16 15:44:45 +03:00
if ( ret ) {
2014-12-12 12:41:36 +01:00
ath10k_warn ( ar , " failed to recalc ps wake threshold on vdev %i: %d \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2013-10-16 15:44:45 +03:00
goto err_peer_delete ;
}
2013-06-12 20:52:10 +03:00
2014-12-12 12:41:36 +01:00
ret = ath10k_mac_vif_recalc_ps_poll_count ( arvif ) ;
2013-10-16 15:44:45 +03:00
if ( ret ) {
2014-12-12 12:41:36 +01:00
ath10k_warn ( ar , " failed to recalc ps poll count on vdev %i: %d \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2013-10-16 15:44:45 +03:00
goto err_peer_delete ;
}
2013-06-12 20:52:10 +03:00
}
2013-07-22 14:13:31 +02:00
ret = ath10k_mac_set_rts ( arvif , ar - > hw - > wiphy - > rts_threshold ) ;
2013-10-16 15:44:45 +03:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set rts threshold for vdev %d: %d \n " ,
2013-07-05 16:15:04 +03:00
arvif - > vdev_id , ret ) ;
2013-10-16 15:44:45 +03:00
goto err_peer_delete ;
}
2013-07-05 16:15:04 +03:00
2013-07-22 14:13:31 +02:00
ret = ath10k_mac_set_frag ( arvif , ar - > hw - > wiphy - > frag_threshold ) ;
2013-10-16 15:44:45 +03:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set frag threshold for vdev %d: %d \n " ,
2013-07-05 16:15:04 +03:00
arvif - > vdev_id , ret ) ;
2013-10-16 15:44:45 +03:00
goto err_peer_delete ;
}
2013-07-05 16:15:04 +03:00
2014-10-21 10:40:15 +03:00
arvif - > txpower = vif - > bss_conf . txpower ;
ret = ath10k_mac_txpower_recalc ( ar ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to recalc tx power: %d \n " , ret ) ;
goto err_peer_delete ;
}
2013-06-12 20:52:10 +03:00
mutex_unlock ( & ar - > conf_mutex ) ;
2013-10-16 15:44:45 +03:00
return 0 ;
err_peer_delete :
if ( arvif - > vdev_type = = WMI_VDEV_TYPE_AP )
ath10k_wmi_peer_delete ( ar , arvif - > vdev_id , vif - > addr ) ;
err_vdev_delete :
ath10k_wmi_vdev_delete ( ar , arvif - > vdev_id ) ;
2014-09-23 14:17:16 -07:00
ar - > free_vdev_map | = 1LL < < arvif - > vdev_id ;
2013-10-16 15:44:45 +03:00
list_del ( & arvif - > list ) ;
2013-10-16 15:44:45 +03:00
err :
2014-09-18 11:18:02 +03:00
if ( arvif - > beacon_buf ) {
dma_free_coherent ( ar - > dev , IEEE80211_MAX_FRAME_LEN ,
arvif - > beacon_buf , arvif - > beacon_paddr ) ;
arvif - > beacon_buf = NULL ;
}
2013-10-16 15:44:45 +03:00
mutex_unlock ( & ar - > conf_mutex ) ;
2013-06-12 20:52:10 +03:00
return ret ;
}
static void ath10k_remove_interface ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif )
{
struct ath10k * ar = hw - > priv ;
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
int ret ;
2015-03-05 16:02:17 +02:00
cancel_work_sync ( & arvif - > ap_csa_work ) ;
2015-03-10 16:22:01 +02:00
cancel_delayed_work_sync ( & arvif - > connection_loss_work ) ;
2015-03-05 16:02:17 +02:00
2014-11-25 11:47:00 +05:30
mutex_lock ( & ar - > conf_mutex ) ;
2013-09-13 14:16:56 +02:00
spin_lock_bh ( & ar - > data_lock ) ;
2014-09-18 11:18:02 +03:00
ath10k_mac_vif_beacon_cleanup ( arvif ) ;
2013-09-13 14:16:56 +02:00
spin_unlock_bh ( & ar - > data_lock ) ;
2014-08-02 09:12:54 +03:00
ret = ath10k_spectral_vif_stop ( arvif ) ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to stop spectral for vdev %i: %d \n " ,
2014-08-02 09:12:54 +03:00
arvif - > vdev_id , ret ) ;
2014-09-23 14:17:16 -07:00
ar - > free_vdev_map | = 1LL < < arvif - > vdev_id ;
2013-10-16 15:44:45 +03:00
list_del ( & arvif - > list ) ;
2013-06-12 20:52:10 +03:00
if ( arvif - > vdev_type = = WMI_VDEV_TYPE_AP ) {
2015-02-15 16:50:40 +02:00
ret = ath10k_wmi_peer_delete ( arvif - > ar , arvif - > vdev_id ,
vif - > addr ) ;
2013-06-12 20:52:10 +03:00
if ( ret )
2015-02-15 16:50:40 +02:00
ath10k_warn ( ar , " failed to submit AP self-peer removal on vdev %i: %d \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
kfree ( arvif - > u . ap . noa_data ) ;
}
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac vdev %i delete (remove interface) \n " ,
2013-09-08 17:56:07 +03:00
arvif - > vdev_id ) ;
2013-06-12 20:52:10 +03:00
ret = ath10k_wmi_vdev_delete ( ar , arvif - > vdev_id ) ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to delete WMI vdev %i: %d \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
2015-02-15 16:50:40 +02:00
/* Some firmware revisions don't notify host about self-peer removal
* until after associated vdev is deleted .
*/
if ( arvif - > vdev_type = = WMI_VDEV_TYPE_AP ) {
ret = ath10k_wait_for_peer_deleted ( ar , arvif - > vdev_id ,
vif - > addr ) ;
if ( ret )
ath10k_warn ( ar , " failed to remove AP self-peer on vdev %i: %d \n " ,
arvif - > vdev_id , ret ) ;
spin_lock_bh ( & ar - > data_lock ) ;
ar - > num_peers - - ;
spin_unlock_bh ( & ar - > data_lock ) ;
}
2013-06-12 20:52:10 +03:00
ath10k_peer_cleanup ( ar , arvif - > vdev_id ) ;
mutex_unlock ( & ar - > conf_mutex ) ;
}
/*
* FIXME : Has to be verified .
*/
# define SUPPORTED_FILTERS \
( FIF_PROMISC_IN_BSS | \
FIF_ALLMULTI | \
FIF_CONTROL | \
FIF_PSPOLL | \
FIF_OTHER_BSS | \
FIF_BCN_PRBRESP_PROMISC | \
FIF_PROBE_REQ | \
FIF_FCSFAIL )
static void ath10k_configure_filter ( struct ieee80211_hw * hw ,
unsigned int changed_flags ,
unsigned int * total_flags ,
u64 multicast )
{
struct ath10k * ar = hw - > priv ;
int ret ;
mutex_lock ( & ar - > conf_mutex ) ;
changed_flags & = SUPPORTED_FILTERS ;
* total_flags & = SUPPORTED_FILTERS ;
ar - > filter_flags = * total_flags ;
2014-08-28 12:58:16 +02:00
ret = ath10k_monitor_recalc ( ar ) ;
if ( ret )
ath10k_warn ( ar , " failed to recalc montior: %d \n " , ret ) ;
2013-06-12 20:52:10 +03:00
mutex_unlock ( & ar - > conf_mutex ) ;
}
static void ath10k_bss_info_changed ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif ,
struct ieee80211_bss_conf * info ,
u32 changed )
{
struct ath10k * ar = hw - > priv ;
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
int ret = 0 ;
2014-09-14 12:50:17 +03:00
u32 vdev_param , pdev_param , slottime , preamble ;
2013-06-12 20:52:10 +03:00
mutex_lock ( & ar - > conf_mutex ) ;
if ( changed & BSS_CHANGED_IBSS )
ath10k_control_ibss ( arvif , info , vif - > addr ) ;
if ( changed & BSS_CHANGED_BEACON_INT ) {
arvif - > beacon_interval = info - > beacon_int ;
2013-09-26 17:47:15 +02:00
vdev_param = ar - > wmi . vdev_param - > beacon_interval ;
ret = ath10k_wmi_vdev_set_param ( ar , arvif - > vdev_id , vdev_param ,
2013-06-12 20:52:10 +03:00
arvif - > beacon_interval ) ;
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC ,
2013-09-08 17:56:07 +03:00
" mac vdev %d beacon_interval %d \n " ,
arvif - > vdev_id , arvif - > beacon_interval ) ;
2013-06-12 20:52:10 +03:00
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set beacon interval for vdev %d: %i \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
}
if ( changed & BSS_CHANGED_BEACON ) {
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC ,
2013-09-08 17:56:07 +03:00
" vdev %d set beacon tx mode to staggered \n " ,
arvif - > vdev_id ) ;
2013-09-26 17:47:16 +02:00
pdev_param = ar - > wmi . pdev_param - > beacon_tx_mode ;
ret = ath10k_wmi_pdev_set_param ( ar , pdev_param ,
2013-06-12 20:52:10 +03:00
WMI_BEACON_STAGGERED_MODE ) ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set beacon mode for vdev %d: %i \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2015-01-13 16:30:12 +02:00
ret = ath10k_mac_setup_bcn_tmpl ( arvif ) ;
if ( ret )
ath10k_warn ( ar , " failed to update beacon template: %d \n " ,
ret ) ;
}
if ( changed & BSS_CHANGED_AP_PROBE_RESP ) {
ret = ath10k_mac_setup_prb_tmpl ( arvif ) ;
if ( ret )
ath10k_warn ( ar , " failed to setup probe resp template on vdev %i: %d \n " ,
arvif - > vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
}
2015-01-24 12:14:51 +02:00
if ( changed & ( BSS_CHANGED_BEACON_INFO | BSS_CHANGED_BEACON ) ) {
2013-06-12 20:52:10 +03:00
arvif - > dtim_period = info - > dtim_period ;
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC ,
2013-09-08 17:56:07 +03:00
" mac vdev %d dtim_period %d \n " ,
arvif - > vdev_id , arvif - > dtim_period ) ;
2013-09-26 17:47:15 +02:00
vdev_param = ar - > wmi . vdev_param - > dtim_period ;
ret = ath10k_wmi_vdev_set_param ( ar , arvif - > vdev_id , vdev_param ,
2013-06-12 20:52:10 +03:00
arvif - > dtim_period ) ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set dtim period for vdev %d: %i \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
}
if ( changed & BSS_CHANGED_SSID & &
vif - > type = = NL80211_IFTYPE_AP ) {
arvif - > u . ap . ssid_len = info - > ssid_len ;
if ( info - > ssid_len )
memcpy ( arvif - > u . ap . ssid , info - > ssid , info - > ssid_len ) ;
arvif - > u . ap . hidden_ssid = info - > hidden_ssid ;
}
2014-10-21 10:10:29 +03:00
if ( changed & BSS_CHANGED_BSSID & & ! is_zero_ether_addr ( info - > bssid ) )
ether_addr_copy ( arvif - > bssid , info - > bssid ) ;
2013-06-12 20:52:10 +03:00
if ( changed & BSS_CHANGED_BEACON_ENABLED )
ath10k_control_beaconing ( arvif , info ) ;
if ( changed & BSS_CHANGED_ERP_CTS_PROT ) {
2014-03-11 12:58:00 +02:00
arvif - > use_cts_prot = info - > use_cts_prot ;
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac vdev %d cts_prot %d \n " ,
2014-03-11 12:58:00 +02:00
arvif - > vdev_id , info - > use_cts_prot ) ;
2013-09-08 17:56:07 +03:00
2014-03-11 12:58:00 +02:00
ret = ath10k_recalc_rtscts_prot ( arvif ) ;
2013-06-12 20:52:10 +03:00
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to recalculate rts/cts prot for vdev %d: %d \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2015-03-02 11:21:17 +01:00
vdev_param = ar - > wmi . vdev_param - > protection_mode ;
ret = ath10k_wmi_vdev_set_param ( ar , arvif - > vdev_id , vdev_param ,
info - > use_cts_prot ? 1 : 0 ) ;
if ( ret )
ath10k_warn ( ar , " failed to set protection mode %d on vdev %i: %d \n " ,
info - > use_cts_prot , arvif - > vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
}
if ( changed & BSS_CHANGED_ERP_SLOT ) {
if ( info - > use_short_slot )
slottime = WMI_VDEV_SLOT_TIME_SHORT ; /* 9us */
else
slottime = WMI_VDEV_SLOT_TIME_LONG ; /* 20us */
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac vdev %d slot_time %d \n " ,
2013-09-08 17:56:07 +03:00
arvif - > vdev_id , slottime ) ;
2013-09-26 17:47:15 +02:00
vdev_param = ar - > wmi . vdev_param - > slot_time ;
ret = ath10k_wmi_vdev_set_param ( ar , arvif - > vdev_id , vdev_param ,
2013-06-12 20:52:10 +03:00
slottime ) ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set erp slot for vdev %d: %i \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
}
if ( changed & BSS_CHANGED_ERP_PREAMBLE ) {
if ( info - > use_short_preamble )
preamble = WMI_VDEV_PREAMBLE_SHORT ;
else
preamble = WMI_VDEV_PREAMBLE_LONG ;
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC ,
2013-09-08 17:56:07 +03:00
" mac vdev %d preamble %dn " ,
arvif - > vdev_id , preamble ) ;
2013-09-26 17:47:15 +02:00
vdev_param = ar - > wmi . vdev_param - > preamble ;
ret = ath10k_wmi_vdev_set_param ( ar , arvif - > vdev_id , vdev_param ,
2013-06-12 20:52:10 +03:00
preamble ) ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set preamble for vdev %d: %i \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
}
if ( changed & BSS_CHANGED_ASSOC ) {
2014-08-28 12:58:17 +02:00
if ( info - > assoc ) {
/* Workaround: Make sure monitor vdev is not running
* when associating to prevent some firmware revisions
* ( e . g . 10.1 and 10.2 ) from crashing .
*/
if ( ar - > monitor_started )
ath10k_monitor_stop ( ar ) ;
2013-06-12 20:52:10 +03:00
ath10k_bss_assoc ( hw , vif , info ) ;
2014-08-28 12:58:17 +02:00
ath10k_monitor_recalc ( ar ) ;
2014-10-21 10:10:29 +03:00
} else {
ath10k_bss_disassoc ( hw , vif ) ;
2014-08-28 12:58:17 +02:00
}
2013-06-12 20:52:10 +03:00
}
2014-10-21 10:40:15 +03:00
if ( changed & BSS_CHANGED_TXPOWER ) {
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac vdev_id %i txpower %d \n " ,
arvif - > vdev_id , info - > txpower ) ;
arvif - > txpower = info - > txpower ;
ret = ath10k_mac_txpower_recalc ( ar ) ;
if ( ret )
ath10k_warn ( ar , " failed to recalc tx power: %d \n " , ret ) ;
}
2014-12-12 12:41:38 +01:00
if ( changed & BSS_CHANGED_PS ) {
2015-02-13 13:30:16 +01:00
arvif - > ps = vif - > bss_conf . ps ;
ret = ath10k_config_ps ( ar ) ;
2014-12-12 12:41:38 +01:00
if ( ret )
ath10k_warn ( ar , " failed to setup ps on vdev %i: %d \n " ,
arvif - > vdev_id , ret ) ;
}
2013-06-12 20:52:10 +03:00
mutex_unlock ( & ar - > conf_mutex ) ;
}
static int ath10k_hw_scan ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif ,
2014-02-05 15:21:13 +02:00
struct ieee80211_scan_request * hw_req )
2013-06-12 20:52:10 +03:00
{
struct ath10k * ar = hw - > priv ;
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
2014-02-05 15:21:13 +02:00
struct cfg80211_scan_request * req = & hw_req - > req ;
2013-06-12 20:52:10 +03:00
struct wmi_start_scan_arg arg ;
int ret = 0 ;
int i ;
mutex_lock ( & ar - > conf_mutex ) ;
spin_lock_bh ( & ar - > data_lock ) ;
2014-08-05 14:54:44 +02:00
switch ( ar - > scan . state ) {
case ATH10K_SCAN_IDLE :
reinit_completion ( & ar - > scan . started ) ;
reinit_completion ( & ar - > scan . completed ) ;
ar - > scan . state = ATH10K_SCAN_STARTING ;
ar - > scan . is_roc = false ;
ar - > scan . vdev_id = arvif - > vdev_id ;
ret = 0 ;
break ;
case ATH10K_SCAN_STARTING :
case ATH10K_SCAN_RUNNING :
case ATH10K_SCAN_ABORTING :
2013-06-12 20:52:10 +03:00
ret = - EBUSY ;
2014-08-05 14:54:44 +02:00
break ;
2013-06-12 20:52:10 +03:00
}
spin_unlock_bh ( & ar - > data_lock ) ;
2014-08-05 14:54:44 +02:00
if ( ret )
goto exit ;
2013-06-12 20:52:10 +03:00
memset ( & arg , 0 , sizeof ( arg ) ) ;
ath10k_wmi_start_scan_init ( ar , & arg ) ;
arg . vdev_id = arvif - > vdev_id ;
arg . scan_id = ATH10K_SCAN_ID ;
if ( ! req - > no_cck )
arg . scan_ctrl_flags | = WMI_SCAN_ADD_CCK_RATES ;
if ( req - > ie_len ) {
arg . ie_len = req - > ie_len ;
memcpy ( arg . ie , req - > ie , arg . ie_len ) ;
}
if ( req - > n_ssids ) {
arg . n_ssids = req - > n_ssids ;
for ( i = 0 ; i < arg . n_ssids ; i + + ) {
arg . ssids [ i ] . len = req - > ssids [ i ] . ssid_len ;
arg . ssids [ i ] . ssid = req - > ssids [ i ] . ssid ;
}
2013-07-31 10:55:12 +02:00
} else {
arg . scan_ctrl_flags | = WMI_SCAN_FLAG_PASSIVE ;
2013-06-12 20:52:10 +03:00
}
if ( req - > n_channels ) {
arg . n_channels = req - > n_channels ;
for ( i = 0 ; i < arg . n_channels ; i + + )
arg . channels [ i ] = req - > channels [ i ] - > center_freq ;
}
ret = ath10k_start_scan ( ar , & arg ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to start hw scan: %d \n " , ret ) ;
2013-06-12 20:52:10 +03:00
spin_lock_bh ( & ar - > data_lock ) ;
2014-08-05 14:54:44 +02:00
ar - > scan . state = ATH10K_SCAN_IDLE ;
2013-06-12 20:52:10 +03:00
spin_unlock_bh ( & ar - > data_lock ) ;
}
exit :
mutex_unlock ( & ar - > conf_mutex ) ;
return ret ;
}
static void ath10k_cancel_hw_scan ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif )
{
struct ath10k * ar = hw - > priv ;
mutex_lock ( & ar - > conf_mutex ) ;
2014-08-05 14:54:44 +02:00
ath10k_scan_abort ( ar ) ;
2013-06-12 20:52:10 +03:00
mutex_unlock ( & ar - > conf_mutex ) ;
2014-10-28 10:23:09 +01:00
cancel_delayed_work_sync ( & ar - > scan . timeout ) ;
2013-06-12 20:52:10 +03:00
}
2013-12-02 09:06:36 +01:00
static void ath10k_set_key_h_def_keyidx ( struct ath10k * ar ,
struct ath10k_vif * arvif ,
enum set_key_cmd cmd ,
struct ieee80211_key_conf * key )
{
u32 vdev_param = arvif - > ar - > wmi . vdev_param - > def_keyid ;
int ret ;
/* 10.1 firmware branch requires default key index to be set to group
* key index after installing it . Otherwise FW / HW Txes corrupted
* frames with multi - vif APs . This is not required for main firmware
* branch ( e . g . 636 ) .
*
* FIXME : This has been tested only in AP . It remains unknown if this
* is required for multi - vif STA interfaces on 10.1 */
if ( arvif - > vdev_type ! = WMI_VDEV_TYPE_AP )
return ;
if ( key - > cipher = = WLAN_CIPHER_SUITE_WEP40 )
return ;
if ( key - > cipher = = WLAN_CIPHER_SUITE_WEP104 )
return ;
if ( key - > flags & IEEE80211_KEY_FLAG_PAIRWISE )
return ;
if ( cmd ! = SET_KEY )
return ;
ret = ath10k_wmi_vdev_set_param ( ar , arvif - > vdev_id , vdev_param ,
key - > keyidx ) ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set vdev %i group key as default key: %d \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , ret ) ;
2013-12-02 09:06:36 +01:00
}
2013-06-12 20:52:10 +03:00
static int ath10k_set_key ( struct ieee80211_hw * hw , enum set_key_cmd cmd ,
struct ieee80211_vif * vif , struct ieee80211_sta * sta ,
struct ieee80211_key_conf * key )
{
struct ath10k * ar = hw - > priv ;
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
struct ath10k_peer * peer ;
const u8 * peer_addr ;
bool is_wep = key - > cipher = = WLAN_CIPHER_SUITE_WEP40 | |
key - > cipher = = WLAN_CIPHER_SUITE_WEP104 ;
int ret = 0 ;
2015-02-18 14:02:26 +01:00
u32 flags = 0 ;
2013-06-12 20:52:10 +03:00
2015-03-10 14:32:19 +01:00
/* this one needs to be done in software */
if ( key - > cipher = = WLAN_CIPHER_SUITE_AES_CMAC )
return 1 ;
2013-06-12 20:52:10 +03:00
if ( key - > keyidx > WMI_MAX_KEY_INDEX )
return - ENOSPC ;
mutex_lock ( & ar - > conf_mutex ) ;
if ( sta )
peer_addr = sta - > addr ;
else if ( arvif - > vdev_type = = WMI_VDEV_TYPE_STA )
peer_addr = vif - > bss_conf . bssid ;
else
peer_addr = vif - > addr ;
key - > hw_key_idx = key - > keyidx ;
/* the peer should not disappear in mid-way (unless FW goes awry) since
* we already hold conf_mutex . we just make sure its there now . */
spin_lock_bh ( & ar - > data_lock ) ;
peer = ath10k_peer_find ( ar , arvif - > vdev_id , peer_addr ) ;
spin_unlock_bh ( & ar - > data_lock ) ;
if ( ! peer ) {
if ( cmd = = SET_KEY ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to install key for non-existent peer %pM \n " ,
2013-06-12 20:52:10 +03:00
peer_addr ) ;
ret = - EOPNOTSUPP ;
goto exit ;
} else {
/* if the peer doesn't exist there is no key to disable
* anymore */
goto exit ;
}
}
2015-03-09 14:24:17 +01:00
if ( key - > flags & IEEE80211_KEY_FLAG_PAIRWISE )
flags | = WMI_KEY_PAIRWISE ;
else
flags | = WMI_KEY_GROUP ;
2013-06-12 20:52:10 +03:00
if ( is_wep ) {
if ( cmd = = SET_KEY )
arvif - > wep_keys [ key - > keyidx ] = key ;
else
arvif - > wep_keys [ key - > keyidx ] = NULL ;
if ( cmd = = DISABLE_KEY )
ath10k_clear_vdev_key ( arvif , key ) ;
2015-02-18 14:02:26 +01:00
2015-02-18 14:02:27 +01:00
/* When WEP keys are uploaded it's possible that there are
* stations associated already ( e . g . when merging ) without any
* keys . Static WEP needs an explicit per - peer key upload .
*/
if ( vif - > type = = NL80211_IFTYPE_ADHOC & &
cmd = = SET_KEY )
ath10k_mac_vif_update_wep_key ( arvif , key ) ;
2015-02-18 14:02:26 +01:00
/* 802.1x never sets the def_wep_key_idx so each set_key()
* call changes default tx key .
*
* Static WEP sets def_wep_key_idx via . set_default_unicast_key
* after first set_key ( ) .
*/
if ( cmd = = SET_KEY & & arvif - > def_wep_key_idx = = - 1 )
flags | = WMI_KEY_TX_USAGE ;
2013-06-12 20:52:10 +03:00
2015-03-09 14:24:17 +01:00
/* mac80211 uploads static WEP keys as groupwise while fw/hw
* requires pairwise keys for non - self peers , i . e . BSSID in STA
* mode and associated stations in AP / IBSS .
*
* Static WEP keys for peer_addr = vif - > addr and 802.1 X WEP keys
* work fine when mapped directly from mac80211 .
*
* Note : When installing first static WEP groupwise key ( which
* should be pairwise ) def_wep_key_idx isn ' t known yet ( it ' s
* equal to - 1 ) . Since . set_default_unicast_key is called only
* for static WEP it ' s used to re - upload the key as pairwise .
*/
if ( arvif - > def_wep_key_idx > = 0 & &
memcmp ( peer_addr , arvif - > vif - > addr , ETH_ALEN ) ) {
flags & = ~ WMI_KEY_GROUP ;
flags | = WMI_KEY_PAIRWISE ;
}
2015-02-18 14:02:26 +01:00
}
2015-01-29 13:50:38 +02:00
2015-02-18 14:02:26 +01:00
ret = ath10k_install_key ( arvif , key , cmd , peer_addr , flags ) ;
2013-06-12 20:52:10 +03:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to install key for vdev %i peer %pM: %d \n " ,
2014-02-27 18:50:00 +02:00
arvif - > vdev_id , peer_addr , ret ) ;
2013-06-12 20:52:10 +03:00
goto exit ;
}
2013-12-02 09:06:36 +01:00
ath10k_set_key_h_def_keyidx ( ar , arvif , cmd , key ) ;
2013-06-12 20:52:10 +03:00
spin_lock_bh ( & ar - > data_lock ) ;
peer = ath10k_peer_find ( ar , arvif - > vdev_id , peer_addr ) ;
if ( peer & & cmd = = SET_KEY )
peer - > keys [ key - > keyidx ] = key ;
else if ( peer & & cmd = = DISABLE_KEY )
peer - > keys [ key - > keyidx ] = NULL ;
else if ( peer = = NULL )
/* impossible unless FW goes crazy */
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " Peer %pM disappeared! \n " , peer_addr ) ;
2013-06-12 20:52:10 +03:00
spin_unlock_bh ( & ar - > data_lock ) ;
exit :
mutex_unlock ( & ar - > conf_mutex ) ;
return ret ;
}
2015-01-29 13:50:38 +02:00
static void ath10k_set_default_unicast_key ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif ,
int keyidx )
{
struct ath10k * ar = hw - > priv ;
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
int ret ;
mutex_lock ( & arvif - > ar - > conf_mutex ) ;
if ( arvif - > ar - > state ! = ATH10K_STATE_ON )
goto unlock ;
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac vdev %d set keyidx %d \n " ,
arvif - > vdev_id , keyidx ) ;
ret = ath10k_wmi_vdev_set_param ( arvif - > ar ,
arvif - > vdev_id ,
arvif - > ar - > wmi . vdev_param - > def_keyid ,
keyidx ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to update wep key index for vdev %d: %d \n " ,
arvif - > vdev_id ,
ret ) ;
goto unlock ;
}
arvif - > def_wep_key_idx = keyidx ;
2015-02-18 14:02:26 +01:00
ret = ath10k_mac_vif_sta_fix_wep_key ( arvif ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to fix sta wep key on vdev %i: %d \n " ,
arvif - > vdev_id , ret ) ;
goto unlock ;
}
2015-01-29 13:50:38 +02:00
unlock :
mutex_unlock ( & arvif - > ar - > conf_mutex ) ;
}
2014-02-14 14:49:48 +01:00
static void ath10k_sta_rc_update_wk ( struct work_struct * wk )
{
struct ath10k * ar ;
struct ath10k_vif * arvif ;
struct ath10k_sta * arsta ;
struct ieee80211_sta * sta ;
u32 changed , bw , nss , smps ;
int err ;
arsta = container_of ( wk , struct ath10k_sta , update_wk ) ;
sta = container_of ( ( void * ) arsta , struct ieee80211_sta , drv_priv ) ;
arvif = arsta - > arvif ;
ar = arvif - > ar ;
spin_lock_bh ( & ar - > data_lock ) ;
changed = arsta - > changed ;
arsta - > changed = 0 ;
bw = arsta - > bw ;
nss = arsta - > nss ;
smps = arsta - > smps ;
spin_unlock_bh ( & ar - > data_lock ) ;
mutex_lock ( & ar - > conf_mutex ) ;
if ( changed & IEEE80211_RC_BW_CHANGED ) {
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac update sta %pM peer bw %d \n " ,
2014-02-14 14:49:48 +01:00
sta - > addr , bw ) ;
err = ath10k_wmi_peer_set_param ( ar , arvif - > vdev_id , sta - > addr ,
WMI_PEER_CHAN_WIDTH , bw ) ;
if ( err )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to update STA %pM peer bw %d: %d \n " ,
2014-02-14 14:49:48 +01:00
sta - > addr , bw , err ) ;
}
if ( changed & IEEE80211_RC_NSS_CHANGED ) {
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac update sta %pM nss %d \n " ,
2014-02-14 14:49:48 +01:00
sta - > addr , nss ) ;
err = ath10k_wmi_peer_set_param ( ar , arvif - > vdev_id , sta - > addr ,
WMI_PEER_NSS , nss ) ;
if ( err )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to update STA %pM nss %d: %d \n " ,
2014-02-14 14:49:48 +01:00
sta - > addr , nss , err ) ;
}
if ( changed & IEEE80211_RC_SMPS_CHANGED ) {
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac update sta %pM smps %d \n " ,
2014-02-14 14:49:48 +01:00
sta - > addr , smps ) ;
err = ath10k_wmi_peer_set_param ( ar , arvif - > vdev_id , sta - > addr ,
WMI_PEER_SMPS_STATE , smps ) ;
if ( err )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to update STA %pM smps %d: %d \n " ,
2014-02-14 14:49:48 +01:00
sta - > addr , smps , err ) ;
}
2014-12-17 12:30:02 +02:00
if ( changed & IEEE80211_RC_SUPP_RATES_CHANGED | |
changed & IEEE80211_RC_NSS_CHANGED ) {
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac update sta %pM supp rates/nss \n " ,
2014-03-07 10:19:30 +02:00
sta - > addr ) ;
2014-10-21 10:10:29 +03:00
err = ath10k_station_assoc ( ar , arvif - > vif , sta , true ) ;
2014-03-07 10:19:30 +02:00
if ( err )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to reassociate station: %pM \n " ,
2014-03-07 10:19:30 +02:00
sta - > addr ) ;
}
2014-02-14 14:49:48 +01:00
mutex_unlock ( & ar - > conf_mutex ) ;
}
2014-11-25 15:16:05 +01:00
static int ath10k_mac_inc_num_stations ( struct ath10k_vif * arvif )
{
struct ath10k * ar = arvif - > ar ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
if ( arvif - > vdev_type ! = WMI_VDEV_TYPE_AP & &
arvif - > vdev_type ! = WMI_VDEV_TYPE_IBSS )
return 0 ;
if ( ar - > num_stations > = ar - > max_num_stations )
return - ENOBUFS ;
ar - > num_stations + + ;
return 0 ;
}
static void ath10k_mac_dec_num_stations ( struct ath10k_vif * arvif )
{
struct ath10k * ar = arvif - > ar ;
lockdep_assert_held ( & ar - > conf_mutex ) ;
if ( arvif - > vdev_type ! = WMI_VDEV_TYPE_AP & &
arvif - > vdev_type ! = WMI_VDEV_TYPE_IBSS )
return ;
ar - > num_stations - - ;
}
2013-06-12 20:52:10 +03:00
static int ath10k_sta_state ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif ,
struct ieee80211_sta * sta ,
enum ieee80211_sta_state old_state ,
enum ieee80211_sta_state new_state )
{
struct ath10k * ar = hw - > priv ;
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
2014-02-14 14:49:48 +01:00
struct ath10k_sta * arsta = ( struct ath10k_sta * ) sta - > drv_priv ;
2013-06-12 20:52:10 +03:00
int ret = 0 ;
2014-02-25 09:29:57 +02:00
if ( old_state = = IEEE80211_STA_NOTEXIST & &
new_state = = IEEE80211_STA_NONE ) {
memset ( arsta , 0 , sizeof ( * arsta ) ) ;
arsta - > arvif = arvif ;
INIT_WORK ( & arsta - > update_wk , ath10k_sta_rc_update_wk ) ;
}
2014-02-14 14:49:48 +01:00
/* cancel must be done outside the mutex to avoid deadlock */
if ( ( old_state = = IEEE80211_STA_NONE & &
new_state = = IEEE80211_STA_NOTEXIST ) )
cancel_work_sync ( & arsta - > update_wk ) ;
2013-06-12 20:52:10 +03:00
mutex_lock ( & ar - > conf_mutex ) ;
if ( old_state = = IEEE80211_STA_NOTEXIST & &
2014-10-21 10:10:29 +03:00
new_state = = IEEE80211_STA_NONE ) {
2013-06-12 20:52:10 +03:00
/*
* New station addition .
*/
2014-11-25 15:16:05 +01:00
ath10k_dbg ( ar , ATH10K_DBG_MAC ,
" mac vdev %d peer create %pM (new sta) sta %d / %d peer %d / %d \n " ,
arvif - > vdev_id , sta - > addr ,
ar - > num_stations + 1 , ar - > max_num_stations ,
ar - > num_peers + 1 , ar - > max_num_peers ) ;
2014-01-02 14:38:33 +01:00
2014-11-25 15:16:05 +01:00
ret = ath10k_mac_inc_num_stations ( arvif ) ;
if ( ret ) {
ath10k_warn ( ar , " refusing to associate station: too many connected already (%d) \n " ,
ar - > max_num_stations ) ;
2014-01-02 14:38:33 +01:00
goto exit ;
}
2013-06-12 20:52:10 +03:00
ret = ath10k_peer_create ( ar , arvif - > vdev_id , sta - > addr ) ;
2014-11-25 15:16:03 +01:00
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to add peer %pM for vdev %d when adding a new sta: %i \n " ,
2013-11-04 09:19:34 -08:00
sta - > addr , arvif - > vdev_id , ret ) ;
2014-11-25 15:16:05 +01:00
ath10k_mac_dec_num_stations ( arvif ) ;
2014-11-25 15:16:03 +01:00
goto exit ;
}
2014-10-21 10:10:29 +03:00
if ( vif - > type = = NL80211_IFTYPE_STATION ) {
WARN_ON ( arvif - > is_started ) ;
ret = ath10k_vdev_start ( arvif ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to start vdev %i: %d \n " ,
arvif - > vdev_id , ret ) ;
WARN_ON ( ath10k_peer_delete ( ar , arvif - > vdev_id ,
sta - > addr ) ) ;
2014-11-25 15:16:05 +01:00
ath10k_mac_dec_num_stations ( arvif ) ;
2014-10-21 10:10:29 +03:00
goto exit ;
}
arvif - > is_started = true ;
}
2013-06-12 20:52:10 +03:00
} else if ( ( old_state = = IEEE80211_STA_NONE & &
new_state = = IEEE80211_STA_NOTEXIST ) ) {
/*
* Existing station deletion .
*/
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC ,
2013-09-08 17:56:07 +03:00
" mac vdev %d peer delete %pM (sta gone) \n " ,
arvif - > vdev_id , sta - > addr ) ;
2014-10-21 10:10:29 +03:00
if ( vif - > type = = NL80211_IFTYPE_STATION ) {
WARN_ON ( ! arvif - > is_started ) ;
ret = ath10k_vdev_stop ( arvif ) ;
if ( ret )
ath10k_warn ( ar , " failed to stop vdev %i: %d \n " ,
arvif - > vdev_id , ret ) ;
arvif - > is_started = false ;
}
2013-06-12 20:52:10 +03:00
ret = ath10k_peer_delete ( ar , arvif - > vdev_id , sta - > addr ) ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to delete peer %pM for vdev %d: %i \n " ,
2014-02-27 18:50:00 +02:00
sta - > addr , arvif - > vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
2014-11-25 15:16:05 +01:00
ath10k_mac_dec_num_stations ( arvif ) ;
2013-06-12 20:52:10 +03:00
} else if ( old_state = = IEEE80211_STA_AUTH & &
new_state = = IEEE80211_STA_ASSOC & &
( vif - > type = = NL80211_IFTYPE_AP | |
vif - > type = = NL80211_IFTYPE_ADHOC ) ) {
/*
* New association .
*/
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac sta %pM associated \n " ,
2013-09-08 17:56:07 +03:00
sta - > addr ) ;
2014-10-21 10:10:29 +03:00
ret = ath10k_station_assoc ( ar , vif , sta , false ) ;
2013-06-12 20:52:10 +03:00
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to associate station %pM for vdev %i: %i \n " ,
2014-02-27 18:50:00 +02:00
sta - > addr , arvif - > vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
} else if ( old_state = = IEEE80211_STA_ASSOC & &
new_state = = IEEE80211_STA_AUTH & &
( vif - > type = = NL80211_IFTYPE_AP | |
vif - > type = = NL80211_IFTYPE_ADHOC ) ) {
/*
* Disassociation .
*/
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac sta %pM disassociated \n " ,
2013-09-08 17:56:07 +03:00
sta - > addr ) ;
2014-10-21 10:10:29 +03:00
ret = ath10k_station_disassoc ( ar , vif , sta ) ;
2013-06-12 20:52:10 +03:00
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to disassociate station: %pM vdev %i: %i \n " ,
2014-02-27 18:50:00 +02:00
sta - > addr , arvif - > vdev_id , ret ) ;
2013-06-12 20:52:10 +03:00
}
2014-01-02 14:38:33 +01:00
exit :
2013-06-12 20:52:10 +03:00
mutex_unlock ( & ar - > conf_mutex ) ;
return ret ;
}
static int ath10k_conf_tx_uapsd ( struct ath10k * ar , struct ieee80211_vif * vif ,
2014-09-14 12:50:06 +03:00
u16 ac , bool enable )
2013-06-12 20:52:10 +03:00
{
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
2015-01-24 12:14:52 +02:00
struct wmi_sta_uapsd_auto_trig_arg arg = { } ;
u32 prio = 0 , acc = 0 ;
2013-06-12 20:52:10 +03:00
u32 value = 0 ;
int ret = 0 ;
2013-07-05 16:15:15 +03:00
lockdep_assert_held ( & ar - > conf_mutex ) ;
2013-06-12 20:52:10 +03:00
if ( arvif - > vdev_type ! = WMI_VDEV_TYPE_STA )
return 0 ;
switch ( ac ) {
case IEEE80211_AC_VO :
value = WMI_STA_PS_UAPSD_AC3_DELIVERY_EN |
WMI_STA_PS_UAPSD_AC3_TRIGGER_EN ;
2015-01-24 12:14:52 +02:00
prio = 7 ;
acc = 3 ;
2013-06-12 20:52:10 +03:00
break ;
case IEEE80211_AC_VI :
value = WMI_STA_PS_UAPSD_AC2_DELIVERY_EN |
WMI_STA_PS_UAPSD_AC2_TRIGGER_EN ;
2015-01-24 12:14:52 +02:00
prio = 5 ;
acc = 2 ;
2013-06-12 20:52:10 +03:00
break ;
case IEEE80211_AC_BE :
value = WMI_STA_PS_UAPSD_AC1_DELIVERY_EN |
WMI_STA_PS_UAPSD_AC1_TRIGGER_EN ;
2015-01-24 12:14:52 +02:00
prio = 2 ;
acc = 1 ;
2013-06-12 20:52:10 +03:00
break ;
case IEEE80211_AC_BK :
value = WMI_STA_PS_UAPSD_AC0_DELIVERY_EN |
WMI_STA_PS_UAPSD_AC0_TRIGGER_EN ;
2015-01-24 12:14:52 +02:00
prio = 0 ;
acc = 0 ;
2013-06-12 20:52:10 +03:00
break ;
}
if ( enable )
arvif - > u . sta . uapsd | = value ;
else
arvif - > u . sta . uapsd & = ~ value ;
ret = ath10k_wmi_set_sta_ps_param ( ar , arvif - > vdev_id ,
WMI_STA_PS_PARAM_UAPSD ,
arvif - > u . sta . uapsd ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set uapsd params: %d \n " , ret ) ;
2013-06-12 20:52:10 +03:00
goto exit ;
}
if ( arvif - > u . sta . uapsd )
value = WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD ;
else
value = WMI_STA_PS_RX_WAKE_POLICY_WAKE ;
ret = ath10k_wmi_set_sta_ps_param ( ar , arvif - > vdev_id ,
WMI_STA_PS_PARAM_RX_WAKE_POLICY ,
value ) ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set rx wake param: %d \n " , ret ) ;
2013-06-12 20:52:10 +03:00
2014-12-12 12:41:36 +01:00
ret = ath10k_mac_vif_recalc_ps_wake_threshold ( arvif ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to recalc ps wake threshold on vdev %i: %d \n " ,
arvif - > vdev_id , ret ) ;
return ret ;
}
ret = ath10k_mac_vif_recalc_ps_poll_count ( arvif ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to recalc ps poll count on vdev %i: %d \n " ,
arvif - > vdev_id , ret ) ;
return ret ;
}
2015-01-24 12:14:52 +02:00
if ( test_bit ( WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG , ar - > wmi . svc_map ) | |
test_bit ( WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG , ar - > wmi . svc_map ) ) {
/* Only userspace can make an educated decision when to send
* trigger frame . The following effectively disables u - UAPSD
* autotrigger in firmware ( which is enabled by default
* provided the autotrigger service is available ) .
*/
arg . wmm_ac = acc ;
arg . user_priority = prio ;
arg . service_interval = 0 ;
arg . suspend_interval = WMI_STA_UAPSD_MAX_INTERVAL_MSEC ;
arg . delay_interval = WMI_STA_UAPSD_MAX_INTERVAL_MSEC ;
ret = ath10k_wmi_vdev_sta_uapsd ( ar , arvif - > vdev_id ,
arvif - > bssid , & arg , 1 ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to set uapsd auto trigger %d \n " ,
ret ) ;
return ret ;
}
}
2013-06-12 20:52:10 +03:00
exit :
return ret ;
}
static int ath10k_conf_tx ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif , u16 ac ,
const struct ieee80211_tx_queue_params * params )
{
struct ath10k * ar = hw - > priv ;
2015-01-19 09:53:41 +01:00
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
2013-06-12 20:52:10 +03:00
struct wmi_wmm_params_arg * p = NULL ;
int ret ;
mutex_lock ( & ar - > conf_mutex ) ;
switch ( ac ) {
case IEEE80211_AC_VO :
2015-01-19 09:53:41 +01:00
p = & arvif - > wmm_params . ac_vo ;
2013-06-12 20:52:10 +03:00
break ;
case IEEE80211_AC_VI :
2015-01-19 09:53:41 +01:00
p = & arvif - > wmm_params . ac_vi ;
2013-06-12 20:52:10 +03:00
break ;
case IEEE80211_AC_BE :
2015-01-19 09:53:41 +01:00
p = & arvif - > wmm_params . ac_be ;
2013-06-12 20:52:10 +03:00
break ;
case IEEE80211_AC_BK :
2015-01-19 09:53:41 +01:00
p = & arvif - > wmm_params . ac_bk ;
2013-06-12 20:52:10 +03:00
break ;
}
if ( WARN_ON ( ! p ) ) {
ret = - EINVAL ;
goto exit ;
}
p - > cwmin = params - > cw_min ;
p - > cwmax = params - > cw_max ;
p - > aifs = params - > aifs ;
/*
* The channel time duration programmed in the HW is in absolute
* microseconds , while mac80211 gives the txop in units of
* 32 microseconds .
*/
p - > txop = params - > txop * 32 ;
2015-01-28 09:57:28 +02:00
if ( ar - > wmi . ops - > gen_vdev_wmm_conf ) {
ret = ath10k_wmi_vdev_wmm_conf ( ar , arvif - > vdev_id ,
& arvif - > wmm_params ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to set vdev wmm params on vdev %i: %d \n " ,
arvif - > vdev_id , ret ) ;
goto exit ;
}
} else {
/* This won't work well with multi-interface cases but it's
* better than nothing .
*/
ret = ath10k_wmi_pdev_set_wmm_params ( ar , & arvif - > wmm_params ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to set wmm params: %d \n " , ret ) ;
goto exit ;
}
2013-06-12 20:52:10 +03:00
}
ret = ath10k_conf_tx_uapsd ( ar , vif , ac , params - > uapsd ) ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set sta uapsd: %d \n " , ret ) ;
2013-06-12 20:52:10 +03:00
exit :
mutex_unlock ( & ar - > conf_mutex ) ;
return ret ;
}
# define ATH10K_ROC_TIMEOUT_HZ (2*HZ)
static int ath10k_remain_on_channel ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif ,
struct ieee80211_channel * chan ,
int duration ,
enum ieee80211_roc_type type )
{
struct ath10k * ar = hw - > priv ;
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
struct wmi_start_scan_arg arg ;
2014-08-05 14:54:44 +02:00
int ret = 0 ;
2013-06-12 20:52:10 +03:00
mutex_lock ( & ar - > conf_mutex ) ;
spin_lock_bh ( & ar - > data_lock ) ;
2014-08-05 14:54:44 +02:00
switch ( ar - > scan . state ) {
case ATH10K_SCAN_IDLE :
reinit_completion ( & ar - > scan . started ) ;
reinit_completion ( & ar - > scan . completed ) ;
reinit_completion ( & ar - > scan . on_channel ) ;
ar - > scan . state = ATH10K_SCAN_STARTING ;
ar - > scan . is_roc = true ;
ar - > scan . vdev_id = arvif - > vdev_id ;
ar - > scan . roc_freq = chan - > center_freq ;
ret = 0 ;
break ;
case ATH10K_SCAN_STARTING :
case ATH10K_SCAN_RUNNING :
case ATH10K_SCAN_ABORTING :
2013-06-12 20:52:10 +03:00
ret = - EBUSY ;
2014-08-05 14:54:44 +02:00
break ;
2013-06-12 20:52:10 +03:00
}
spin_unlock_bh ( & ar - > data_lock ) ;
2014-08-05 14:54:44 +02:00
if ( ret )
goto exit ;
2014-11-24 14:58:32 +01:00
duration = max ( duration , WMI_SCAN_CHAN_MIN_TIME_MSEC ) ;
2013-06-12 20:52:10 +03:00
memset ( & arg , 0 , sizeof ( arg ) ) ;
ath10k_wmi_start_scan_init ( ar , & arg ) ;
arg . vdev_id = arvif - > vdev_id ;
arg . scan_id = ATH10K_SCAN_ID ;
arg . n_channels = 1 ;
arg . channels [ 0 ] = chan - > center_freq ;
arg . dwell_time_active = duration ;
arg . dwell_time_passive = duration ;
arg . max_scan_time = 2 * duration ;
arg . scan_ctrl_flags | = WMI_SCAN_FLAG_PASSIVE ;
arg . scan_ctrl_flags | = WMI_SCAN_FILTER_PROBE_REQ ;
ret = ath10k_start_scan ( ar , & arg ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to start roc scan: %d \n " , ret ) ;
2013-06-12 20:52:10 +03:00
spin_lock_bh ( & ar - > data_lock ) ;
2014-08-05 14:54:44 +02:00
ar - > scan . state = ATH10K_SCAN_IDLE ;
2013-06-12 20:52:10 +03:00
spin_unlock_bh ( & ar - > data_lock ) ;
goto exit ;
}
ret = wait_for_completion_timeout ( & ar - > scan . on_channel , 3 * HZ ) ;
if ( ret = = 0 ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to switch to channel for roc scan \n " ) ;
2014-08-05 14:54:44 +02:00
ret = ath10k_scan_stop ( ar ) ;
if ( ret )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to stop scan: %d \n " , ret ) ;
2014-08-05 14:54:44 +02:00
2013-06-12 20:52:10 +03:00
ret = - ETIMEDOUT ;
goto exit ;
}
ret = 0 ;
exit :
mutex_unlock ( & ar - > conf_mutex ) ;
return ret ;
}
static int ath10k_cancel_remain_on_channel ( struct ieee80211_hw * hw )
{
struct ath10k * ar = hw - > priv ;
mutex_lock ( & ar - > conf_mutex ) ;
2014-08-05 14:54:44 +02:00
ath10k_scan_abort ( ar ) ;
2013-06-12 20:52:10 +03:00
mutex_unlock ( & ar - > conf_mutex ) ;
2014-10-28 10:23:09 +01:00
cancel_delayed_work_sync ( & ar - > scan . timeout ) ;
2013-06-12 20:52:10 +03:00
return 0 ;
}
/*
* Both RTS and Fragmentation threshold are interface - specific
* in ath10k , but device - specific in mac80211 .
*/
2013-10-16 15:44:46 +03:00
static int ath10k_set_rts_threshold ( struct ieee80211_hw * hw , u32 value )
{
struct ath10k * ar = hw - > priv ;
struct ath10k_vif * arvif ;
int ret = 0 ;
2013-07-05 16:15:15 +03:00
2013-06-12 20:52:10 +03:00
mutex_lock ( & ar - > conf_mutex ) ;
2013-10-16 15:44:46 +03:00
list_for_each_entry ( arvif , & ar - > arvifs , list ) {
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac vdev %d rts threshold %d \n " ,
2013-10-16 15:44:46 +03:00
arvif - > vdev_id , value ) ;
ret = ath10k_mac_set_rts ( arvif , value ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set rts threshold for vdev %d: %d \n " ,
2013-10-16 15:44:46 +03:00
arvif - > vdev_id , ret ) ;
break ;
}
}
2013-06-12 20:52:10 +03:00
mutex_unlock ( & ar - > conf_mutex ) ;
2013-10-16 15:44:46 +03:00
return ret ;
2013-06-12 20:52:10 +03:00
}
2014-03-27 11:30:29 +02:00
static void ath10k_flush ( struct ieee80211_hw * hw , struct ieee80211_vif * vif ,
u32 queues , bool drop )
2013-06-12 20:52:10 +03:00
{
struct ath10k * ar = hw - > priv ;
2013-07-16 09:54:35 +02:00
bool skip ;
2013-06-12 20:52:10 +03:00
int ret ;
/* mac80211 doesn't care if we really xmit queued frames or not
* we ' ll collect those frames either way if we stop / delete vdevs */
if ( drop )
return ;
2013-07-05 16:15:15 +03:00
mutex_lock ( & ar - > conf_mutex ) ;
2013-07-16 09:54:35 +02:00
if ( ar - > state = = ATH10K_STATE_WEDGED )
goto skip ;
2013-07-05 16:15:14 +03:00
ret = wait_event_timeout ( ar - > htt . empty_tx_wq , ( {
2013-06-12 20:52:10 +03:00
bool empty ;
2013-07-16 09:54:35 +02:00
2013-07-05 16:15:14 +03:00
spin_lock_bh ( & ar - > htt . tx_lock ) ;
2013-09-18 14:43:18 +02:00
empty = ( ar - > htt . num_pending_tx = = 0 ) ;
2013-07-05 16:15:14 +03:00
spin_unlock_bh ( & ar - > htt . tx_lock ) ;
2013-07-16 09:54:35 +02:00
2014-10-28 10:34:38 +01:00
skip = ( ar - > state = = ATH10K_STATE_WEDGED ) | |
test_bit ( ATH10K_FLAG_CRASH_FLUSH ,
& ar - > dev_flags ) ;
2013-07-16 09:54:35 +02:00
( empty | | skip ) ;
2013-06-12 20:52:10 +03:00
} ) , ATH10K_FLUSH_TIMEOUT_HZ ) ;
2013-07-16 09:54:35 +02:00
if ( ret < = 0 | | skip )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to flush transmit queue (skip %i ar-state %i): %i \n " ,
2014-02-25 09:29:57 +02:00
skip , ar - > state , ret ) ;
2013-07-05 16:15:15 +03:00
2013-07-16 09:54:35 +02:00
skip :
2013-07-05 16:15:15 +03:00
mutex_unlock ( & ar - > conf_mutex ) ;
2013-06-12 20:52:10 +03:00
}
/* TODO: Implement this function properly
* For now it is needed to reply to Probe Requests in IBSS mode .
* Propably we need this information from FW .
*/
static int ath10k_tx_last_beacon ( struct ieee80211_hw * hw )
{
return 1 ;
}
2014-11-04 11:43:54 +02:00
static void ath10k_reconfig_complete ( struct ieee80211_hw * hw ,
enum ieee80211_reconfig_type reconfig_type )
2013-07-16 09:54:35 +02:00
{
struct ath10k * ar = hw - > priv ;
2014-11-04 11:43:54 +02:00
if ( reconfig_type ! = IEEE80211_RECONFIG_TYPE_RESTART )
return ;
2013-07-16 09:54:35 +02:00
mutex_lock ( & ar - > conf_mutex ) ;
/* If device failed to restart it will be in a different state, e.g.
* ATH10K_STATE_WEDGED */
if ( ar - > state = = ATH10K_STATE_RESTARTED ) {
2014-08-25 12:09:38 +02:00
ath10k_info ( ar , " device successfully recovered \n " ) ;
2013-07-16 09:54:35 +02:00
ar - > state = ATH10K_STATE_ON ;
2014-10-28 10:34:38 +01:00
ieee80211_wake_queues ( ar - > hw ) ;
2013-07-16 09:54:35 +02:00
}
mutex_unlock ( & ar - > conf_mutex ) ;
}
2013-07-31 10:32:40 +02:00
static int ath10k_get_survey ( struct ieee80211_hw * hw , int idx ,
struct survey_info * survey )
{
struct ath10k * ar = hw - > priv ;
struct ieee80211_supported_band * sband ;
struct survey_info * ar_survey = & ar - > survey [ idx ] ;
int ret = 0 ;
mutex_lock ( & ar - > conf_mutex ) ;
sband = hw - > wiphy - > bands [ IEEE80211_BAND_2GHZ ] ;
if ( sband & & idx > = sband - > n_channels ) {
idx - = sband - > n_channels ;
sband = NULL ;
}
if ( ! sband )
sband = hw - > wiphy - > bands [ IEEE80211_BAND_5GHZ ] ;
if ( ! sband | | idx > = sband - > n_channels ) {
ret = - ENOENT ;
goto exit ;
}
spin_lock_bh ( & ar - > data_lock ) ;
memcpy ( survey , ar_survey , sizeof ( * survey ) ) ;
spin_unlock_bh ( & ar - > data_lock ) ;
survey - > channel = & sband - > channels [ idx ] ;
2014-10-23 17:04:28 +03:00
if ( ar - > rx_channel = = survey - > channel )
survey - > filled | = SURVEY_INFO_IN_USE ;
2013-07-31 10:32:40 +02:00
exit :
mutex_unlock ( & ar - > conf_mutex ) ;
return ret ;
}
2014-01-08 09:08:33 +01:00
/* Helper table for legacy fixed_rate/bitrate_mask */
static const u8 cck_ofdm_rate [ ] = {
/* CCK */
3 , /* 1Mbps */
2 , /* 2Mbps */
1 , /* 5.5Mbps */
0 , /* 11Mbps */
/* OFDM */
3 , /* 6Mbps */
7 , /* 9Mbps */
2 , /* 12Mbps */
6 , /* 18Mbps */
1 , /* 24Mbps */
5 , /* 36Mbps */
0 , /* 48Mbps */
4 , /* 54Mbps */
} ;
/* Check if only one bit set */
static int ath10k_check_single_mask ( u32 mask )
{
int bit ;
bit = ffs ( mask ) ;
if ( ! bit )
return 0 ;
mask & = ~ BIT ( bit - 1 ) ;
if ( mask )
return 2 ;
return 1 ;
}
static bool
ath10k_default_bitrate_mask ( struct ath10k * ar ,
enum ieee80211_band band ,
const struct cfg80211_bitrate_mask * mask )
{
u32 legacy = 0x00ff ;
u8 ht = 0xff , i ;
u16 vht = 0x3ff ;
2014-11-24 16:22:10 +02:00
u16 nrf = ar - > num_rf_chains ;
if ( ar - > cfg_tx_chainmask )
nrf = get_nss_from_chainmask ( ar - > cfg_tx_chainmask ) ;
2014-01-08 09:08:33 +01:00
switch ( band ) {
case IEEE80211_BAND_2GHZ :
legacy = 0x00fff ;
vht = 0 ;
break ;
case IEEE80211_BAND_5GHZ :
break ;
default :
return false ;
}
if ( mask - > control [ band ] . legacy ! = legacy )
return false ;
2014-11-24 16:22:10 +02:00
for ( i = 0 ; i < nrf ; i + + )
2014-01-08 09:08:33 +01:00
if ( mask - > control [ band ] . ht_mcs [ i ] ! = ht )
return false ;
2014-11-24 16:22:10 +02:00
for ( i = 0 ; i < nrf ; i + + )
2014-01-08 09:08:33 +01:00
if ( mask - > control [ band ] . vht_mcs [ i ] ! = vht )
return false ;
return true ;
}
static bool
ath10k_bitrate_mask_nss ( const struct cfg80211_bitrate_mask * mask ,
enum ieee80211_band band ,
u8 * fixed_nss )
{
int ht_nss = 0 , vht_nss = 0 , i ;
/* check legacy */
if ( ath10k_check_single_mask ( mask - > control [ band ] . legacy ) )
return false ;
/* check HT */
for ( i = 0 ; i < IEEE80211_HT_MCS_MASK_LEN ; i + + ) {
if ( mask - > control [ band ] . ht_mcs [ i ] = = 0xff )
continue ;
else if ( mask - > control [ band ] . ht_mcs [ i ] = = 0x00 )
break ;
2014-09-14 12:50:33 +03:00
return false ;
2014-01-08 09:08:33 +01:00
}
ht_nss = i ;
/* check VHT */
for ( i = 0 ; i < NL80211_VHT_NSS_MAX ; i + + ) {
if ( mask - > control [ band ] . vht_mcs [ i ] = = 0x03ff )
continue ;
else if ( mask - > control [ band ] . vht_mcs [ i ] = = 0x0000 )
break ;
2014-09-14 12:50:33 +03:00
return false ;
2014-01-08 09:08:33 +01:00
}
vht_nss = i ;
if ( ht_nss > 0 & & vht_nss > 0 )
return false ;
if ( ht_nss )
* fixed_nss = ht_nss ;
else if ( vht_nss )
* fixed_nss = vht_nss ;
else
return false ;
return true ;
}
static bool
ath10k_bitrate_mask_correct ( const struct cfg80211_bitrate_mask * mask ,
enum ieee80211_band band ,
enum wmi_rate_preamble * preamble )
{
int legacy = 0 , ht = 0 , vht = 0 , i ;
* preamble = WMI_RATE_PREAMBLE_OFDM ;
/* check legacy */
legacy = ath10k_check_single_mask ( mask - > control [ band ] . legacy ) ;
if ( legacy > 1 )
return false ;
/* check HT */
for ( i = 0 ; i < IEEE80211_HT_MCS_MASK_LEN ; i + + )
ht + = ath10k_check_single_mask ( mask - > control [ band ] . ht_mcs [ i ] ) ;
if ( ht > 1 )
return false ;
/* check VHT */
for ( i = 0 ; i < NL80211_VHT_NSS_MAX ; i + + )
vht + = ath10k_check_single_mask ( mask - > control [ band ] . vht_mcs [ i ] ) ;
if ( vht > 1 )
return false ;
/* Currently we support only one fixed_rate */
if ( ( legacy + ht + vht ) ! = 1 )
return false ;
if ( ht )
* preamble = WMI_RATE_PREAMBLE_HT ;
else if ( vht )
* preamble = WMI_RATE_PREAMBLE_VHT ;
return true ;
}
static bool
2014-08-25 12:09:38 +02:00
ath10k_bitrate_mask_rate ( struct ath10k * ar ,
const struct cfg80211_bitrate_mask * mask ,
2014-01-08 09:08:33 +01:00
enum ieee80211_band band ,
u8 * fixed_rate ,
u8 * fixed_nss )
{
u8 rate = 0 , pream = 0 , nss = 0 , i ;
enum wmi_rate_preamble preamble ;
/* Check if single rate correct */
if ( ! ath10k_bitrate_mask_correct ( mask , band , & preamble ) )
return false ;
pream = preamble ;
switch ( preamble ) {
case WMI_RATE_PREAMBLE_CCK :
case WMI_RATE_PREAMBLE_OFDM :
i = ffs ( mask - > control [ band ] . legacy ) - 1 ;
if ( band = = IEEE80211_BAND_2GHZ & & i < 4 )
pream = WMI_RATE_PREAMBLE_CCK ;
if ( band = = IEEE80211_BAND_5GHZ )
i + = 4 ;
if ( i > = ARRAY_SIZE ( cck_ofdm_rate ) )
return false ;
rate = cck_ofdm_rate [ i ] ;
break ;
case WMI_RATE_PREAMBLE_HT :
for ( i = 0 ; i < IEEE80211_HT_MCS_MASK_LEN ; i + + )
if ( mask - > control [ band ] . ht_mcs [ i ] )
break ;
if ( i = = IEEE80211_HT_MCS_MASK_LEN )
return false ;
rate = ffs ( mask - > control [ band ] . ht_mcs [ i ] ) - 1 ;
nss = i ;
break ;
case WMI_RATE_PREAMBLE_VHT :
for ( i = 0 ; i < NL80211_VHT_NSS_MAX ; i + + )
if ( mask - > control [ band ] . vht_mcs [ i ] )
break ;
if ( i = = NL80211_VHT_NSS_MAX )
return false ;
rate = ffs ( mask - > control [ band ] . vht_mcs [ i ] ) - 1 ;
nss = i ;
break ;
}
* fixed_nss = nss + 1 ;
nss < < = 4 ;
pream < < = 6 ;
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac fixed rate pream 0x%02x nss 0x%02x rate 0x%02x \n " ,
2014-01-08 09:08:33 +01:00
pream , nss , rate ) ;
* fixed_rate = pream | nss | rate ;
return true ;
}
2014-08-25 12:09:38 +02:00
static bool ath10k_get_fixed_rate_nss ( struct ath10k * ar ,
const struct cfg80211_bitrate_mask * mask ,
2014-01-08 09:08:33 +01:00
enum ieee80211_band band ,
u8 * fixed_rate ,
u8 * fixed_nss )
{
/* First check full NSS mask, if we can simply limit NSS */
if ( ath10k_bitrate_mask_nss ( mask , band , fixed_nss ) )
return true ;
/* Next Check single rate is set */
2014-08-25 12:09:38 +02:00
return ath10k_bitrate_mask_rate ( ar , mask , band , fixed_rate , fixed_nss ) ;
2014-01-08 09:08:33 +01:00
}
static int ath10k_set_fixed_rate_param ( struct ath10k_vif * arvif ,
u8 fixed_rate ,
2014-01-17 20:04:14 +01:00
u8 fixed_nss ,
u8 force_sgi )
2014-01-08 09:08:33 +01:00
{
struct ath10k * ar = arvif - > ar ;
u32 vdev_param ;
int ret = 0 ;
mutex_lock ( & ar - > conf_mutex ) ;
if ( arvif - > fixed_rate = = fixed_rate & &
2014-01-17 20:04:14 +01:00
arvif - > fixed_nss = = fixed_nss & &
arvif - > force_sgi = = force_sgi )
2014-01-08 09:08:33 +01:00
goto exit ;
if ( fixed_rate = = WMI_FIXED_RATE_NONE )
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac disable fixed bitrate mask \n " ) ;
2014-01-08 09:08:33 +01:00
2014-01-17 20:04:14 +01:00
if ( force_sgi )
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac force sgi \n " ) ;
2014-01-17 20:04:14 +01:00
2014-01-08 09:08:33 +01:00
vdev_param = ar - > wmi . vdev_param - > fixed_rate ;
ret = ath10k_wmi_vdev_set_param ( ar , arvif - > vdev_id ,
vdev_param , fixed_rate ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set fixed rate param 0x%02x: %d \n " ,
2014-01-08 09:08:33 +01:00
fixed_rate , ret ) ;
ret = - EINVAL ;
goto exit ;
}
arvif - > fixed_rate = fixed_rate ;
vdev_param = ar - > wmi . vdev_param - > nss ;
ret = ath10k_wmi_vdev_set_param ( ar , arvif - > vdev_id ,
vdev_param , fixed_nss ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set fixed nss param %d: %d \n " ,
2014-01-08 09:08:33 +01:00
fixed_nss , ret ) ;
ret = - EINVAL ;
goto exit ;
}
arvif - > fixed_nss = fixed_nss ;
2014-01-17 20:04:14 +01:00
vdev_param = ar - > wmi . vdev_param - > sgi ;
ret = ath10k_wmi_vdev_set_param ( ar , arvif - > vdev_id , vdev_param ,
force_sgi ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to set sgi param %d: %d \n " ,
2014-01-17 20:04:14 +01:00
force_sgi , ret ) ;
ret = - EINVAL ;
goto exit ;
}
arvif - > force_sgi = force_sgi ;
2014-01-08 09:08:33 +01:00
exit :
mutex_unlock ( & ar - > conf_mutex ) ;
return ret ;
}
static int ath10k_set_bitrate_mask ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif ,
const struct cfg80211_bitrate_mask * mask )
{
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
struct ath10k * ar = arvif - > ar ;
enum ieee80211_band band = ar - > hw - > conf . chandef . chan - > band ;
u8 fixed_rate = WMI_FIXED_RATE_NONE ;
u8 fixed_nss = ar - > num_rf_chains ;
2014-01-17 20:04:14 +01:00
u8 force_sgi ;
2014-11-24 16:22:10 +02:00
if ( ar - > cfg_tx_chainmask )
fixed_nss = get_nss_from_chainmask ( ar - > cfg_tx_chainmask ) ;
2014-01-17 20:04:14 +01:00
force_sgi = mask - > control [ band ] . gi ;
if ( force_sgi = = NL80211_TXRATE_FORCE_LGI )
return - EINVAL ;
2014-01-08 09:08:33 +01:00
if ( ! ath10k_default_bitrate_mask ( ar , band , mask ) ) {
2014-08-25 12:09:38 +02:00
if ( ! ath10k_get_fixed_rate_nss ( ar , mask , band ,
2014-01-08 09:08:33 +01:00
& fixed_rate ,
& fixed_nss ) )
return - EINVAL ;
}
2014-01-17 20:04:14 +01:00
if ( fixed_rate = = WMI_FIXED_RATE_NONE & & force_sgi ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to force SGI usage for default rate settings \n " ) ;
2014-01-17 20:04:14 +01:00
return - EINVAL ;
}
return ath10k_set_fixed_rate_param ( arvif , fixed_rate ,
fixed_nss , force_sgi ) ;
2014-01-08 09:08:33 +01:00
}
2014-02-14 14:49:48 +01:00
static void ath10k_sta_rc_update ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif ,
struct ieee80211_sta * sta ,
u32 changed )
{
struct ath10k * ar = hw - > priv ;
struct ath10k_sta * arsta = ( struct ath10k_sta * ) sta - > drv_priv ;
u32 bw , smps ;
spin_lock_bh ( & ar - > data_lock ) ;
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC ,
2014-02-14 14:49:48 +01:00
" mac sta rc update for %pM changed %08x bw %d nss %d smps %d \n " ,
sta - > addr , changed , sta - > bandwidth , sta - > rx_nss ,
sta - > smps_mode ) ;
if ( changed & IEEE80211_RC_BW_CHANGED ) {
bw = WMI_PEER_CHWIDTH_20MHZ ;
switch ( sta - > bandwidth ) {
case IEEE80211_STA_RX_BW_20 :
bw = WMI_PEER_CHWIDTH_20MHZ ;
break ;
case IEEE80211_STA_RX_BW_40 :
bw = WMI_PEER_CHWIDTH_40MHZ ;
break ;
case IEEE80211_STA_RX_BW_80 :
bw = WMI_PEER_CHWIDTH_80MHZ ;
break ;
case IEEE80211_STA_RX_BW_160 :
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " Invalid bandwith %d in rc update for %pM \n " ,
2014-03-25 14:18:51 +02:00
sta - > bandwidth , sta - > addr ) ;
2014-02-14 14:49:48 +01:00
bw = WMI_PEER_CHWIDTH_20MHZ ;
break ;
}
arsta - > bw = bw ;
}
if ( changed & IEEE80211_RC_NSS_CHANGED )
arsta - > nss = sta - > rx_nss ;
if ( changed & IEEE80211_RC_SMPS_CHANGED ) {
smps = WMI_PEER_SMPS_PS_NONE ;
switch ( sta - > smps_mode ) {
case IEEE80211_SMPS_AUTOMATIC :
case IEEE80211_SMPS_OFF :
smps = WMI_PEER_SMPS_PS_NONE ;
break ;
case IEEE80211_SMPS_STATIC :
smps = WMI_PEER_SMPS_STATIC ;
break ;
case IEEE80211_SMPS_DYNAMIC :
smps = WMI_PEER_SMPS_DYNAMIC ;
break ;
case IEEE80211_SMPS_NUM_MODES :
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " Invalid smps %d in sta rc update for %pM \n " ,
2014-03-25 14:18:51 +02:00
sta - > smps_mode , sta - > addr ) ;
2014-02-14 14:49:48 +01:00
smps = WMI_PEER_SMPS_PS_NONE ;
break ;
}
arsta - > smps = smps ;
}
arsta - > changed | = changed ;
spin_unlock_bh ( & ar - > data_lock ) ;
ieee80211_queue_work ( hw , & arsta - > update_wk ) ;
}
2014-02-25 09:29:54 +02:00
static u64 ath10k_get_tsf ( struct ieee80211_hw * hw , struct ieee80211_vif * vif )
{
/*
* FIXME : Return 0 for time being . Need to figure out whether FW
* has the API to fetch 64 - bit local TSF
*/
return 0 ;
}
2014-07-23 12:20:33 +02:00
static int ath10k_ampdu_action ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif ,
enum ieee80211_ampdu_mlme_action action ,
struct ieee80211_sta * sta , u16 tid , u16 * ssn ,
u8 buf_size )
{
2014-08-25 12:09:38 +02:00
struct ath10k * ar = hw - > priv ;
2014-07-23 12:20:33 +02:00
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
2014-08-25 12:09:38 +02:00
ath10k_dbg ( ar , ATH10K_DBG_MAC , " mac ampdu vdev_id %i sta %pM tid %hu action %d \n " ,
2014-07-23 12:20:33 +02:00
arvif - > vdev_id , sta - > addr , tid , action ) ;
switch ( action ) {
case IEEE80211_AMPDU_RX_START :
case IEEE80211_AMPDU_RX_STOP :
/* HTT AddBa/DelBa events trigger mac80211 Rx BA session
* creation / removal . Do we need to verify this ?
*/
return 0 ;
case IEEE80211_AMPDU_TX_START :
case IEEE80211_AMPDU_TX_STOP_CONT :
case IEEE80211_AMPDU_TX_STOP_FLUSH :
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT :
case IEEE80211_AMPDU_TX_OPERATIONAL :
/* Firmware offloads Tx aggregation entirely so deny mac80211
* Tx aggregation requests .
*/
return - EOPNOTSUPP ;
}
return - EINVAL ;
}
2013-06-12 20:52:10 +03:00
static const struct ieee80211_ops ath10k_ops = {
. tx = ath10k_tx ,
. start = ath10k_start ,
. stop = ath10k_stop ,
. config = ath10k_config ,
. add_interface = ath10k_add_interface ,
. remove_interface = ath10k_remove_interface ,
. configure_filter = ath10k_configure_filter ,
. bss_info_changed = ath10k_bss_info_changed ,
. hw_scan = ath10k_hw_scan ,
. cancel_hw_scan = ath10k_cancel_hw_scan ,
. set_key = ath10k_set_key ,
2015-01-29 13:50:38 +02:00
. set_default_unicast_key = ath10k_set_default_unicast_key ,
2013-06-12 20:52:10 +03:00
. sta_state = ath10k_sta_state ,
. conf_tx = ath10k_conf_tx ,
. remain_on_channel = ath10k_remain_on_channel ,
. cancel_remain_on_channel = ath10k_cancel_remain_on_channel ,
. set_rts_threshold = ath10k_set_rts_threshold ,
. flush = ath10k_flush ,
. tx_last_beacon = ath10k_tx_last_beacon ,
2014-05-16 17:15:38 +03:00
. set_antenna = ath10k_set_antenna ,
. get_antenna = ath10k_get_antenna ,
2014-11-04 11:43:54 +02:00
. reconfig_complete = ath10k_reconfig_complete ,
2013-07-31 10:32:40 +02:00
. get_survey = ath10k_get_survey ,
2014-01-08 09:08:33 +01:00
. set_bitrate_mask = ath10k_set_bitrate_mask ,
2014-02-14 14:49:48 +01:00
. sta_rc_update = ath10k_sta_rc_update ,
2014-02-25 09:29:54 +02:00
. get_tsf = ath10k_get_tsf ,
2014-07-23 12:20:33 +02:00
. ampdu_action = ath10k_ampdu_action ,
2014-09-29 14:41:46 +03:00
. get_et_sset_count = ath10k_debug_get_et_sset_count ,
. get_et_stats = ath10k_debug_get_et_stats ,
. get_et_strings = ath10k_debug_get_et_strings ,
2014-09-10 18:23:30 +03:00
CFG80211_TESTMODE_CMD ( ath10k_tm_cmd )
2013-07-16 09:38:54 +02:00
# ifdef CONFIG_PM
2015-03-23 17:32:53 +02:00
. suspend = ath10k_wow_op_suspend ,
. resume = ath10k_wow_op_resume ,
2013-07-16 09:38:54 +02:00
# endif
2015-01-12 14:07:27 +02:00
# ifdef CONFIG_MAC80211_DEBUGFS
. sta_add_debugfs = ath10k_sta_add_debugfs ,
# endif
2013-06-12 20:52:10 +03:00
} ;
# define RATETAB_ENT(_rate, _rateid, _flags) { \
. bitrate = ( _rate ) , \
. flags = ( _flags ) , \
. hw_value = ( _rateid ) , \
}
# define CHAN2G(_channel, _freq, _flags) { \
. band = IEEE80211_BAND_2GHZ , \
. hw_value = ( _channel ) , \
. center_freq = ( _freq ) , \
. flags = ( _flags ) , \
. max_antenna_gain = 0 , \
. max_power = 30 , \
}
# define CHAN5G(_channel, _freq, _flags) { \
. band = IEEE80211_BAND_5GHZ , \
. hw_value = ( _channel ) , \
. center_freq = ( _freq ) , \
. flags = ( _flags ) , \
. max_antenna_gain = 0 , \
. max_power = 30 , \
}
static const struct ieee80211_channel ath10k_2ghz_channels [ ] = {
CHAN2G ( 1 , 2412 , 0 ) ,
CHAN2G ( 2 , 2417 , 0 ) ,
CHAN2G ( 3 , 2422 , 0 ) ,
CHAN2G ( 4 , 2427 , 0 ) ,
CHAN2G ( 5 , 2432 , 0 ) ,
CHAN2G ( 6 , 2437 , 0 ) ,
CHAN2G ( 7 , 2442 , 0 ) ,
CHAN2G ( 8 , 2447 , 0 ) ,
CHAN2G ( 9 , 2452 , 0 ) ,
CHAN2G ( 10 , 2457 , 0 ) ,
CHAN2G ( 11 , 2462 , 0 ) ,
CHAN2G ( 12 , 2467 , 0 ) ,
CHAN2G ( 13 , 2472 , 0 ) ,
CHAN2G ( 14 , 2484 , 0 ) ,
} ;
static const struct ieee80211_channel ath10k_5ghz_channels [ ] = {
2013-06-26 08:54:54 +02:00
CHAN5G ( 36 , 5180 , 0 ) ,
CHAN5G ( 40 , 5200 , 0 ) ,
CHAN5G ( 44 , 5220 , 0 ) ,
CHAN5G ( 48 , 5240 , 0 ) ,
CHAN5G ( 52 , 5260 , 0 ) ,
CHAN5G ( 56 , 5280 , 0 ) ,
CHAN5G ( 60 , 5300 , 0 ) ,
CHAN5G ( 64 , 5320 , 0 ) ,
CHAN5G ( 100 , 5500 , 0 ) ,
CHAN5G ( 104 , 5520 , 0 ) ,
CHAN5G ( 108 , 5540 , 0 ) ,
CHAN5G ( 112 , 5560 , 0 ) ,
CHAN5G ( 116 , 5580 , 0 ) ,
CHAN5G ( 120 , 5600 , 0 ) ,
CHAN5G ( 124 , 5620 , 0 ) ,
CHAN5G ( 128 , 5640 , 0 ) ,
CHAN5G ( 132 , 5660 , 0 ) ,
CHAN5G ( 136 , 5680 , 0 ) ,
CHAN5G ( 140 , 5700 , 0 ) ,
2015-03-18 11:39:18 -07:00
CHAN5G ( 144 , 5720 , 0 ) ,
2013-06-26 08:54:54 +02:00
CHAN5G ( 149 , 5745 , 0 ) ,
CHAN5G ( 153 , 5765 , 0 ) ,
CHAN5G ( 157 , 5785 , 0 ) ,
CHAN5G ( 161 , 5805 , 0 ) ,
CHAN5G ( 165 , 5825 , 0 ) ,
2013-06-12 20:52:10 +03:00
} ;
2014-12-12 12:41:35 +01:00
/* Note: Be careful if you re-order these. There is code which depends on this
* ordering .
*/
2013-06-12 20:52:10 +03:00
static struct ieee80211_rate ath10k_rates [ ] = {
/* CCK */
RATETAB_ENT ( 10 , 0x82 , 0 ) ,
RATETAB_ENT ( 20 , 0x84 , 0 ) ,
RATETAB_ENT ( 55 , 0x8b , 0 ) ,
RATETAB_ENT ( 110 , 0x96 , 0 ) ,
/* OFDM */
RATETAB_ENT ( 60 , 0x0c , 0 ) ,
RATETAB_ENT ( 90 , 0x12 , 0 ) ,
RATETAB_ENT ( 120 , 0x18 , 0 ) ,
RATETAB_ENT ( 180 , 0x24 , 0 ) ,
RATETAB_ENT ( 240 , 0x30 , 0 ) ,
RATETAB_ENT ( 360 , 0x48 , 0 ) ,
RATETAB_ENT ( 480 , 0x60 , 0 ) ,
RATETAB_ENT ( 540 , 0x6c , 0 ) ,
} ;
# define ath10k_a_rates (ath10k_rates + 4)
# define ath10k_a_rates_size (ARRAY_SIZE(ath10k_rates) - 4)
# define ath10k_g_rates (ath10k_rates + 0)
# define ath10k_g_rates_size (ARRAY_SIZE(ath10k_rates))
2014-08-07 11:03:27 +02:00
struct ath10k * ath10k_mac_create ( size_t priv_size )
2013-06-12 20:52:10 +03:00
{
struct ieee80211_hw * hw ;
struct ath10k * ar ;
2014-08-07 11:03:27 +02:00
hw = ieee80211_alloc_hw ( sizeof ( struct ath10k ) + priv_size , & ath10k_ops ) ;
2013-06-12 20:52:10 +03:00
if ( ! hw )
return NULL ;
ar = hw - > priv ;
ar - > hw = hw ;
return ar ;
}
void ath10k_mac_destroy ( struct ath10k * ar )
{
ieee80211_free_hw ( ar - > hw ) ;
}
static const struct ieee80211_iface_limit ath10k_if_limits [ ] = {
{
. max = 8 ,
. types = BIT ( NL80211_IFTYPE_STATION )
| BIT ( NL80211_IFTYPE_P2P_CLIENT )
2013-07-31 10:55:13 +02:00
} ,
{
. max = 3 ,
. types = BIT ( NL80211_IFTYPE_P2P_GO )
} ,
{
2014-12-12 12:41:39 +01:00
. max = 1 ,
. types = BIT ( NL80211_IFTYPE_P2P_DEVICE )
} ,
{
2013-07-31 10:55:13 +02:00
. max = 7 ,
. types = BIT ( NL80211_IFTYPE_AP )
} ,
2013-06-12 20:52:10 +03:00
} ;
2013-12-10 16:20:39 +01:00
static const struct ieee80211_iface_limit ath10k_10x_if_limits [ ] = {
2013-11-20 09:59:47 +02:00
{
. max = 8 ,
. types = BIT ( NL80211_IFTYPE_AP )
} ,
} ;
static const struct ieee80211_iface_combination ath10k_if_comb [ ] = {
{
. limits = ath10k_if_limits ,
. n_limits = ARRAY_SIZE ( ath10k_if_limits ) ,
. max_interfaces = 8 ,
. num_different_channels = 1 ,
. beacon_int_infra_match = true ,
} ,
2013-12-10 16:20:39 +01:00
} ;
static const struct ieee80211_iface_combination ath10k_10x_if_comb [ ] = {
2013-11-20 09:59:47 +02:00
{
2013-12-10 16:20:39 +01:00
. limits = ath10k_10x_if_limits ,
. n_limits = ARRAY_SIZE ( ath10k_10x_if_limits ) ,
2013-11-20 09:59:47 +02:00
. max_interfaces = 8 ,
. num_different_channels = 1 ,
. beacon_int_infra_match = true ,
2013-12-10 16:20:39 +01:00
# ifdef CONFIG_ATH10K_DFS_CERTIFIED
2013-11-20 09:59:47 +02:00
. radar_detect_widths = BIT ( NL80211_CHAN_WIDTH_20_NOHT ) |
BIT ( NL80211_CHAN_WIDTH_20 ) |
BIT ( NL80211_CHAN_WIDTH_40 ) |
BIT ( NL80211_CHAN_WIDTH_80 ) ,
# endif
2013-12-10 16:20:39 +01:00
} ,
2013-06-12 20:52:10 +03:00
} ;
static struct ieee80211_sta_vht_cap ath10k_create_vht_cap ( struct ath10k * ar )
{
struct ieee80211_sta_vht_cap vht_cap = { 0 } ;
u16 mcs_map ;
2015-02-26 11:11:22 +01:00
u32 val ;
2013-07-24 12:36:46 +02:00
int i ;
2013-06-12 20:52:10 +03:00
vht_cap . vht_supported = 1 ;
vht_cap . cap = ar - > vht_cap_info ;
2015-02-26 11:11:22 +01:00
if ( ar - > vht_cap_info & ( IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE ) ) {
val = ar - > num_rf_chains - 1 ;
val < < = IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT ;
val & = IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK ;
vht_cap . cap | = val ;
}
if ( ar - > vht_cap_info & ( IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE ) ) {
val = ar - > num_rf_chains - 1 ;
val < < = IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT ;
val & = IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK ;
vht_cap . cap | = val ;
}
2013-07-24 12:36:46 +02:00
mcs_map = 0 ;
for ( i = 0 ; i < 8 ; i + + ) {
if ( i < ar - > num_rf_chains )
mcs_map | = IEEE80211_VHT_MCS_SUPPORT_0_9 < < ( i * 2 ) ;
else
mcs_map | = IEEE80211_VHT_MCS_NOT_SUPPORTED < < ( i * 2 ) ;
}
2013-06-12 20:52:10 +03:00
vht_cap . vht_mcs . rx_mcs_map = cpu_to_le16 ( mcs_map ) ;
vht_cap . vht_mcs . tx_mcs_map = cpu_to_le16 ( mcs_map ) ;
return vht_cap ;
}
static struct ieee80211_sta_ht_cap ath10k_get_ht_cap ( struct ath10k * ar )
{
int i ;
struct ieee80211_sta_ht_cap ht_cap = { 0 } ;
if ( ! ( ar - > ht_cap_info & WMI_HT_CAP_ENABLED ) )
return ht_cap ;
ht_cap . ht_supported = 1 ;
ht_cap . ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K ;
ht_cap . ampdu_density = IEEE80211_HT_MPDU_DENSITY_8 ;
ht_cap . cap | = IEEE80211_HT_CAP_SUP_WIDTH_20_40 ;
ht_cap . cap | = IEEE80211_HT_CAP_DSSSCCK40 ;
ht_cap . cap | = WLAN_HT_CAP_SM_PS_STATIC < < IEEE80211_HT_CAP_SM_PS_SHIFT ;
if ( ar - > ht_cap_info & WMI_HT_CAP_HT20_SGI )
ht_cap . cap | = IEEE80211_HT_CAP_SGI_20 ;
if ( ar - > ht_cap_info & WMI_HT_CAP_HT40_SGI )
ht_cap . cap | = IEEE80211_HT_CAP_SGI_40 ;
if ( ar - > ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS ) {
u32 smps ;
smps = WLAN_HT_CAP_SM_PS_DYNAMIC ;
smps < < = IEEE80211_HT_CAP_SM_PS_SHIFT ;
ht_cap . cap | = smps ;
}
if ( ar - > ht_cap_info & WMI_HT_CAP_TX_STBC )
ht_cap . cap | = IEEE80211_HT_CAP_TX_STBC ;
if ( ar - > ht_cap_info & WMI_HT_CAP_RX_STBC ) {
u32 stbc ;
stbc = ar - > ht_cap_info ;
stbc & = WMI_HT_CAP_RX_STBC ;
stbc > > = WMI_HT_CAP_RX_STBC_MASK_SHIFT ;
stbc < < = IEEE80211_HT_CAP_RX_STBC_SHIFT ;
stbc & = IEEE80211_HT_CAP_RX_STBC ;
ht_cap . cap | = stbc ;
}
if ( ar - > ht_cap_info & WMI_HT_CAP_LDPC )
ht_cap . cap | = IEEE80211_HT_CAP_LDPC_CODING ;
if ( ar - > ht_cap_info & WMI_HT_CAP_L_SIG_TXOP_PROT )
ht_cap . cap | = IEEE80211_HT_CAP_LSIG_TXOP_PROT ;
/* max AMSDU is implicitly taken from vht_cap_info */
if ( ar - > vht_cap_info & WMI_VHT_CAP_MAX_MPDU_LEN_MASK )
ht_cap . cap | = IEEE80211_HT_CAP_MAX_AMSDU ;
2013-07-24 12:36:46 +02:00
for ( i = 0 ; i < ar - > num_rf_chains ; i + + )
2013-06-12 20:52:10 +03:00
ht_cap . mcs . rx_mask [ i ] = 0xFF ;
ht_cap . mcs . tx_params | = IEEE80211_HT_MCS_TX_DEFINED ;
return ht_cap ;
}
static void ath10k_get_arvif_iter ( void * data , u8 * mac ,
struct ieee80211_vif * vif )
{
struct ath10k_vif_iter * arvif_iter = data ;
struct ath10k_vif * arvif = ath10k_vif_to_arvif ( vif ) ;
if ( arvif - > vdev_id = = arvif_iter - > vdev_id )
arvif_iter - > arvif = arvif ;
}
struct ath10k_vif * ath10k_get_arvif ( struct ath10k * ar , u32 vdev_id )
{
struct ath10k_vif_iter arvif_iter ;
u32 flags ;
memset ( & arvif_iter , 0 , sizeof ( struct ath10k_vif_iter ) ) ;
arvif_iter . vdev_id = vdev_id ;
flags = IEEE80211_IFACE_ITER_RESUME_ALL ;
ieee80211_iterate_active_interfaces_atomic ( ar - > hw ,
flags ,
ath10k_get_arvif_iter ,
& arvif_iter ) ;
if ( ! arvif_iter . arvif ) {
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " No VIF found for vdev %d \n " , vdev_id ) ;
2013-06-12 20:52:10 +03:00
return NULL ;
}
return arvif_iter . arvif ;
}
int ath10k_mac_register ( struct ath10k * ar )
{
2015-01-22 21:38:45 +01:00
static const u32 cipher_suites [ ] = {
WLAN_CIPHER_SUITE_WEP40 ,
WLAN_CIPHER_SUITE_WEP104 ,
WLAN_CIPHER_SUITE_TKIP ,
WLAN_CIPHER_SUITE_CCMP ,
WLAN_CIPHER_SUITE_AES_CMAC ,
} ;
2013-06-12 20:52:10 +03:00
struct ieee80211_supported_band * band ;
struct ieee80211_sta_vht_cap vht_cap ;
struct ieee80211_sta_ht_cap ht_cap ;
void * channels ;
int ret ;
SET_IEEE80211_PERM_ADDR ( ar - > hw , ar - > mac_addr ) ;
SET_IEEE80211_DEV ( ar - > hw , ar - > dev ) ;
ht_cap = ath10k_get_ht_cap ( ar ) ;
vht_cap = ath10k_create_vht_cap ( ar ) ;
if ( ar - > phy_capability & WHAL_WLAN_11G_CAPABILITY ) {
channels = kmemdup ( ath10k_2ghz_channels ,
sizeof ( ath10k_2ghz_channels ) ,
GFP_KERNEL ) ;
2013-07-22 14:13:30 +02:00
if ( ! channels ) {
ret = - ENOMEM ;
goto err_free ;
}
2013-06-12 20:52:10 +03:00
band = & ar - > mac . sbands [ IEEE80211_BAND_2GHZ ] ;
band - > n_channels = ARRAY_SIZE ( ath10k_2ghz_channels ) ;
band - > channels = channels ;
band - > n_bitrates = ath10k_g_rates_size ;
band - > bitrates = ath10k_g_rates ;
band - > ht_cap = ht_cap ;
2015-01-23 08:18:20 +08:00
/* Enable the VHT support at 2.4 GHz */
band - > vht_cap = vht_cap ;
2013-06-12 20:52:10 +03:00
ar - > hw - > wiphy - > bands [ IEEE80211_BAND_2GHZ ] = band ;
}
if ( ar - > phy_capability & WHAL_WLAN_11A_CAPABILITY ) {
channels = kmemdup ( ath10k_5ghz_channels ,
sizeof ( ath10k_5ghz_channels ) ,
GFP_KERNEL ) ;
if ( ! channels ) {
2013-07-22 14:13:30 +02:00
ret = - ENOMEM ;
goto err_free ;
2013-06-12 20:52:10 +03:00
}
band = & ar - > mac . sbands [ IEEE80211_BAND_5GHZ ] ;
band - > n_channels = ARRAY_SIZE ( ath10k_5ghz_channels ) ;
band - > channels = channels ;
band - > n_bitrates = ath10k_a_rates_size ;
band - > bitrates = ath10k_a_rates ;
band - > ht_cap = ht_cap ;
band - > vht_cap = vht_cap ;
ar - > hw - > wiphy - > bands [ IEEE80211_BAND_5GHZ ] = band ;
}
ar - > hw - > wiphy - > interface_modes =
BIT ( NL80211_IFTYPE_STATION ) |
2013-12-10 16:20:40 +01:00
BIT ( NL80211_IFTYPE_AP ) ;
2014-05-16 17:15:38 +03:00
ar - > hw - > wiphy - > available_antennas_rx = ar - > supp_rx_chainmask ;
ar - > hw - > wiphy - > available_antennas_tx = ar - > supp_tx_chainmask ;
2013-12-10 16:20:40 +01:00
if ( ! test_bit ( ATH10K_FW_FEATURE_NO_P2P , ar - > fw_features ) )
ar - > hw - > wiphy - > interface_modes | =
2014-12-12 12:41:39 +01:00
BIT ( NL80211_IFTYPE_P2P_DEVICE ) |
2013-12-10 16:20:40 +01:00
BIT ( NL80211_IFTYPE_P2P_CLIENT ) |
BIT ( NL80211_IFTYPE_P2P_GO ) ;
2013-06-12 20:52:10 +03:00
ar - > hw - > flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
IEEE80211_HW_MFP_CAPABLE |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
IEEE80211_HW_HAS_RATE_CONTROL |
2014-02-26 18:42:09 +02:00
IEEE80211_HW_AP_LINK_PS |
2015-01-22 21:38:45 +01:00
IEEE80211_HW_SPECTRUM_MGMT |
2015-03-10 16:22:01 +02:00
IEEE80211_HW_SW_CRYPTO_CONTROL |
IEEE80211_HW_CONNECTION_MONITOR ;
2013-06-12 20:52:10 +03:00
2014-09-10 14:07:36 +03:00
ar - > hw - > wiphy - > features | = NL80211_FEATURE_STATIC_SMPS ;
2013-06-12 20:52:10 +03:00
if ( ar - > ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS )
2014-09-10 14:07:36 +03:00
ar - > hw - > wiphy - > features | = NL80211_FEATURE_DYNAMIC_SMPS ;
2013-06-12 20:52:10 +03:00
if ( ar - > ht_cap_info & WMI_HT_CAP_ENABLED ) {
ar - > hw - > flags | = IEEE80211_HW_AMPDU_AGGREGATION ;
ar - > hw - > flags | = IEEE80211_HW_TX_AMPDU_SETUP_IN_HW ;
}
ar - > hw - > wiphy - > max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID ;
ar - > hw - > wiphy - > max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN ;
ar - > hw - > vif_data_size = sizeof ( struct ath10k_vif ) ;
2014-02-14 14:49:48 +01:00
ar - > hw - > sta_data_size = sizeof ( struct ath10k_sta ) ;
2013-06-12 20:52:10 +03:00
ar - > hw - > max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL ;
2015-01-13 16:30:12 +02:00
if ( test_bit ( WMI_SERVICE_BEACON_OFFLOAD , ar - > wmi . svc_map ) ) {
ar - > hw - > wiphy - > flags | = WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD ;
/* Firmware delivers WPS/P2P Probe Requests frames to driver so
* that userspace ( e . g . wpa_supplicant / hostapd ) can generate
* correct Probe Responses . This is more of a hack advert . .
*/
ar - > hw - > wiphy - > probe_resp_offload | =
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P ;
}
2013-06-12 20:52:10 +03:00
ar - > hw - > wiphy - > flags | = WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL ;
2014-01-23 11:38:26 +01:00
ar - > hw - > wiphy - > flags | = WIPHY_FLAG_HAS_CHANNEL_SWITCH ;
2013-06-12 20:52:10 +03:00
ar - > hw - > wiphy - > max_remain_on_channel_duration = 5000 ;
ar - > hw - > wiphy - > flags | = WIPHY_FLAG_AP_UAPSD ;
2014-11-17 16:44:15 +02:00
ar - > hw - > wiphy - > features | = NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE ;
2015-03-12 13:11:41 +01:00
ar - > hw - > wiphy - > max_ap_assoc_sta = ar - > max_num_stations ;
2015-03-23 17:32:53 +02:00
ret = ath10k_wow_init ( ar ) ;
if ( ret ) {
ath10k_warn ( ar , " failed to init wow: %d \n " , ret ) ;
goto err_free ;
}
2013-06-12 20:52:10 +03:00
/*
* on LL hardware queues are managed entirely by the FW
* so we only advertise to mac we can do the queues thing
*/
ar - > hw - > queues = 4 ;
2014-12-17 12:20:54 +02:00
switch ( ar - > wmi . op_version ) {
case ATH10K_FW_WMI_OP_VERSION_MAIN :
case ATH10K_FW_WMI_OP_VERSION_TLV :
2013-12-10 16:20:39 +01:00
ar - > hw - > wiphy - > iface_combinations = ath10k_if_comb ;
ar - > hw - > wiphy - > n_iface_combinations =
ARRAY_SIZE ( ath10k_if_comb ) ;
2014-07-24 20:07:00 +03:00
ar - > hw - > wiphy - > interface_modes | = BIT ( NL80211_IFTYPE_ADHOC ) ;
2014-12-17 12:20:54 +02:00
break ;
case ATH10K_FW_WMI_OP_VERSION_10_1 :
case ATH10K_FW_WMI_OP_VERSION_10_2 :
2014-12-17 12:21:12 +02:00
case ATH10K_FW_WMI_OP_VERSION_10_2_4 :
2014-12-17 12:20:54 +02:00
ar - > hw - > wiphy - > iface_combinations = ath10k_10x_if_comb ;
ar - > hw - > wiphy - > n_iface_combinations =
ARRAY_SIZE ( ath10k_10x_if_comb ) ;
break ;
case ATH10K_FW_WMI_OP_VERSION_UNSET :
case ATH10K_FW_WMI_OP_VERSION_MAX :
WARN_ON ( 1 ) ;
ret = - EINVAL ;
goto err_free ;
2013-12-10 16:20:39 +01:00
}
2013-06-12 20:52:10 +03:00
2013-07-31 10:47:57 +02:00
ar - > hw - > netdev_features = NETIF_F_HW_CSUM ;
2013-11-20 09:59:41 +02:00
if ( config_enabled ( CONFIG_ATH10K_DFS_CERTIFIED ) ) {
/* Init ath dfs pattern detector */
ar - > ath_common . debug_mask = ATH_DBG_DFS ;
ar - > dfs_detector = dfs_pattern_detector_init ( & ar - > ath_common ,
NL80211_DFS_UNSET ) ;
if ( ! ar - > dfs_detector )
2014-08-25 12:09:38 +02:00
ath10k_warn ( ar , " failed to initialise DFS pattern detector \n " ) ;
2013-11-20 09:59:41 +02:00
}
2013-06-12 20:52:10 +03:00
ret = ath_regd_init ( & ar - > ath_common . regulatory , ar - > hw - > wiphy ,
ath10k_reg_notifier ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_err ( ar , " failed to initialise regulatory: %i \n " , ret ) ;
2013-07-22 14:13:30 +02:00
goto err_free ;
2013-06-12 20:52:10 +03:00
}
2015-01-22 21:38:45 +01:00
ar - > hw - > wiphy - > cipher_suites = cipher_suites ;
ar - > hw - > wiphy - > n_cipher_suites = ARRAY_SIZE ( cipher_suites ) ;
2013-06-12 20:52:10 +03:00
ret = ieee80211_register_hw ( ar - > hw ) ;
if ( ret ) {
2014-08-25 12:09:38 +02:00
ath10k_err ( ar , " failed to register ieee80211: %d \n " , ret ) ;
2013-07-22 14:13:30 +02:00
goto err_free ;
2013-06-12 20:52:10 +03:00
}
if ( ! ath_is_world_regd ( & ar - > ath_common . regulatory ) ) {
ret = regulatory_hint ( ar - > hw - > wiphy ,
ar - > ath_common . regulatory . alpha2 ) ;
if ( ret )
2013-07-22 14:13:30 +02:00
goto err_unregister ;
2013-06-12 20:52:10 +03:00
}
return 0 ;
2013-07-22 14:13:30 +02:00
err_unregister :
2013-06-12 20:52:10 +03:00
ieee80211_unregister_hw ( ar - > hw ) ;
2013-07-22 14:13:30 +02:00
err_free :
kfree ( ar - > mac . sbands [ IEEE80211_BAND_2GHZ ] . channels ) ;
kfree ( ar - > mac . sbands [ IEEE80211_BAND_5GHZ ] . channels ) ;
2013-06-12 20:52:10 +03:00
return ret ;
}
void ath10k_mac_unregister ( struct ath10k * ar )
{
ieee80211_unregister_hw ( ar - > hw ) ;
2013-11-20 09:59:41 +02:00
if ( config_enabled ( CONFIG_ATH10K_DFS_CERTIFIED ) & & ar - > dfs_detector )
ar - > dfs_detector - > exit ( ar - > dfs_detector ) ;
2013-06-12 20:52:10 +03:00
kfree ( ar - > mac . sbands [ IEEE80211_BAND_2GHZ ] . channels ) ;
kfree ( ar - > mac . sbands [ IEEE80211_BAND_5GHZ ] . channels ) ;
SET_IEEE80211_DEV ( ar - > hw , NULL ) ;
}