Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
d9a577c3
Commit
d9a577c3
authored
Dec 11, 2013
by
John W. Linville
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-john' of
git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
parents
d6b5075d
9d10849e
Changes
30
Show whitespace changes
Inline
Side-by-side
Showing
30 changed files
with
1538 additions
and
1592 deletions
+1538
-1592
drivers/net/wireless/iwlwifi/dvm/rs.h
drivers/net/wireless/iwlwifi/dvm/rs.h
+0
-7
drivers/net/wireless/iwlwifi/dvm/tx.c
drivers/net/wireless/iwlwifi/dvm/tx.c
+1
-0
drivers/net/wireless/iwlwifi/iwl-config.h
drivers/net/wireless/iwlwifi/iwl-config.h
+6
-0
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
+2
-1
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/iwl-prph.h
+3
-0
drivers/net/wireless/iwlwifi/mvm/Makefile
drivers/net/wireless/iwlwifi/mvm/Makefile
+1
-0
drivers/net/wireless/iwlwifi/mvm/bt-coex.c
drivers/net/wireless/iwlwifi/mvm/bt-coex.c
+7
-6
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/d3.c
+27
-11
drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
+190
-0
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/debugfs.c
+47
-589
drivers/net/wireless/iwlwifi/mvm/debugfs.h
drivers/net/wireless/iwlwifi/mvm/debugfs.h
+101
-0
drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h
drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h
+1
-0
drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
+25
-2
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
+2
-3
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+42
-9
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
+16
-3
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/mvm.h
+8
-3
drivers/net/wireless/iwlwifi/mvm/nvm.c
drivers/net/wireless/iwlwifi/mvm/nvm.c
+23
-0
drivers/net/wireless/iwlwifi/mvm/quota.c
drivers/net/wireless/iwlwifi/mvm/quota.c
+1
-2
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/rs.c
+874
-807
drivers/net/wireless/iwlwifi/mvm/rs.h
drivers/net/wireless/iwlwifi/mvm/rs.h
+70
-80
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/scan.c
+40
-15
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/net/wireless/iwlwifi/mvm/sta.c
+7
-7
drivers/net/wireless/iwlwifi/mvm/sta.h
drivers/net/wireless/iwlwifi/mvm/sta.h
+6
-0
drivers/net/wireless/iwlwifi/mvm/tt.c
drivers/net/wireless/iwlwifi/mvm/tt.c
+1
-1
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/iwlwifi/mvm/tx.c
+6
-5
drivers/net/wireless/iwlwifi/mvm/utils.c
drivers/net/wireless/iwlwifi/mvm/utils.c
+2
-6
drivers/net/wireless/iwlwifi/pcie/drv.c
drivers/net/wireless/iwlwifi/pcie/drv.c
+5
-0
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/iwlwifi/pcie/rx.c
+11
-15
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/iwlwifi/pcie/tx.c
+13
-20
No files found.
drivers/net/wireless/iwlwifi/dvm/rs.h
View file @
d9a577c3
...
...
@@ -389,13 +389,6 @@ struct iwl_lq_sta {
u8
last_bt_traffic
;
};
static
inline
u8
num_of_ant
(
u8
mask
)
{
return
!!
((
mask
)
&
ANT_A
)
+
!!
((
mask
)
&
ANT_B
)
+
!!
((
mask
)
&
ANT_C
);
}
static
inline
u8
first_antenna
(
u8
mask
)
{
if
(
mask
&
ANT_A
)
...
...
drivers/net/wireless/iwlwifi/dvm/tx.c
View file @
d9a577c3
...
...
@@ -368,6 +368,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv,
goto
drop_unlock_priv
;
memset
(
dev_cmd
,
0
,
sizeof
(
*
dev_cmd
));
dev_cmd
->
hdr
.
cmd
=
REPLY_TX
;
tx_cmd
=
(
struct
iwl_tx_cmd
*
)
dev_cmd
->
payload
;
/* Total # bytes to be transmitted */
...
...
drivers/net/wireless/iwlwifi/iwl-config.h
View file @
d9a577c3
...
...
@@ -129,6 +129,12 @@ enum iwl_led_mode {
#define ANT_BC (ANT_B | ANT_C)
#define ANT_ABC (ANT_A | ANT_B | ANT_C)
static
inline
u8
num_of_ant
(
u8
mask
)
{
return
!!
((
mask
)
&
ANT_A
)
+
!!
((
mask
)
&
ANT_B
)
+
!!
((
mask
)
&
ANT_C
);
}
/*
* @max_ll_items: max number of OTP blocks
...
...
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
View file @
d9a577c3
...
...
@@ -283,7 +283,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
IEEE80211_VHT_MCS_NOT_SUPPORTED
<<
12
|
IEEE80211_VHT_MCS_NOT_SUPPORTED
<<
14
);
if
(
data
->
valid_rx_ant
==
1
||
cfg
->
rx_with_siso_diversity
)
{
if
(
num_of_ant
(
data
->
valid_rx_ant
)
==
1
||
cfg
->
rx_with_siso_diversity
)
{
vht_cap
->
cap
|=
IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN
|
IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN
;
/* this works because NOT_SUPPORTED == 3 */
...
...
drivers/net/wireless/iwlwifi/iwl-prph.h
View file @
d9a577c3
...
...
@@ -102,6 +102,9 @@
/* Device system time */
#define DEVICE_SYSTEM_TIME_REG 0xA0206C
/* Device NMI register */
#define DEVICE_SET_NMI_REG 0x00a01c30
/*****************************************************************************
* 7000/3000 series SHR DTS addresses *
*****************************************************************************/
...
...
drivers/net/wireless/iwlwifi/mvm/Makefile
View file @
d9a577c3
...
...
@@ -5,6 +5,7 @@ iwlmvm-y += scan.o time-event.o rs.o
iwlmvm-y
+=
power.o power_legacy.o bt-coex.o
iwlmvm-y
+=
led.o tt.o
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS)
+=
debugfs.o
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS)
+=
debugfs.o debugfs-vif.o
iwlmvm-$(CONFIG_PM_SLEEP)
+=
d3.o
ccflags-y
+=
-D__CHECK_ENDIAN__
-I
$(src)
/../
drivers/net/wireless/iwlwifi/mvm/bt-coex.c
View file @
d9a577c3
...
...
@@ -396,7 +396,8 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
BT_VALID_ANT_ISOLATION
|
BT_VALID_ANT_ISOLATION_THRS
|
BT_VALID_TXTX_DELTA_FREQ_THRS
|
BT_VALID_TXRX_MAX_FREQ_0
);
BT_VALID_TXRX_MAX_FREQ_0
|
BT_VALID_SYNC_TO_SCO
);
if
(
mvm
->
cfg
->
bt_shared_single_ant
)
memcpy
(
&
bt_cmd
->
decision_lut
,
iwl_single_shared_ant
,
...
...
@@ -514,7 +515,7 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
if
(
IS_ERR_OR_NULL
(
sta
))
return
0
;
mvmsta
=
(
void
*
)
sta
->
drv_priv
;
mvmsta
=
iwl_mvm_sta_from_mac80211
(
sta
)
;
/* nothing to do */
if
(
mvmsta
->
bt_reduced_txpower
==
enable
)
...
...
@@ -846,7 +847,7 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
if
(
IS_ERR_OR_NULL
(
sta
))
return
;
mvmsta
=
(
void
*
)
sta
->
drv_priv
;
mvmsta
=
iwl_mvm_sta_from_mac80211
(
sta
)
;
data
->
num_bss_ifaces
++
;
...
...
@@ -917,11 +918,11 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
u16
iwl_mvm_bt_coex_agg_time_limit
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
)
{
struct
iwl_mvm_sta
*
mvmsta
=
(
void
*
)
sta
->
drv_priv
;
struct
iwl_mvm_sta
*
mvmsta
=
iwl_mvm_sta_from_mac80211
(
sta
)
;
enum
iwl_bt_coex_lut_type
lut_type
;
if
(
le32_to_cpu
(
mvm
->
last_bt_notif
.
bt_activity_grading
)
<
BT_
LOW
_TRAFFIC
)
BT_
HIGH
_TRAFFIC
)
return
LINK_QUAL_AGG_TIME_LIMIT_DEF
;
lut_type
=
iwl_get_coex_type
(
mvm
,
mvmsta
->
vif
);
...
...
@@ -936,7 +937,7 @@ u16 iwl_mvm_bt_coex_agg_time_limit(struct iwl_mvm *mvm,
bool
iwl_mvm_bt_coex_is_mimo_allowed
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
)
{
struct
iwl_mvm_sta
*
mvmsta
=
(
void
*
)
sta
->
drv_priv
;
struct
iwl_mvm_sta
*
mvmsta
=
iwl_mvm_sta_from_mac80211
(
sta
)
;
if
(
le32_to_cpu
(
mvm
->
last_bt_notif
.
bt_activity_grading
)
<
BT_HIGH_TRAFFIC
)
...
...
drivers/net/wireless/iwlwifi/mvm/d3.c
View file @
d9a577c3
...
...
@@ -1216,10 +1216,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
if
(
len
>=
sizeof
(
u32
)
*
2
)
{
mvm
->
d3_test_pme_ptr
=
le32_to_cpup
((
__le32
*
)
d3_cfg_cmd
.
resp_pkt
->
data
);
}
else
if
(
test
)
{
/* in test mode we require the pointer */
ret
=
-
EIO
;
goto
out
;
}
#endif
iwl_free_resp
(
&
d3_cfg_cmd
);
...
...
@@ -1231,10 +1227,11 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
mvm
->
aux_sta
.
sta_id
=
old_aux_sta_id
;
mvm_ap_sta
->
sta_id
=
old_ap_sta_id
;
mvmvif
->
ap_sta_id
=
old_ap_sta_id
;
out_noreset:
kfree
(
key_data
.
rsc_tsc
);
if
(
ret
<
0
)
ieee80211_restart_hw
(
mvm
->
hw
);
out_noreset:
kfree
(
key_data
.
rsc_tsc
);
mutex_unlock
(
&
mvm
->
mutex
);
...
...
@@ -1537,10 +1534,16 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
struct
iwl_mvm_d3_gtk_iter_data
gtkdata
=
{
.
status
=
status
,
};
u32
disconnection_reasons
=
IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON
|
IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH
;
if
(
!
status
||
!
vif
->
bss_conf
.
bssid
)
return
false
;
if
(
le32_to_cpu
(
status
->
wakeup_reasons
)
&
disconnection_reasons
)
return
false
;
/* find last GTK that we used initially, if any */
gtkdata
.
find_phase
=
true
;
ieee80211_iter_keys
(
mvm
->
hw
,
vif
,
...
...
@@ -1805,6 +1808,10 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
iwl_mvm_read_d3_sram
(
mvm
);
keep
=
iwl_mvm_query_wakeup_reasons
(
mvm
,
vif
);
#ifdef CONFIG_IWLWIFI_DEBUGFS
if
(
keep
)
mvm
->
keep_vif
=
vif
;
#endif
/* has unlocked the mutex, so skip that */
goto
out
;
...
...
@@ -1861,6 +1868,7 @@ static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file)
return
err
;
}
mvm
->
d3_test_active
=
true
;
mvm
->
keep_vif
=
NULL
;
return
0
;
}
...
...
@@ -1871,10 +1879,14 @@ static ssize_t iwl_mvm_d3_test_read(struct file *file, char __user *user_buf,
u32
pme_asserted
;
while
(
true
)
{
/* read pme_ptr if available */
if
(
mvm
->
d3_test_pme_ptr
)
{
pme_asserted
=
iwl_trans_read_mem32
(
mvm
->
trans
,
mvm
->
d3_test_pme_ptr
);
if
(
pme_asserted
)
break
;
}
if
(
msleep_interruptible
(
100
))
break
;
}
...
...
@@ -1885,6 +1897,10 @@ static ssize_t iwl_mvm_d3_test_read(struct file *file, char __user *user_buf,
static
void
iwl_mvm_d3_test_disconn_work_iter
(
void
*
_data
,
u8
*
mac
,
struct
ieee80211_vif
*
vif
)
{
/* skip the one we keep connection on */
if
(
_data
==
vif
)
return
;
if
(
vif
->
type
==
NL80211_IFTYPE_STATION
)
ieee80211_connection_loss
(
vif
);
}
...
...
@@ -1911,7 +1927,7 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)
ieee80211_iterate_active_interfaces_atomic
(
mvm
->
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
iwl_mvm_d3_test_disconn_work_iter
,
NULL
);
iwl_mvm_d3_test_disconn_work_iter
,
mvm
->
keep_vif
);
ieee80211_wake_queues
(
mvm
->
hw
);
...
...
drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
0 → 100644
View file @
d9a577c3
/******************************************************************************
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
*
* Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
#include "mvm.h"
#include "debugfs.h"
static
ssize_t
iwl_dbgfs_mac_params_read
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ieee80211_vif
*
vif
=
file
->
private_data
;
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_mvm
*
mvm
=
mvmvif
->
mvm
;
u8
ap_sta_id
;
struct
ieee80211_chanctx_conf
*
chanctx_conf
;
char
buf
[
512
];
int
bufsz
=
sizeof
(
buf
);
int
pos
=
0
;
int
i
;
mutex_lock
(
&
mvm
->
mutex
);
ap_sta_id
=
mvmvif
->
ap_sta_id
;
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"mac id/color: %d / %d
\n
"
,
mvmvif
->
id
,
mvmvif
->
color
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bssid: %pM
\n
"
,
vif
->
bss_conf
.
bssid
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"QoS:
\n
"
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
mvmvif
->
queue_params
);
i
++
)
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"
\t
%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d
\n
"
,
i
,
mvmvif
->
queue_params
[
i
].
txop
,
mvmvif
->
queue_params
[
i
].
cw_min
,
mvmvif
->
queue_params
[
i
].
cw_max
,
mvmvif
->
queue_params
[
i
].
aifs
,
mvmvif
->
queue_params
[
i
].
uapsd
);
if
(
vif
->
type
==
NL80211_IFTYPE_STATION
&&
ap_sta_id
!=
IWL_MVM_STATION_COUNT
)
{
struct
ieee80211_sta
*
sta
;
struct
iwl_mvm_sta
*
mvm_sta
;
sta
=
rcu_dereference_protected
(
mvm
->
fw_id_to_mac_id
[
ap_sta_id
],
lockdep_is_held
(
&
mvm
->
mutex
));
mvm_sta
=
(
void
*
)
sta
->
drv_priv
;
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"ap_sta_id %d - reduced Tx power %d
\n
"
,
ap_sta_id
,
mvm_sta
->
bt_reduced_txpower
);
}
rcu_read_lock
();
chanctx_conf
=
rcu_dereference
(
vif
->
chanctx_conf
);
if
(
chanctx_conf
)
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"idle rx chains %d, active rx chains: %d
\n
"
,
chanctx_conf
->
rx_chains_static
,
chanctx_conf
->
rx_chains_dynamic
);
rcu_read_unlock
();
mutex_unlock
(
&
mvm
->
mutex
);
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
pos
);
}
#define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do { \
if (!debugfs_create_file(#name, mode, parent, vif, \
&iwl_dbgfs_##name##_ops)) \
goto err; \
} while (0)
MVM_DEBUGFS_READ_FILE_OPS
(
mac_params
);
void
iwl_mvm_vif_dbgfs_register
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
struct
dentry
*
dbgfs_dir
=
vif
->
debugfs_dir
;
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
char
buf
[
100
];
/*
* Check if debugfs directory already exist before creating it.
* This may happen when, for example, resetting hw or suspend-resume
*/
if
(
!
dbgfs_dir
||
mvmvif
->
dbgfs_dir
)
return
;
mvmvif
->
dbgfs_dir
=
debugfs_create_dir
(
"iwlmvm"
,
dbgfs_dir
);
mvmvif
->
mvm
=
mvm
;
if
(
!
mvmvif
->
dbgfs_dir
)
{
IWL_ERR
(
mvm
,
"Failed to create debugfs directory under %s
\n
"
,
dbgfs_dir
->
d_name
.
name
);
return
;
}
MVM_DEBUGFS_ADD_FILE_VIF
(
mac_params
,
mvmvif
->
dbgfs_dir
,
S_IRUSR
);
/*
* Create symlink for convenience pointing to interface specific
* debugfs entries for the driver. For example, under
* /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/
* find
* netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/
*/
snprintf
(
buf
,
100
,
"../../../%s/%s/%s/%s"
,
dbgfs_dir
->
d_parent
->
d_parent
->
d_name
.
name
,
dbgfs_dir
->
d_parent
->
d_name
.
name
,
dbgfs_dir
->
d_name
.
name
,
mvmvif
->
dbgfs_dir
->
d_name
.
name
);
mvmvif
->
dbgfs_slink
=
debugfs_create_symlink
(
dbgfs_dir
->
d_name
.
name
,
mvm
->
debugfs_dir
,
buf
);
if
(
!
mvmvif
->
dbgfs_slink
)
IWL_ERR
(
mvm
,
"Can't create debugfs symbolic link under %s
\n
"
,
dbgfs_dir
->
d_name
.
name
);
return
;
err:
IWL_ERR
(
mvm
,
"Can't create debugfs entity
\n
"
);
}
void
iwl_mvm_vif_dbgfs_clean
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
debugfs_remove
(
mvmvif
->
dbgfs_slink
);
mvmvif
->
dbgfs_slink
=
NULL
;
debugfs_remove_recursive
(
mvmvif
->
dbgfs_dir
);
mvmvif
->
dbgfs_dir
=
NULL
;
}
drivers/net/wireless/iwlwifi/mvm/debugfs.c
View file @
d9a577c3
...
...
@@ -63,30 +63,18 @@
#include "mvm.h"
#include "sta.h"
#include "iwl-io.h"
#include "iwl-prph.h"
#include "debugfs.h"
struct
iwl_dbgfs_mvm_ctx
{
struct
iwl_mvm
*
mvm
;
struct
ieee80211_vif
*
vif
;
};
static
ssize_t
iwl_dbgfs_tx_flush_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
static
ssize_t
iwl_dbgfs_tx_flush_write
(
struct
iwl_mvm
*
mvm
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
iwl_mvm
*
mvm
=
file
->
private_data
;
char
buf
[
16
];
int
buf_size
,
ret
;
int
ret
;
u32
scd_q_msk
;
if
(
!
mvm
->
ucode_loaded
||
mvm
->
cur_ucode
!=
IWL_UCODE_REGULAR
)
return
-
EIO
;
memset
(
buf
,
0
,
sizeof
(
buf
));
buf_size
=
min
(
count
,
sizeof
(
buf
)
-
1
);
if
(
copy_from_user
(
buf
,
user_buf
,
buf_size
))
return
-
EFAULT
;
if
(
sscanf
(
buf
,
"%x"
,
&
scd_q_msk
)
!=
1
)
return
-
EINVAL
;
...
...
@@ -99,24 +87,15 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct file *file,
return
ret
;
}
static
ssize_t
iwl_dbgfs_sta_drain_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
static
ssize_t
iwl_dbgfs_sta_drain_write
(
struct
iwl_mvm
*
mvm
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
iwl_mvm
*
mvm
=
file
->
private_data
;
struct
ieee80211_sta
*
sta
;
char
buf
[
8
];
int
buf_size
,
sta_id
,
drain
,
ret
;
int
sta_id
,
drain
,
ret
;
if
(
!
mvm
->
ucode_loaded
||
mvm
->
cur_ucode
!=
IWL_UCODE_REGULAR
)
return
-
EIO
;
memset
(
buf
,
0
,
sizeof
(
buf
));
buf_size
=
min
(
count
,
sizeof
(
buf
)
-
1
);
if
(
copy_from_user
(
buf
,
user_buf
,
buf_size
))
return
-
EFAULT
;
if
(
sscanf
(
buf
,
"%d %d"
,
&
sta_id
,
&
drain
)
!=
2
)
return
-
EINVAL
;
if
(
sta_id
<
0
||
sta_id
>=
IWL_MVM_STATION_COUNT
)
...
...
@@ -194,20 +173,11 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
return
ret
;
}
static
ssize_t
iwl_dbgfs_sram_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
static
ssize_t
iwl_dbgfs_sram_write
(
struct
iwl_mvm
*
mvm
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
iwl_mvm
*
mvm
=
file
->
private_data
;
char
buf
[
64
];
int
buf_size
;
u32
offset
,
len
;
memset
(
buf
,
0
,
sizeof
(
buf
));
buf_size
=
min
(
count
,
sizeof
(
buf
)
-
1
);
if
(
copy_from_user
(
buf
,
user_buf
,
buf_size
))
return
-
EFAULT
;
if
(
sscanf
(
buf
,
"%x,%x"
,
&
offset
,
&
len
)
==
2
)
{
if
((
offset
&
0x3
)
||
(
len
&
0x3
))
return
-
EINVAL
;
...
...
@@ -267,22 +237,14 @@ static ssize_t iwl_dbgfs_disable_power_off_read(struct file *file,
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
pos
);
}
static
ssize_t
iwl_dbgfs_disable_power_off_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
static
ssize_t
iwl_dbgfs_disable_power_off_write
(
struct
iwl_mvm
*
mvm
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
iwl_mvm
*
mvm
=
file
->
private_data
;
char
buf
[
64
]
=
{};
int
ret
;
int
val
;
int
ret
,
val
;
if
(
!
mvm
->
ucode_loaded
)
return
-
EIO
;
count
=
min_t
(
size_t
,
count
,
sizeof
(
buf
)
-
1
);
if
(
copy_from_user
(
buf
,
user_buf
,
count
))
return
-
EFAULT
;
if
(
!
strncmp
(
"disable_power_off_d0="
,
buf
,
21
))
{
if
(
sscanf
(
buf
+
21
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
...
...
@@ -302,212 +264,6 @@ static ssize_t iwl_dbgfs_disable_power_off_write(struct file *file,
return
ret
?:
count
;
}
static
void
iwl_dbgfs_update_pm
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
enum
iwl_dbgfs_pm_mask
param
,
int
val
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_dbgfs_pm
*
dbgfs_pm
=
&
mvmvif
->
dbgfs_pm
;
dbgfs_pm
->
mask
|=
param
;
switch
(
param
)
{
case
MVM_DEBUGFS_PM_KEEP_ALIVE
:
{
struct
ieee80211_hw
*
hw
=
mvm
->
hw
;
int
dtimper
=
hw
->
conf
.
ps_dtim_period
?:
1
;
int
dtimper_msec
=
dtimper
*
vif
->
bss_conf
.
beacon_int
;
IWL_DEBUG_POWER
(
mvm
,
"debugfs: set keep_alive= %d sec
\n
"
,
val
);
if
(
val
*
MSEC_PER_SEC
<
3
*
dtimper_msec
)
{
IWL_WARN
(
mvm
,
"debugfs: keep alive period (%ld msec) is less than minimum required (%d msec)
\n
"
,
val
*
MSEC_PER_SEC
,
3
*
dtimper_msec
);
}
dbgfs_pm
->
keep_alive_seconds
=
val
;
break
;
}
case
MVM_DEBUGFS_PM_SKIP_OVER_DTIM
:
IWL_DEBUG_POWER
(
mvm
,
"skip_over_dtim %s
\n
"
,
val
?
"enabled"
:
"disabled"
);
dbgfs_pm
->
skip_over_dtim
=
val
;
break
;
case
MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS
:
IWL_DEBUG_POWER
(
mvm
,
"skip_dtim_periods=%d
\n
"
,
val
);
dbgfs_pm
->
skip_dtim_periods
=
val
;
break
;
case
MVM_DEBUGFS_PM_RX_DATA_TIMEOUT
:
IWL_DEBUG_POWER
(
mvm
,
"rx_data_timeout=%d
\n
"
,
val
);
dbgfs_pm
->
rx_data_timeout
=
val
;
break
;
case
MVM_DEBUGFS_PM_TX_DATA_TIMEOUT
:
IWL_DEBUG_POWER
(
mvm
,
"tx_data_timeout=%d
\n
"
,
val
);
dbgfs_pm
->
tx_data_timeout
=
val
;
break
;
case
MVM_DEBUGFS_PM_DISABLE_POWER_OFF
:
IWL_DEBUG_POWER
(
mvm
,
"disable_power_off=%d
\n
"
,
val
);
dbgfs_pm
->
disable_power_off
=
val
;
break
;
case
MVM_DEBUGFS_PM_LPRX_ENA
:
IWL_DEBUG_POWER
(
mvm
,
"lprx %s
\n
"
,
val
?
"enabled"
:
"disabled"
);
dbgfs_pm
->
lprx_ena
=
val
;
break
;
case
MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD
:
IWL_DEBUG_POWER
(
mvm
,
"lprx_rssi_threshold=%d
\n
"
,
val
);
dbgfs_pm
->
lprx_rssi_threshold
=
val
;
break
;
case
MVM_DEBUGFS_PM_SNOOZE_ENABLE
:
IWL_DEBUG_POWER
(
mvm
,
"snooze_enable=%d
\n
"
,
val
);
dbgfs_pm
->
snooze_ena
=
val
;
break
;
}
}
static
ssize_t
iwl_dbgfs_pm_params_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ieee80211_vif
*
vif
=
file
->
private_data
;
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_mvm
*
mvm
=
mvmvif
->
dbgfs_data
;
enum
iwl_dbgfs_pm_mask
param
;
char
buf
[
32
]
=
{};
int
val
;
int
ret
;
count
=
min_t
(
size_t
,
count
,
sizeof
(
buf
)
-
1
);
if
(
copy_from_user
(
buf
,
user_buf
,
count
))
return
-
EFAULT
;
if
(
!
strncmp
(
"keep_alive="
,
buf
,
11
))
{
if
(
sscanf
(
buf
+
11
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_PM_KEEP_ALIVE
;
}
else
if
(
!
strncmp
(
"skip_over_dtim="
,
buf
,
15
))
{
if
(
sscanf
(
buf
+
15
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_PM_SKIP_OVER_DTIM
;
}
else
if
(
!
strncmp
(
"skip_dtim_periods="
,
buf
,
18
))
{
if
(
sscanf
(
buf
+
18
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS
;
}
else
if
(
!
strncmp
(
"rx_data_timeout="
,
buf
,
16
))
{
if
(
sscanf
(
buf
+
16
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_PM_RX_DATA_TIMEOUT
;
}
else
if
(
!
strncmp
(
"tx_data_timeout="
,
buf
,
16
))
{
if
(
sscanf
(
buf
+
16
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_PM_TX_DATA_TIMEOUT
;
}
else
if
(
!
strncmp
(
"disable_power_off="
,
buf
,
18
)
&&
!
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD
))
{
if
(
sscanf
(
buf
+
18
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_PM_DISABLE_POWER_OFF
;
}
else
if
(
!
strncmp
(
"lprx="
,
buf
,
5
))
{
if
(
sscanf
(
buf
+
5
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_PM_LPRX_ENA
;
}
else
if
(
!
strncmp
(
"lprx_rssi_threshold="
,
buf
,
20
))
{
if
(
sscanf
(
buf
+
20
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
if
(
val
>
POWER_LPRX_RSSI_THRESHOLD_MAX
||
val
<
POWER_LPRX_RSSI_THRESHOLD_MIN
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD
;
}
else
if
(
!
strncmp
(
"snooze_enable="
,
buf
,
14
))
{
if
(
sscanf
(
buf
+
14
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_PM_SNOOZE_ENABLE
;
}
else
{
return
-
EINVAL
;
}
mutex_lock
(
&
mvm
->
mutex
);
iwl_dbgfs_update_pm
(
mvm
,
vif
,
param
,
val
);
ret
=
iwl_mvm_power_update_mode
(
mvm
,
vif
);
mutex_unlock
(
&
mvm
->
mutex
);
return
ret
?:
count
;
}
static
ssize_t
iwl_dbgfs_pm_params_read
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ieee80211_vif
*
vif
=
file
->
private_data
;
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_mvm
*
mvm
=
mvmvif
->
dbgfs_data
;
char
buf
[
512
];
int
bufsz
=
sizeof
(
buf
);
int
pos
;
pos
=
iwl_mvm_power_dbgfs_read
(
mvm
,
vif
,
buf
,
bufsz
);
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
pos
);
}
static
ssize_t
iwl_dbgfs_mac_params_read
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ieee80211_vif
*
vif
=
file
->
private_data
;
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_mvm
*
mvm
=
mvmvif
->
dbgfs_data
;
u8
ap_sta_id
;
struct
ieee80211_chanctx_conf
*
chanctx_conf
;
char
buf
[
512
];
int
bufsz
=
sizeof
(
buf
);
int
pos
=
0
;
int
i
;
mutex_lock
(
&
mvm
->
mutex
);
ap_sta_id
=
mvmvif
->
ap_sta_id
;
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"mac id/color: %d / %d
\n
"
,
mvmvif
->
id
,
mvmvif
->
color
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bssid: %pM
\n
"
,
vif
->
bss_conf
.
bssid
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"QoS:
\n
"
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
mvmvif
->
queue_params
);
i
++
)
{
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"
\t
%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d
\n
"
,
i
,
mvmvif
->
queue_params
[
i
].
txop
,
mvmvif
->
queue_params
[
i
].
cw_min
,
mvmvif
->
queue_params
[
i
].
cw_max
,
mvmvif
->
queue_params
[
i
].
aifs
,
mvmvif
->
queue_params
[
i
].
uapsd
);
}
if
(
vif
->
type
==
NL80211_IFTYPE_STATION
&&
ap_sta_id
!=
IWL_MVM_STATION_COUNT
)
{
struct
ieee80211_sta
*
sta
;
struct
iwl_mvm_sta
*
mvm_sta
;
sta
=
rcu_dereference_protected
(
mvm
->
fw_id_to_mac_id
[
ap_sta_id
],
lockdep_is_held
(
&
mvm
->
mutex
));
mvm_sta
=
(
void
*
)
sta
->
drv_priv
;
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"ap_sta_id %d - reduced Tx power %d
\n
"
,
ap_sta_id
,
mvm_sta
->
bt_reduced_txpower
);
}
rcu_read_lock
();
chanctx_conf
=
rcu_dereference
(
vif
->
chanctx_conf
);
if
(
chanctx_conf
)
{
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"idle rx chains %d, active rx chains: %d
\n
"
,
chanctx_conf
->
rx_chains_static
,
chanctx_conf
->
rx_chains_dynamic
);
}
rcu_read_unlock
();
mutex_unlock
(
&
mvm
->
mutex
);
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
pos
);
}
#define BT_MBOX_MSG(_notif, _num, _field) \
((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\
>> BT_MBOX##_num##_##_field##_POS)
...
...
@@ -783,11 +539,9 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file,
}
#undef PRINT_STAT_LE32
static
ssize_t
iwl_dbgfs_fw_restart_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
static
ssize_t
iwl_dbgfs_fw_restart_write
(
struct
iwl_mvm
*
mvm
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
iwl_mvm
*
mvm
=
file
->
private_data
;
int
ret
;
mutex_lock
(
&
mvm
->
mutex
);
...
...
@@ -804,6 +558,14 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct file *file,
return
count
;
}
static
ssize_t
iwl_dbgfs_fw_nmi_write
(
struct
iwl_mvm
*
mvm
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
iwl_write_prph
(
mvm
->
trans
,
DEVICE_SET_NMI_REG
,
1
);
return
count
;
}
static
ssize_t
iwl_dbgfs_scan_ant_rxchain_read
(
struct
file
*
file
,
char
__user
*
user_buf
,
...
...
@@ -828,21 +590,11 @@ iwl_dbgfs_scan_ant_rxchain_read(struct file *file,
}
static
ssize_t
iwl_dbgfs_scan_ant_rxchain_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
iwl_dbgfs_scan_ant_rxchain_write
(
struct
iwl_mvm
*
mvm
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
iwl_mvm
*
mvm
=
file
->
private_data
;
char
buf
[
8
];
int
buf_size
;
u8
scan_rx_ant
;
memset
(
buf
,
0
,
sizeof
(
buf
));
buf_size
=
min
(
count
,
sizeof
(
buf
)
-
1
);
/* get the argument from the user and check if it is valid */
if
(
copy_from_user
(
buf
,
user_buf
,
buf_size
))
return
-
EFAULT
;
if
(
sscanf
(
buf
,
"%hhx"
,
&
scan_rx_ant
)
!=
1
)
return
-
EINVAL
;
if
(
scan_rx_ant
>
ANT_ABC
)
...
...
@@ -850,228 +602,17 @@ iwl_dbgfs_scan_ant_rxchain_write(struct file *file,
if
(
scan_rx_ant
&
~
iwl_fw_valid_rx_ant
(
mvm
->
fw
))
return
-
EINVAL
;
/* change the rx antennas for scan command */
mvm
->
scan_rx_ant
=
scan_rx_ant
;
return
count
;
}
static
void
iwl_dbgfs_update_bf
(
struct
ieee80211_vif
*
vif
,
enum
iwl_dbgfs_bf_mask
param
,
int
value
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_dbgfs_bf
*
dbgfs_bf
=
&
mvmvif
->
dbgfs_bf
;
dbgfs_bf
->
mask
|=
param
;
switch
(
param
)
{
case
MVM_DEBUGFS_BF_ENERGY_DELTA
:
dbgfs_bf
->
bf_energy_delta
=
value
;
break
;
case
MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA
:
dbgfs_bf
->
bf_roaming_energy_delta
=
value
;
break
;
case
MVM_DEBUGFS_BF_ROAMING_STATE
:
dbgfs_bf
->
bf_roaming_state
=
value
;
break
;
case
MVM_DEBUGFS_BF_TEMP_THRESHOLD
:
dbgfs_bf
->
bf_temp_threshold
=
value
;
break
;
case
MVM_DEBUGFS_BF_TEMP_FAST_FILTER
:
dbgfs_bf
->
bf_temp_fast_filter
=
value
;
break
;
case
MVM_DEBUGFS_BF_TEMP_SLOW_FILTER
:
dbgfs_bf
->
bf_temp_slow_filter
=
value
;
break
;
case
MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER
:
dbgfs_bf
->
bf_enable_beacon_filter
=
value
;
break
;
case
MVM_DEBUGFS_BF_DEBUG_FLAG
:
dbgfs_bf
->
bf_debug_flag
=
value
;
break
;
case
MVM_DEBUGFS_BF_ESCAPE_TIMER
:
dbgfs_bf
->
bf_escape_timer
=
value
;
break
;
case
MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT
:
dbgfs_bf
->
ba_enable_beacon_abort
=
value
;
break
;
case
MVM_DEBUGFS_BA_ESCAPE_TIMER
:
dbgfs_bf
->
ba_escape_timer
=
value
;
break
;
}
}
static
ssize_t
iwl_dbgfs_bf_params_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ieee80211_vif
*
vif
=
file
->
private_data
;
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_mvm
*
mvm
=
mvmvif
->
dbgfs_data
;
enum
iwl_dbgfs_bf_mask
param
;
char
buf
[
256
];
int
buf_size
;
int
value
;
int
ret
=
0
;
memset
(
buf
,
0
,
sizeof
(
buf
));
buf_size
=
min
(
count
,
sizeof
(
buf
)
-
1
);
if
(
copy_from_user
(
buf
,
user_buf
,
buf_size
))
return
-
EFAULT
;
if
(
!
strncmp
(
"bf_energy_delta="
,
buf
,
16
))
{
if
(
sscanf
(
buf
+
16
,
"%d"
,
&
value
)
!=
1
)
return
-
EINVAL
;
if
(
value
<
IWL_BF_ENERGY_DELTA_MIN
||
value
>
IWL_BF_ENERGY_DELTA_MAX
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_BF_ENERGY_DELTA
;
}
else
if
(
!
strncmp
(
"bf_roaming_energy_delta="
,
buf
,
24
))
{
if
(
sscanf
(
buf
+
24
,
"%d"
,
&
value
)
!=
1
)
return
-
EINVAL
;
if
(
value
<
IWL_BF_ROAMING_ENERGY_DELTA_MIN
||
value
>
IWL_BF_ROAMING_ENERGY_DELTA_MAX
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA
;
}
else
if
(
!
strncmp
(
"bf_roaming_state="
,
buf
,
17
))
{
if
(
sscanf
(
buf
+
17
,
"%d"
,
&
value
)
!=
1
)
return
-
EINVAL
;
if
(
value
<
IWL_BF_ROAMING_STATE_MIN
||
value
>
IWL_BF_ROAMING_STATE_MAX
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_BF_ROAMING_STATE
;
}
else
if
(
!
strncmp
(
"bf_temp_threshold="
,
buf
,
18
))
{
if
(
sscanf
(
buf
+
18
,
"%d"
,
&
value
)
!=
1
)
return
-
EINVAL
;
if
(
value
<
IWL_BF_TEMP_THRESHOLD_MIN
||
value
>
IWL_BF_TEMP_THRESHOLD_MAX
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_BF_TEMP_THRESHOLD
;
}
else
if
(
!
strncmp
(
"bf_temp_fast_filter="
,
buf
,
20
))
{
if
(
sscanf
(
buf
+
20
,
"%d"
,
&
value
)
!=
1
)
return
-
EINVAL
;
if
(
value
<
IWL_BF_TEMP_FAST_FILTER_MIN
||
value
>
IWL_BF_TEMP_FAST_FILTER_MAX
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_BF_TEMP_FAST_FILTER
;
}
else
if
(
!
strncmp
(
"bf_temp_slow_filter="
,
buf
,
20
))
{
if
(
sscanf
(
buf
+
20
,
"%d"
,
&
value
)
!=
1
)
return
-
EINVAL
;
if
(
value
<
IWL_BF_TEMP_SLOW_FILTER_MIN
||
value
>
IWL_BF_TEMP_SLOW_FILTER_MAX
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_BF_TEMP_SLOW_FILTER
;
}
else
if
(
!
strncmp
(
"bf_enable_beacon_filter="
,
buf
,
24
))
{
if
(
sscanf
(
buf
+
24
,
"%d"
,
&
value
)
!=
1
)
return
-
EINVAL
;
if
(
value
<
0
||
value
>
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER
;
}
else
if
(
!
strncmp
(
"bf_debug_flag="
,
buf
,
14
))
{
if
(
sscanf
(
buf
+
14
,
"%d"
,
&
value
)
!=
1
)
return
-
EINVAL
;
if
(
value
<
0
||
value
>
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_BF_DEBUG_FLAG
;
}
else
if
(
!
strncmp
(
"bf_escape_timer="
,
buf
,
16
))
{
if
(
sscanf
(
buf
+
16
,
"%d"
,
&
value
)
!=
1
)
return
-
EINVAL
;
if
(
value
<
IWL_BF_ESCAPE_TIMER_MIN
||
value
>
IWL_BF_ESCAPE_TIMER_MAX
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_BF_ESCAPE_TIMER
;
}
else
if
(
!
strncmp
(
"ba_escape_timer="
,
buf
,
16
))
{
if
(
sscanf
(
buf
+
16
,
"%d"
,
&
value
)
!=
1
)
return
-
EINVAL
;
if
(
value
<
IWL_BA_ESCAPE_TIMER_MIN
||
value
>
IWL_BA_ESCAPE_TIMER_MAX
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_BA_ESCAPE_TIMER
;
}
else
if
(
!
strncmp
(
"ba_enable_beacon_abort="
,
buf
,
23
))
{
if
(
sscanf
(
buf
+
23
,
"%d"
,
&
value
)
!=
1
)
return
-
EINVAL
;
if
(
value
<
0
||
value
>
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT
;
}
else
{
return
-
EINVAL
;
}
mutex_lock
(
&
mvm
->
mutex
);
iwl_dbgfs_update_bf
(
vif
,
param
,
value
);
if
(
param
==
MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER
&&
!
value
)
{
ret
=
iwl_mvm_disable_beacon_filter
(
mvm
,
vif
);
}
else
{
ret
=
iwl_mvm_enable_beacon_filter
(
mvm
,
vif
);
}
mutex_unlock
(
&
mvm
->
mutex
);
return
ret
?:
count
;
}
static
ssize_t
iwl_dbgfs_bf_params_read
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ieee80211_vif
*
vif
=
file
->
private_data
;
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
char
buf
[
256
];
int
pos
=
0
;
const
size_t
bufsz
=
sizeof
(
buf
);
struct
iwl_beacon_filter_cmd
cmd
=
{
IWL_BF_CMD_CONFIG_DEFAULTS
,
.
bf_enable_beacon_filter
=
cpu_to_le32
(
IWL_BF_ENABLE_BEACON_FILTER_DEFAULT
),
.
ba_enable_beacon_abort
=
cpu_to_le32
(
IWL_BA_ENABLE_BEACON_ABORT_DEFAULT
),
};
iwl_mvm_beacon_filter_debugfs_parameters
(
vif
,
&
cmd
);
if
(
mvmvif
->
bf_data
.
bf_enabled
)
cmd
.
bf_enable_beacon_filter
=
cpu_to_le32
(
1
);
else
cmd
.
bf_enable_beacon_filter
=
0
;
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bf_energy_delta = %d
\n
"
,
le32_to_cpu
(
cmd
.
bf_energy_delta
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bf_roaming_energy_delta = %d
\n
"
,
le32_to_cpu
(
cmd
.
bf_roaming_energy_delta
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bf_roaming_state = %d
\n
"
,
le32_to_cpu
(
cmd
.
bf_roaming_state
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bf_temp_threshold = %d
\n
"
,
le32_to_cpu
(
cmd
.
bf_temp_threshold
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bf_temp_fast_filter = %d
\n
"
,
le32_to_cpu
(
cmd
.
bf_temp_fast_filter
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bf_temp_slow_filter = %d
\n
"
,
le32_to_cpu
(
cmd
.
bf_temp_slow_filter
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bf_enable_beacon_filter = %d
\n
"
,
le32_to_cpu
(
cmd
.
bf_enable_beacon_filter
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bf_debug_flag = %d
\n
"
,
le32_to_cpu
(
cmd
.
bf_debug_flag
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bf_escape_timer = %d
\n
"
,
le32_to_cpu
(
cmd
.
bf_escape_timer
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"ba_escape_timer = %d
\n
"
,
le32_to_cpu
(
cmd
.
ba_escape_timer
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"ba_enable_beacon_abort = %d
\n
"
,
le32_to_cpu
(
cmd
.
ba_enable_beacon_abort
));
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
pos
);
}
#ifdef CONFIG_PM_SLEEP
static
ssize_t
iwl_dbgfs_d3_sram_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
static
ssize_t
iwl_dbgfs_d3_sram_write
(
struct
iwl_mvm
*
mvm
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
iwl_mvm
*
mvm
=
file
->
private_data
;
char
buf
[
8
]
=
{};
int
store
;
count
=
min_t
(
size_t
,
count
,
sizeof
(
buf
)
-
1
);
if
(
copy_from_user
(
buf
,
user_buf
,
count
))
return
-
EFAULT
;
if
(
sscanf
(
buf
,
"%d"
,
&
store
)
!=
1
)
return
-
EINVAL
;
...
...
@@ -1124,61 +665,33 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf,
}
#endif
#define MVM_DEBUGFS_READ_FILE_OPS(name) \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.read = iwl_dbgfs_##name##_read, \
.open = simple_open, \
.llseek = generic_file_llseek, \
}
#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name) \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.write = iwl_dbgfs_##name##_write, \
.read = iwl_dbgfs_##name##_read, \
.open = simple_open, \
.llseek = generic_file_llseek, \
};
#define MVM_DEBUGFS_WRITE_FILE_OPS(name) \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.write = iwl_dbgfs_##name##_write, \
.open = simple_open, \
.llseek = generic_file_llseek, \
};
#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
_MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm)
#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
_MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm)
#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) do { \
if (!debugfs_create_file(#name, mode, parent, mvm, \
&iwl_dbgfs_##name##_ops)) \
goto err; \
} while (0)
#define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do { \
if (!debugfs_create_file(#name, mode, parent, vif, \
&iwl_dbgfs_##name##_ops)) \
goto err; \
} while (0)
/* Device wide debugfs entries */
MVM_DEBUGFS_WRITE_FILE_OPS
(
tx_flush
);
MVM_DEBUGFS_WRITE_FILE_OPS
(
sta_drain
);
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
sram
);
MVM_DEBUGFS_WRITE_FILE_OPS
(
tx_flush
,
16
);
MVM_DEBUGFS_WRITE_FILE_OPS
(
sta_drain
,
8
);
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
sram
,
64
);
MVM_DEBUGFS_READ_FILE_OPS
(
stations
);
MVM_DEBUGFS_READ_FILE_OPS
(
bt_notif
);
MVM_DEBUGFS_READ_FILE_OPS
(
bt_cmd
);
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
disable_power_off
);
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
disable_power_off
,
64
);
MVM_DEBUGFS_READ_FILE_OPS
(
fw_rx_stats
);
MVM_DEBUGFS_WRITE_FILE_OPS
(
fw_restart
);
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
scan_ant_rxchain
);
MVM_DEBUGFS_WRITE_FILE_OPS
(
fw_restart
,
10
);
MVM_DEBUGFS_WRITE_FILE_OPS
(
fw_nmi
,
10
);
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
scan_ant_rxchain
,
8
);
#ifdef CONFIG_PM_SLEEP
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
d3_sram
);
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
d3_sram
,
8
);
#endif
/* Interface specific debugfs entries */
MVM_DEBUGFS_READ_FILE_OPS
(
mac_params
);
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
pm_params
);
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
bf_params
);
int
iwl_mvm_dbgfs_register
(
struct
iwl_mvm
*
mvm
,
struct
dentry
*
dbgfs_dir
)
{
char
buf
[
100
];
...
...
@@ -1196,6 +709,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
S_IRUSR
|
S_IWUSR
);
MVM_DEBUGFS_ADD_FILE
(
fw_rx_stats
,
mvm
->
debugfs_dir
,
S_IRUSR
);
MVM_DEBUGFS_ADD_FILE
(
fw_restart
,
mvm
->
debugfs_dir
,
S_IWUSR
);
MVM_DEBUGFS_ADD_FILE
(
fw_nmi
,
mvm
->
debugfs_dir
,
S_IWUSR
);
MVM_DEBUGFS_ADD_FILE
(
scan_ant_rxchain
,
mvm
->
debugfs_dir
,
S_IWUSR
|
S_IRUSR
);
#ifdef CONFIG_PM_SLEEP
...
...
@@ -1206,6 +720,19 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
goto
err
;
#endif
if
(
!
debugfs_create_blob
(
"nvm_hw"
,
S_IRUSR
,
mvm
->
debugfs_dir
,
&
mvm
->
nvm_hw_blob
))
goto
err
;
if
(
!
debugfs_create_blob
(
"nvm_sw"
,
S_IRUSR
,
mvm
->
debugfs_dir
,
&
mvm
->
nvm_sw_blob
))
goto
err
;
if
(
!
debugfs_create_blob
(
"nvm_calib"
,
S_IRUSR
,
mvm
->
debugfs_dir
,
&
mvm
->
nvm_calib_blob
))
goto
err
;
if
(
!
debugfs_create_blob
(
"nvm_prod"
,
S_IRUSR
,
mvm
->
debugfs_dir
,
&
mvm
->
nvm_prod_blob
))
goto
err
;
/*
* Create a symlink with mac80211. It will be removed when mac80211
* exists (before the opmode exists which removes the target.)
...
...
@@ -1221,72 +748,3 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
IWL_ERR
(
mvm
,
"Can't create the mvm debugfs directory
\n
"
);
return
-
ENOMEM
;
}
void
iwl_mvm_vif_dbgfs_register
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
struct
dentry
*
dbgfs_dir
=
vif
->
debugfs_dir
;
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
char
buf
[
100
];
/*
* Check if debugfs directory already exist before creating it.
* This may happen when, for example, resetting hw or suspend-resume
*/
if
(
!
dbgfs_dir
||
mvmvif
->
dbgfs_dir
)
return
;
mvmvif
->
dbgfs_dir
=
debugfs_create_dir
(
"iwlmvm"
,
dbgfs_dir
);
mvmvif
->
dbgfs_data
=
mvm
;
if
(
!
mvmvif
->
dbgfs_dir
)
{
IWL_ERR
(
mvm
,
"Failed to create debugfs directory under %s
\n
"
,
dbgfs_dir
->
d_name
.
name
);
return
;
}
if
(
iwlmvm_mod_params
.
power_scheme
!=
IWL_POWER_SCHEME_CAM
&&
vif
->
type
==
NL80211_IFTYPE_STATION
&&
!
vif
->
p2p
)
MVM_DEBUGFS_ADD_FILE_VIF
(
pm_params
,
mvmvif
->
dbgfs_dir
,
S_IWUSR
|
S_IRUSR
);
MVM_DEBUGFS_ADD_FILE_VIF
(
mac_params
,
mvmvif
->
dbgfs_dir
,
S_IRUSR
);
if
(
vif
->
type
==
NL80211_IFTYPE_STATION
&&
!
vif
->
p2p
&&
mvmvif
==
mvm
->
bf_allowed_vif
)
MVM_DEBUGFS_ADD_FILE_VIF
(
bf_params
,
mvmvif
->
dbgfs_dir
,
S_IRUSR
|
S_IWUSR
);
/*
* Create symlink for convenience pointing to interface specific
* debugfs entries for the driver. For example, under
* /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/
* find
* netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/
*/
snprintf
(
buf
,
100
,
"../../../%s/%s/%s/%s"
,
dbgfs_dir
->
d_parent
->
d_parent
->
d_name
.
name
,
dbgfs_dir
->
d_parent
->
d_name
.
name
,
dbgfs_dir
->
d_name
.
name
,
mvmvif
->
dbgfs_dir
->
d_name
.
name
);
mvmvif
->
dbgfs_slink
=
debugfs_create_symlink
(
dbgfs_dir
->
d_name
.
name
,
mvm
->
debugfs_dir
,
buf
);
if
(
!
mvmvif
->
dbgfs_slink
)
IWL_ERR
(
mvm
,
"Can't create debugfs symbolic link under %s
\n
"
,
dbgfs_dir
->
d_name
.
name
);
return
;
err:
IWL_ERR
(
mvm
,
"Can't create debugfs entity
\n
"
);
}
void
iwl_mvm_vif_dbgfs_clean
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
debugfs_remove
(
mvmvif
->
dbgfs_slink
);
mvmvif
->
dbgfs_slink
=
NULL
;
debugfs_remove_recursive
(
mvmvif
->
dbgfs_dir
);
mvmvif
->
dbgfs_dir
=
NULL
;
}
drivers/net/wireless/iwlwifi/mvm/debugfs.h
0 → 100644
View file @
d9a577c3
/******************************************************************************
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
*
* Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
#define MVM_DEBUGFS_READ_FILE_OPS(name) \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.read = iwl_dbgfs_##name##_read, \
.open = simple_open, \
.llseek = generic_file_llseek, \
}
#define MVM_DEBUGFS_WRITE_WRAPPER(name, buflen, argtype) \
static ssize_t _iwl_dbgfs_##name##_write(struct file *file, \
const char __user *user_buf, \
size_t count, loff_t *ppos) \
{ \
argtype *arg = file->private_data; \
char buf[buflen] = {}; \
size_t buf_size = min(count, sizeof(buf) - 1); \
\
if (copy_from_user(buf, user_buf, buf_size)) \
return -EFAULT; \
\
return iwl_dbgfs_##name##_write(arg, buf, buf_size, ppos); \
} \
#define _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, buflen, argtype) \
MVM_DEBUGFS_WRITE_WRAPPER(name, buflen, argtype) \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.write = _iwl_dbgfs_##name##_write, \
.read = iwl_dbgfs_##name##_read, \
.open = simple_open, \
.llseek = generic_file_llseek, \
};
#define _MVM_DEBUGFS_WRITE_FILE_OPS(name, buflen, argtype) \
MVM_DEBUGFS_WRITE_WRAPPER(name, buflen, argtype) \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.write = _iwl_dbgfs_##name##_write, \
.open = simple_open, \
.llseek = generic_file_llseek, \
};
drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h
View file @
d9a577c3
...
...
@@ -127,6 +127,7 @@ enum iwl_bt_coex_valid_bit_msk {
BT_VALID_ANT_ISOLATION_THRS
=
BIT
(
15
),
BT_VALID_TXTX_DELTA_FREQ_THRS
=
BIT
(
16
),
BT_VALID_TXRX_MAX_FREQ_0
=
BIT
(
17
),
BT_VALID_SYNC_TO_SCO
=
BIT
(
18
),
};
/**
...
...
drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
View file @
d9a577c3
...
...
@@ -281,8 +281,31 @@ enum {
/* # entries in rate scale table to support Tx retries */
#define LQ_MAX_RETRY_NUM 16
/* Link quality command flags, only this one is available */
#define LQ_FLAG_SET_STA_TLC_RTS_MSK BIT(0)
/* Link quality command flags bit fields */
/* Bit 0: (0) Don't use RTS (1) Use RTS */
#define LQ_FLAG_USE_RTS_POS 0
#define LQ_FLAG_USE_RTS_MSK (1 << LQ_FLAG_USE_RTS_POS)
/* Bit 1-3: LQ command color. Used to match responses to LQ commands */
#define LQ_FLAG_COLOR_POS 1
#define LQ_FLAG_COLOR_MSK (7 << LQ_FLAG_COLOR_POS)
/* Bit 4-5: Tx RTS BW Signalling
* (0) No RTS BW signalling
* (1) Static BW signalling
* (2) Dynamic BW signalling
*/
#define LQ_FLAG_RTS_BW_SIG_POS 4
#define LQ_FLAG_RTS_BW_SIG_NONE (0 << LQ_FLAG_RTS_BW_SIG_POS)
#define LQ_FLAG_RTS_BW_SIG_STATIC (1 << LQ_FLAG_RTS_BW_SIG_POS)
#define LQ_FLAG_RTS_BW_SIG_DYNAMIC (2 << LQ_FLAG_RTS_BW_SIG_POS)
/* Bit 6: (0) No dynamic BW selection (1) Allow dynamic BW selection
* Dyanmic BW selection allows Tx with narrower BW then requested in rates
*/
#define LQ_FLAG_DYNAMIC_BW_POS 6
#define LQ_FLAG_DYNAMIC_BW_MSK (1 << LQ_FLAG_DYNAMIC_BW_POS)
/**
* struct iwl_lq_cmd - link quality command
...
...
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
View file @
d9a577c3
...
...
@@ -530,14 +530,13 @@ struct iwl_scan_offload_schedule {
/*
* iwl_scan_offload_flags
*
* IWL_SCAN_OFFLOAD_FLAG_FILTER_SSID: filter mode - upload every beacon or match
* ssid list.
* IWL_SCAN_OFFLOAD_FLAG_PASS_ALL: pass all results - no filtering.
* IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL: add cached channels to partial scan.
* IWL_SCAN_OFFLOAD_FLAG_ENERGY_SCAN: use energy based scan before partial scan
* on A band.
*/
enum
iwl_scan_offload_flags
{
IWL_SCAN_OFFLOAD_FLAG_
FILTER_SSID
=
BIT
(
0
),
IWL_SCAN_OFFLOAD_FLAG_
PASS_ALL
=
BIT
(
0
),
IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL
=
BIT
(
2
),
IWL_SCAN_OFFLOAD_FLAG_ENERGY_SCAN
=
BIT
(
3
),
};
...
...
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
View file @
d9a577c3
...
...
@@ -488,6 +488,40 @@ static void iwl_mvm_ack_rates(struct iwl_mvm *mvm,
*
ofdm_rates
=
ofdm
;
}
static
void
iwl_mvm_mac_ctxt_set_ht_flags
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
iwl_mac_ctx_cmd
*
cmd
)
{
/* for both sta and ap, ht_operation_mode hold the protection_mode */
u8
protection_mode
=
vif
->
bss_conf
.
ht_operation_mode
&
IEEE80211_HT_OP_MODE_PROTECTION
;
/* The fw does not distinguish between ht and fat */
u32
ht_flag
=
MAC_PROT_FLG_HT_PROT
|
MAC_PROT_FLG_FAT_PROT
;
IWL_DEBUG_RATE
(
mvm
,
"protection mode set to %d
\n
"
,
protection_mode
);
/*
* See section 9.23.3.1 of IEEE 80211-2012.
* Nongreenfield HT STAs Present is not supported.
*/
switch
(
protection_mode
)
{
case
IEEE80211_HT_OP_MODE_PROTECTION_NONE
:
break
;
case
IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER
:
case
IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED
:
cmd
->
protection_flags
|=
cpu_to_le32
(
ht_flag
);
break
;
case
IEEE80211_HT_OP_MODE_PROTECTION_20MHZ
:
/* Protect when channel wider than 20MHz */
if
(
vif
->
bss_conf
.
chandef
.
width
>
NL80211_CHAN_WIDTH_20
)
cmd
->
protection_flags
|=
cpu_to_le32
(
ht_flag
);
break
;
default:
IWL_ERR
(
mvm
,
"Illegal protection mode %d
\n
"
,
protection_mode
);
break
;
}
}
static
void
iwl_mvm_mac_ctxt_cmd_common
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
iwl_mac_ctx_cmd
*
cmd
,
...
...
@@ -495,6 +529,8 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
ieee80211_chanctx_conf
*
chanctx
;
bool
ht_enabled
=
!!
(
vif
->
bss_conf
.
ht_operation_mode
&
IEEE80211_HT_OP_MODE_PROTECTION
);
u8
cck_ack_rates
,
ofdm_ack_rates
;
int
i
;
...
...
@@ -573,16 +609,13 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
cmd
->
protection_flags
|=
cpu_to_le32
(
MAC_PROT_FLG_SELF_CTS_EN
);
}
/*
* I think that we should enable these 2 flags regardless the HT PROT
* fields in the HT IE, but I am not sure. Someone knows whom to ask?...
*/
if
(
vif
->
bss_conf
.
chandef
.
width
!=
NL80211_CHAN_WIDTH_20_NOHT
)
{
IWL_DEBUG_RATE
(
mvm
,
"use_cts_prot %d, ht_operation_mode %d
\n
"
,
vif
->
bss_conf
.
use_cts_prot
,
vif
->
bss_conf
.
ht_operation_mode
);
if
(
vif
->
bss_conf
.
chandef
.
width
!=
NL80211_CHAN_WIDTH_20_NOHT
)
cmd
->
qos_flags
|=
cpu_to_le32
(
MAC_QOS_FLG_TGN
);
cmd
->
protection_flags
|=
cpu_to_le32
(
MAC_PROT_FLG_HT_PROT
|
MAC_PROT_FLG_FAT_PROT
);
}
if
(
ht_enabled
)
iwl_mvm_mac_ctxt_set_ht_flags
(
mvm
,
vif
,
cmd
);
cmd
->
filter_flags
=
cpu_to_le32
(
MAC_FILTER_ACCEPT_GRP
);
}
...
...
drivers/net/wireless/iwlwifi/mvm/mac80211.c
View file @
d9a577c3
...
...
@@ -256,7 +256,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
}
hw
->
wiphy
->
features
|=
NL80211_FEATURE_P2P_GO_CTWIN
|
NL80211_FEATURE_P2P_GO_OPPPS
;
NL80211_FEATURE_P2P_GO_OPPPS
|
NL80211_FEATURE_LOW_PRIORITY_SCAN
;
mvm
->
rts_threshold
=
IEEE80211_MAX_RTS_THRESHOLD
;
...
...
@@ -990,6 +991,17 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,
struct
ieee80211_bss_conf
*
bss_conf
,
u32
changes
)
{
enum
ieee80211_bss_change
ht_change
=
BSS_CHANGED_ERP_CTS_PROT
|
BSS_CHANGED_HT
|
BSS_CHANGED_BANDWIDTH
;
int
ret
;
if
(
changes
&
ht_change
)
{
ret
=
iwl_mvm_mac_ctxt_changed
(
mvm
,
vif
);
if
(
ret
)
IWL_ERR
(
mvm
,
"failed to update MAC %pM
\n
"
,
vif
->
addr
);
}
/* Need to send a new beacon template to the FW */
if
(
changes
&
BSS_CHANGED_BEACON
)
{
if
(
iwl_mvm_mac_ctxt_beacon_changed
(
mvm
,
vif
))
...
...
@@ -1080,7 +1092,7 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
struct
ieee80211_sta
*
sta
)
{
struct
iwl_mvm
*
mvm
=
IWL_MAC80211_GET_MVM
(
hw
);
struct
iwl_mvm_sta
*
mvmsta
=
(
void
*
)
sta
->
drv_priv
;
struct
iwl_mvm_sta
*
mvmsta
=
iwl_mvm_sta_from_mac80211
(
sta
)
;
switch
(
cmd
)
{
case
STA_NOTIFY_SLEEP
:
...
...
@@ -1149,7 +1161,8 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
ret
=
iwl_mvm_update_sta
(
mvm
,
vif
,
sta
);
if
(
ret
==
0
)
iwl_mvm_rs_rate_init
(
mvm
,
sta
,
mvmvif
->
phy_ctxt
->
channel
->
band
);
mvmvif
->
phy_ctxt
->
channel
->
band
,
true
);
}
else
if
(
old_state
==
IEEE80211_STA_ASSOC
&&
new_state
==
IEEE80211_STA_AUTHORIZED
)
{
/* enable beacon filtering */
...
...
drivers/net/wireless/iwlwifi/mvm/mvm.h
View file @
d9a577c3
...
...
@@ -323,9 +323,9 @@ struct iwl_mvm_vif {
#endif
#ifdef CONFIG_IWLWIFI_DEBUGFS
struct
iwl_mvm
*
mvm
;
struct
dentry
*
dbgfs_dir
;
struct
dentry
*
dbgfs_slink
;
void
*
dbgfs_data
;
struct
iwl_dbgfs_pm
dbgfs_pm
;
struct
iwl_dbgfs_bf
dbgfs_bf
;
#endif
...
...
@@ -494,6 +494,11 @@ struct iwl_mvm {
u32
dbgfs_sram_offset
,
dbgfs_sram_len
;
bool
disable_power_off
;
bool
disable_power_off_d3
;
struct
debugfs_blob_wrapper
nvm_hw_blob
;
struct
debugfs_blob_wrapper
nvm_sw_blob
;
struct
debugfs_blob_wrapper
nvm_calib_blob
;
struct
debugfs_blob_wrapper
nvm_prod_blob
;
#endif
struct
iwl_mvm_phy_ctxt
phy_ctxts
[
NUM_PHY_CTX
];
...
...
@@ -531,6 +536,7 @@ struct iwl_mvm {
bool
store_d3_resume_sram
;
void
*
d3_resume_sram
;
u32
d3_test_pme_ptr
;
struct
ieee80211_vif
*
keep_vif
;
#endif
#endif
...
...
@@ -750,8 +756,7 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
#endif
/* CONFIG_IWLWIFI_DEBUGFS */
/* rate scaling */
int
iwl_mvm_send_lq_cmd
(
struct
iwl_mvm
*
mvm
,
struct
iwl_lq_cmd
*
lq
,
u8
flags
,
bool
init
);
int
iwl_mvm_send_lq_cmd
(
struct
iwl_mvm
*
mvm
,
struct
iwl_lq_cmd
*
lq
,
bool
init
);
/* power managment */
static
inline
int
iwl_mvm_power_update_mode
(
struct
iwl_mvm
*
mvm
,
...
...
drivers/net/wireless/iwlwifi/mvm/nvm.c
View file @
d9a577c3
...
...
@@ -443,6 +443,29 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
}
mvm
->
nvm_sections
[
section
].
data
=
temp
;
mvm
->
nvm_sections
[
section
].
length
=
ret
;
#ifdef CONFIG_IWLWIFI_DEBUGFS
switch
(
section
)
{
case
NVM_SECTION_TYPE_HW
:
mvm
->
nvm_hw_blob
.
data
=
temp
;
mvm
->
nvm_hw_blob
.
size
=
ret
;
break
;
case
NVM_SECTION_TYPE_SW
:
mvm
->
nvm_sw_blob
.
data
=
temp
;
mvm
->
nvm_sw_blob
.
size
=
ret
;
break
;
case
NVM_SECTION_TYPE_CALIBRATION
:
mvm
->
nvm_calib_blob
.
data
=
temp
;
mvm
->
nvm_calib_blob
.
size
=
ret
;
break
;
case
NVM_SECTION_TYPE_PRODUCTION
:
mvm
->
nvm_prod_blob
.
data
=
temp
;
mvm
->
nvm_prod_blob
.
size
=
ret
;
break
;
default:
WARN
(
1
,
"section: %d"
,
section
);
}
#endif
}
kfree
(
nvm_buffer
);
if
(
ret
<
0
)
...
...
drivers/net/wireless/iwlwifi/mvm/quota.c
View file @
d9a577c3
...
...
@@ -217,8 +217,7 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif)
}
else
{
cmd
.
quotas
[
idx
].
quota
=
cpu_to_le32
(
quota
*
data
.
n_interfaces
[
i
]);
cmd
.
quotas
[
idx
].
max_duration
=
cpu_to_le32
(
IWL_MVM_MAX_QUOTA
);
cmd
.
quotas
[
idx
].
max_duration
=
cpu_to_le32
(
0
);
}
idx
++
;
}
...
...
drivers/net/wireless/iwlwifi/mvm/rs.c
View file @
d9a577c3
...
...
@@ -47,28 +47,25 @@
#define IWL_HT_NUMBER_TRY 3
#define IWL_RATE_MAX_WINDOW 62
/* # tx in history window */
#define IWL_RATE_MIN_FAILURE_TH
6
/* min failures to calc tpt */
#define IWL_RATE_MIN_FAILURE_TH
3
/* min failures to calc tpt */
#define IWL_RATE_MIN_SUCCESS_TH 8
/* min successes to calc tpt */
/* max allowed rate miss before sync LQ cmd */
#define IWL_MISSED_RATE_MAX 15
/* max time to accum history 2 seconds */
#define IWL_RATE_SCALE_FLUSH_INTVL (3*HZ)
#define RS_STAY_IN_COLUMN_TIMEOUT (5*HZ)
static
u8
rs_ht_to_legacy
[]
=
{
[
IWL_RATE_1M_INDEX
]
=
IWL_RATE_6M_INDEX
,
[
IWL_RATE_2M_INDEX
]
=
IWL_RATE_6M_INDEX
,
[
IWL_RATE_5M_INDEX
]
=
IWL_RATE_6M_INDEX
,
[
IWL_RATE_11M_INDEX
]
=
IWL_RATE_6M_INDEX
,
[
IWL_RATE_6M_INDEX
]
=
IWL_RATE_6M_INDEX
,
[
IWL_RATE_9M_INDEX
]
=
IWL_RATE_6M_INDEX
,
[
IWL_RATE_12M_INDEX
]
=
IWL_RATE_9M_INDEX
,
[
IWL_RATE_18M_INDEX
]
=
IWL_RATE_12M_INDEX
,
[
IWL_RATE_24M_INDEX
]
=
IWL_RATE_18M_INDEX
,
[
IWL_RATE_36M_INDEX
]
=
IWL_RATE_24M_INDEX
,
[
IWL_RATE_48M_INDEX
]
=
IWL_RATE_36M_INDEX
,
[
IWL_RATE_54M_INDEX
]
=
IWL_RATE_48M_INDEX
,
[
IWL_RATE_60M_INDEX
]
=
IWL_RATE_54M_INDEX
,
[
IWL_RATE_MCS_0_INDEX
]
=
IWL_RATE_6M_INDEX
,
[
IWL_RATE_MCS_1_INDEX
]
=
IWL_RATE_9M_INDEX
,
[
IWL_RATE_MCS_2_INDEX
]
=
IWL_RATE_12M_INDEX
,
[
IWL_RATE_MCS_3_INDEX
]
=
IWL_RATE_18M_INDEX
,
[
IWL_RATE_MCS_4_INDEX
]
=
IWL_RATE_24M_INDEX
,
[
IWL_RATE_MCS_5_INDEX
]
=
IWL_RATE_36M_INDEX
,
[
IWL_RATE_MCS_6_INDEX
]
=
IWL_RATE_48M_INDEX
,
[
IWL_RATE_MCS_7_INDEX
]
=
IWL_RATE_54M_INDEX
,
[
IWL_RATE_MCS_8_INDEX
]
=
IWL_RATE_54M_INDEX
,
[
IWL_RATE_MCS_9_INDEX
]
=
IWL_RATE_54M_INDEX
,
};
static
const
u8
ant_toggle_lookup
[]
=
{
...
...
@@ -126,6 +123,190 @@ static const struct iwl_rs_rate_info iwl_rates[IWL_RATE_COUNT] = {
IWL_DECLARE_MCS_RATE
(
9
),
/* MCS 9 */
};
enum
rs_column_mode
{
RS_INVALID
=
0
,
RS_LEGACY
,
RS_SISO
,
RS_MIMO2
,
};
#define MAX_NEXT_COLUMNS 5
#define MAX_COLUMN_CHECKS 3
typedef
bool
(
*
allow_column_func_t
)
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
,
struct
iwl_scale_tbl_info
*
tbl
);
struct
rs_tx_column
{
enum
rs_column_mode
mode
;
u8
ant
;
bool
sgi
;
enum
rs_column
next_columns
[
MAX_NEXT_COLUMNS
];
allow_column_func_t
checks
[
MAX_COLUMN_CHECKS
];
};
static
bool
rs_mimo_allow
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
,
struct
iwl_scale_tbl_info
*
tbl
)
{
if
(
!
sta
->
ht_cap
.
ht_supported
)
return
false
;
if
(
sta
->
smps_mode
==
IEEE80211_SMPS_STATIC
)
return
false
;
if
(
num_of_ant
(
iwl_fw_valid_tx_ant
(
mvm
->
fw
))
<
2
)
return
false
;
if
(
!
iwl_mvm_bt_coex_is_mimo_allowed
(
mvm
,
sta
))
return
false
;
return
true
;
}
static
bool
rs_siso_allow
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
,
struct
iwl_scale_tbl_info
*
tbl
)
{
if
(
!
sta
->
ht_cap
.
ht_supported
)
return
false
;
return
true
;
}
static
bool
rs_sgi_allow
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
,
struct
iwl_scale_tbl_info
*
tbl
)
{
struct
rs_rate
*
rate
=
&
tbl
->
rate
;
struct
ieee80211_sta_ht_cap
*
ht_cap
=
&
sta
->
ht_cap
;
struct
ieee80211_sta_vht_cap
*
vht_cap
=
&
sta
->
vht_cap
;
if
(
is_ht20
(
rate
)
&&
(
ht_cap
->
cap
&
IEEE80211_HT_CAP_SGI_20
))
return
true
;
if
(
is_ht40
(
rate
)
&&
(
ht_cap
->
cap
&
IEEE80211_HT_CAP_SGI_40
))
return
true
;
if
(
is_ht80
(
rate
)
&&
(
vht_cap
->
cap
&
IEEE80211_VHT_CAP_SHORT_GI_80
))
return
true
;
return
false
;
}
static
const
struct
rs_tx_column
rs_tx_columns
[]
=
{
[
RS_COLUMN_LEGACY_ANT_A
]
=
{
.
mode
=
RS_LEGACY
,
.
ant
=
ANT_A
,
.
next_columns
=
{
RS_COLUMN_LEGACY_ANT_B
,
RS_COLUMN_SISO_ANT_A
,
RS_COLUMN_MIMO2
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
},
},
[
RS_COLUMN_LEGACY_ANT_B
]
=
{
.
mode
=
RS_LEGACY
,
.
ant
=
ANT_B
,
.
next_columns
=
{
RS_COLUMN_LEGACY_ANT_A
,
RS_COLUMN_SISO_ANT_B
,
RS_COLUMN_MIMO2
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
},
},
[
RS_COLUMN_SISO_ANT_A
]
=
{
.
mode
=
RS_SISO
,
.
ant
=
ANT_A
,
.
next_columns
=
{
RS_COLUMN_SISO_ANT_B
,
RS_COLUMN_MIMO2
,
RS_COLUMN_SISO_ANT_A_SGI
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
},
.
checks
=
{
rs_siso_allow
,
},
},
[
RS_COLUMN_SISO_ANT_B
]
=
{
.
mode
=
RS_SISO
,
.
ant
=
ANT_B
,
.
next_columns
=
{
RS_COLUMN_SISO_ANT_A
,
RS_COLUMN_MIMO2
,
RS_COLUMN_SISO_ANT_B_SGI
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
},
.
checks
=
{
rs_siso_allow
,
},
},
[
RS_COLUMN_SISO_ANT_A_SGI
]
=
{
.
mode
=
RS_SISO
,
.
ant
=
ANT_A
,
.
sgi
=
true
,
.
next_columns
=
{
RS_COLUMN_SISO_ANT_B_SGI
,
RS_COLUMN_MIMO2_SGI
,
RS_COLUMN_SISO_ANT_A
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
},
.
checks
=
{
rs_siso_allow
,
rs_sgi_allow
,
},
},
[
RS_COLUMN_SISO_ANT_B_SGI
]
=
{
.
mode
=
RS_SISO
,
.
ant
=
ANT_B
,
.
sgi
=
true
,
.
next_columns
=
{
RS_COLUMN_SISO_ANT_A_SGI
,
RS_COLUMN_MIMO2_SGI
,
RS_COLUMN_SISO_ANT_B
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
},
.
checks
=
{
rs_siso_allow
,
rs_sgi_allow
,
},
},
[
RS_COLUMN_MIMO2
]
=
{
.
mode
=
RS_MIMO2
,
.
ant
=
ANT_AB
,
.
next_columns
=
{
RS_COLUMN_SISO_ANT_A
,
RS_COLUMN_MIMO2_SGI
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
},
.
checks
=
{
rs_mimo_allow
,
},
},
[
RS_COLUMN_MIMO2_SGI
]
=
{
.
mode
=
RS_MIMO2
,
.
ant
=
ANT_AB
,
.
sgi
=
true
,
.
next_columns
=
{
RS_COLUMN_SISO_ANT_A_SGI
,
RS_COLUMN_MIMO2
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
},
.
checks
=
{
rs_mimo_allow
,
rs_sgi_allow
,
},
},
};
static
inline
u8
rs_extract_rate
(
u32
rate_n_flags
)
{
/* also works for HT because bits 7:6 are zero there */
...
...
@@ -175,7 +356,6 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
struct
iwl_lq_sta
*
lq_sta
,
u32
rate_n_flags
);
static
void
rs_stay_in_table
(
struct
iwl_lq_sta
*
lq_sta
,
bool
force_search
);
#ifdef CONFIG_MAC80211_DEBUGFS
static
void
rs_dbgfs_set_mcs
(
struct
iwl_lq_sta
*
lq_sta
,
u32
*
rate_n_flags
);
...
...
@@ -264,6 +444,52 @@ static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {
#define MCS_INDEX_PER_STREAM (8)
static
const
char
*
rs_pretty_ant
(
u8
ant
)
{
static
const
char
*
const
ant_name
[]
=
{
[
ANT_NONE
]
=
"None"
,
[
ANT_A
]
=
"A"
,
[
ANT_B
]
=
"B"
,
[
ANT_AB
]
=
"AB"
,
[
ANT_C
]
=
"C"
,
[
ANT_AC
]
=
"AC"
,
[
ANT_BC
]
=
"BC"
,
[
ANT_ABC
]
=
"ABC"
,
};
if
(
ant
>
ANT_ABC
)
return
"UNKNOWN"
;
return
ant_name
[
ant
];
}
static
const
char
*
rs_pretty_lq_type
(
enum
iwl_table_type
type
)
{
static
const
char
*
const
lq_types
[]
=
{
[
LQ_NONE
]
=
"NONE"
,
[
LQ_LEGACY_A
]
=
"LEGACY_A"
,
[
LQ_LEGACY_G
]
=
"LEGACY_G"
,
[
LQ_HT_SISO
]
=
"HT SISO"
,
[
LQ_HT_MIMO2
]
=
"HT MIMO"
,
[
LQ_VHT_SISO
]
=
"VHT SISO"
,
[
LQ_VHT_MIMO2
]
=
"VHT MIMO"
,
};
if
(
type
<
LQ_NONE
||
type
>=
LQ_MAX
)
return
"UNKNOWN"
;
return
lq_types
[
type
];
}
static
inline
void
rs_dump_rate
(
struct
iwl_mvm
*
mvm
,
const
struct
rs_rate
*
rate
,
const
char
*
prefix
)
{
IWL_DEBUG_RATE
(
mvm
,
"%s: (%s: %d) ANT: %s BW: %d SGI: %d
\n
"
,
prefix
,
rs_pretty_lq_type
(
rate
->
type
),
rate
->
index
,
rs_pretty_ant
(
rate
->
ant
),
rate
->
bw
,
rate
->
sgi
);
}
static
void
rs_rate_scale_clear_window
(
struct
iwl_rate_scale_data
*
window
)
{
window
->
data
=
0
;
...
...
@@ -271,7 +497,6 @@ static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
window
->
success_ratio
=
IWL_INVALID_VALUE
;
window
->
counter
=
0
;
window
->
average_tpt
=
IWL_INVALID_VALUE
;
window
->
stamp
=
0
;
}
static
inline
u8
rs_is_valid_ant
(
u8
valid_antenna
,
u8
ant_type
)
...
...
@@ -298,7 +523,7 @@ static void rs_program_fix_rate(struct iwl_mvm *mvm,
if
(
lq_sta
->
dbg_fixed_rate
)
{
rs_fill_link_cmd
(
NULL
,
NULL
,
lq_sta
,
lq_sta
->
dbg_fixed_rate
);
iwl_mvm_send_lq_cmd
(
lq_sta
->
drv
,
&
lq_sta
->
lq
,
CMD_ASYNC
,
false
);
iwl_mvm_send_lq_cmd
(
lq_sta
->
drv
,
&
lq_sta
->
lq
,
false
);
}
}
#endif
...
...
@@ -428,192 +653,174 @@ static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
else
window
->
average_tpt
=
IWL_INVALID_VALUE
;
/* Tag this window as having been updated */
window
->
stamp
=
jiffies
;
return
0
;
}
/*
* Fill uCode API rate_n_flags field, based on "search" or "active" table.
*/
/* FIXME:RS:remove this function and put the flags statically in the table */
static
u32
rate_n_flags_from_tbl
(
struct
iwl_mvm
*
mvm
,
struct
iwl_scale_tbl_info
*
tbl
,
int
index
)
/* Convert rs_rate object into ucode rate bitmask */
static
u32
ucode_rate_from_rs_rate
(
struct
iwl_mvm
*
mvm
,
struct
rs_rate
*
rate
)
{
u32
rate_n_flags
=
0
;
u32
ucode_rate
=
0
;
int
index
=
rate
->
index
;
rate_n_flags
|=
((
tbl
->
ant_type
<<
RATE_MCS_ANT_POS
)
&
ucode_rate
|=
((
rate
->
ant
<<
RATE_MCS_ANT_POS
)
&
RATE_MCS_ANT_ABC_MSK
);
if
(
is_legacy
(
tbl
->
lq_typ
e
))
{
rate_n_flags
|=
iwl_rates
[
index
].
plcp
;
if
(
is_legacy
(
rat
e
))
{
ucode_rate
|=
iwl_rates
[
index
].
plcp
;
if
(
index
>=
IWL_FIRST_CCK_RATE
&&
index
<=
IWL_LAST_CCK_RATE
)
rate_n_flags
|=
RATE_MCS_CCK_MSK
;
return
rate_n_flags
;
ucode_rate
|=
RATE_MCS_CCK_MSK
;
return
ucode_rate
;
}
if
(
is_ht
(
tbl
->
lq_typ
e
))
{
if
(
is_ht
(
rat
e
))
{
if
(
index
<
IWL_FIRST_HT_RATE
||
index
>
IWL_LAST_HT_RATE
)
{
IWL_ERR
(
mvm
,
"Invalid HT rate index %d
\n
"
,
index
);
index
=
IWL_LAST_HT_RATE
;
}
rate_n_flags
|=
RATE_MCS_HT_MSK
;
ucode_rate
|=
RATE_MCS_HT_MSK
;
if
(
is_ht_siso
(
tbl
->
lq_typ
e
))
rate_n_flags
|=
iwl_rates
[
index
].
plcp_ht_siso
;
else
if
(
is_ht_mimo2
(
tbl
->
lq_typ
e
))
rate_n_flags
|=
iwl_rates
[
index
].
plcp_ht_mimo2
;
if
(
is_ht_siso
(
rat
e
))
ucode_rate
|=
iwl_rates
[
index
].
plcp_ht_siso
;
else
if
(
is_ht_mimo2
(
rat
e
))
ucode_rate
|=
iwl_rates
[
index
].
plcp_ht_mimo2
;
else
WARN_ON_ONCE
(
1
);
}
else
if
(
is_vht
(
tbl
->
lq_typ
e
))
{
}
else
if
(
is_vht
(
rat
e
))
{
if
(
index
<
IWL_FIRST_VHT_RATE
||
index
>
IWL_LAST_VHT_RATE
)
{
IWL_ERR
(
mvm
,
"Invalid VHT rate index %d
\n
"
,
index
);
index
=
IWL_LAST_VHT_RATE
;
}
rate_n_flags
|=
RATE_MCS_VHT_MSK
;
if
(
is_vht_siso
(
tbl
->
lq_typ
e
))
rate_n_flags
|=
iwl_rates
[
index
].
plcp_vht_siso
;
else
if
(
is_vht_mimo2
(
tbl
->
lq_typ
e
))
rate_n_flags
|=
iwl_rates
[
index
].
plcp_vht_mimo2
;
ucode_rate
|=
RATE_MCS_VHT_MSK
;
if
(
is_vht_siso
(
rat
e
))
ucode_rate
|=
iwl_rates
[
index
].
plcp_vht_siso
;
else
if
(
is_vht_mimo2
(
rat
e
))
ucode_rate
|=
iwl_rates
[
index
].
plcp_vht_mimo2
;
else
WARN_ON_ONCE
(
1
);
}
else
{
IWL_ERR
(
mvm
,
"Invalid
tbl->lq_type %d
\n
"
,
tbl
->
lq_
type
);
IWL_ERR
(
mvm
,
"Invalid
rate->type %d
\n
"
,
rate
->
type
);
}
rate_n_flags
|=
tbl
->
bw
;
if
(
tbl
->
is_SGI
)
rate_n_flags
|=
RATE_MCS_SGI_MSK
;
ucode_rate
|=
rate
->
bw
;
if
(
rate
->
sgi
)
ucode_rate
|=
RATE_MCS_SGI_MSK
;
return
rate_n_flags
;
return
ucode_rate
;
}
/*
* Interpret uCode API's rate_n_flags format,
* fill "search" or "active" tx mode table.
*/
static
int
rs_get_tbl_info_from_mcs
(
const
u32
rate_n_flags
,
/* Convert a ucode rate into an rs_rate object */
static
int
rs_rate_from_ucode_rate
(
const
u32
ucode_rate
,
enum
ieee80211_band
band
,
struct
iwl_scale_tbl_info
*
tbl
,
int
*
rate_idx
)
struct
rs_rate
*
rate
)
{
u32
ant_msk
=
(
rate_n_flags
&
RATE_MCS_ANT_ABC_MSK
)
;
u8
num_of_ant
=
get_num_of_ant_from_rate
(
rate_n_flags
);
u32
ant_msk
=
ucode_rate
&
RATE_MCS_ANT_ABC_MSK
;
u8
num_of_ant
=
get_num_of_ant_from_rate
(
ucode_rate
);
u8
nss
;
memset
(
tbl
,
0
,
offsetof
(
struct
iwl_scale_tbl_info
,
win
));
*
rate_idx
=
iwl_hwrate_to_plcp_idx
(
rate_n_flags
);
memset
(
rate
,
0
,
sizeof
(
struct
rs_rate
));
rate
->
index
=
iwl_hwrate_to_plcp_idx
(
ucode_rate
);
if
(
*
rate_idx
==
IWL_RATE_INVALID
)
{
*
rate_id
x
=
-
1
;
if
(
rate
->
index
==
IWL_RATE_INVALID
)
{
rate
->
inde
x
=
-
1
;
return
-
EINVAL
;
}
tbl
->
is_SGI
=
0
;
/* default legacy setup */
tbl
->
bw
=
0
;
tbl
->
ant_type
=
(
ant_msk
>>
RATE_MCS_ANT_POS
);
tbl
->
lq_type
=
LQ_NONE
;
tbl
->
max_search
=
IWL_MAX_SEARCH
;
rate
->
ant
=
(
ant_msk
>>
RATE_MCS_ANT_POS
);
/* Legacy */
if
(
!
(
rate_n_flags
&
RATE_MCS_HT_MSK
)
&&
!
(
rate_n_flags
&
RATE_MCS_VHT_MSK
))
{
if
(
!
(
ucode_rate
&
RATE_MCS_HT_MSK
)
&&
!
(
ucode_rate
&
RATE_MCS_VHT_MSK
))
{
if
(
num_of_ant
==
1
)
{
if
(
band
==
IEEE80211_BAND_5GHZ
)
tbl
->
lq_
type
=
LQ_LEGACY_A
;
rate
->
type
=
LQ_LEGACY_A
;
else
tbl
->
lq_
type
=
LQ_LEGACY_G
;
rate
->
type
=
LQ_LEGACY_G
;
}
return
0
;
}
/* HT or VHT */
if
(
rate_n_flags
&
RATE_MCS_SGI_MSK
)
tbl
->
is_SGI
=
1
;
if
(
ucode_rate
&
RATE_MCS_SGI_MSK
)
rate
->
sgi
=
true
;
tbl
->
bw
=
rate_n_flags
&
RATE_MCS_CHAN_WIDTH_MSK
;
rate
->
bw
=
ucode_rate
&
RATE_MCS_CHAN_WIDTH_MSK
;
if
(
rate_n_flags
&
RATE_MCS_HT_MSK
)
{
nss
=
((
rate_n_flags
&
RATE_HT_MCS_NSS_MSK
)
>>
if
(
ucode_rate
&
RATE_MCS_HT_MSK
)
{
nss
=
((
ucode_rate
&
RATE_HT_MCS_NSS_MSK
)
>>
RATE_HT_MCS_NSS_POS
)
+
1
;
if
(
nss
==
1
)
{
tbl
->
lq_
type
=
LQ_HT_SISO
;
rate
->
type
=
LQ_HT_SISO
;
WARN_ON_ONCE
(
num_of_ant
!=
1
);
}
else
if
(
nss
==
2
)
{
tbl
->
lq_
type
=
LQ_HT_MIMO2
;
rate
->
type
=
LQ_HT_MIMO2
;
WARN_ON_ONCE
(
num_of_ant
!=
2
);
}
else
{
WARN_ON_ONCE
(
1
);
}
}
else
if
(
rate_n_flags
&
RATE_MCS_VHT_MSK
)
{
nss
=
((
rate_n_flags
&
RATE_VHT_MCS_NSS_MSK
)
>>
}
else
if
(
ucode_rate
&
RATE_MCS_VHT_MSK
)
{
nss
=
((
ucode_rate
&
RATE_VHT_MCS_NSS_MSK
)
>>
RATE_VHT_MCS_NSS_POS
)
+
1
;
if
(
nss
==
1
)
{
tbl
->
lq_
type
=
LQ_VHT_SISO
;
rate
->
type
=
LQ_VHT_SISO
;
WARN_ON_ONCE
(
num_of_ant
!=
1
);
}
else
if
(
nss
==
2
)
{
tbl
->
lq_
type
=
LQ_VHT_MIMO2
;
rate
->
type
=
LQ_VHT_MIMO2
;
WARN_ON_ONCE
(
num_of_ant
!=
2
);
}
else
{
WARN_ON_ONCE
(
1
);
}
}
WARN_ON_ONCE
(
tbl
->
bw
==
RATE_MCS_CHAN_WIDTH_160
);
WARN_ON_ONCE
(
tbl
->
bw
==
RATE_MCS_CHAN_WIDTH_80
&&
!
is_vht
(
tbl
->
lq_typ
e
));
WARN_ON_ONCE
(
rate
->
bw
==
RATE_MCS_CHAN_WIDTH_160
);
WARN_ON_ONCE
(
rate
->
bw
==
RATE_MCS_CHAN_WIDTH_80
&&
!
is_vht
(
rat
e
));
return
0
;
}
/* switch to another antenna/antennas and return 1 */
/* if no other valid antenna found, return 0 */
static
int
rs_toggle_antenna
(
u32
valid_ant
,
u32
*
rate_n_flags
,
struct
iwl_scale_tbl_info
*
tbl
)
static
int
rs_toggle_antenna
(
u32
valid_ant
,
u32
*
ucode_rate
,
struct
rs_rate
*
rate
)
{
u8
new_ant_type
;
if
(
!
tbl
->
ant_type
||
tbl
->
ant_type
>
ANT_ABC
)
if
(
!
rate
->
ant
||
rate
->
ant
>
ANT_ABC
)
return
0
;
if
(
!
rs_is_valid_ant
(
valid_ant
,
tbl
->
ant_type
))
if
(
!
rs_is_valid_ant
(
valid_ant
,
rate
->
ant
))
return
0
;
new_ant_type
=
ant_toggle_lookup
[
tbl
->
ant_type
];
new_ant_type
=
ant_toggle_lookup
[
rate
->
ant
];
while
((
new_ant_type
!=
tbl
->
ant_type
)
&&
while
((
new_ant_type
!=
rate
->
ant
)
&&
!
rs_is_valid_ant
(
valid_ant
,
new_ant_type
))
new_ant_type
=
ant_toggle_lookup
[
new_ant_type
];
if
(
new_ant_type
==
tbl
->
ant_type
)
if
(
new_ant_type
==
rate
->
ant
)
return
0
;
tbl
->
ant_type
=
new_ant_type
;
*
rate_n_flags
&=
~
RATE_MCS_ANT_ABC_MSK
;
*
rate_n_flags
|=
new_ant_type
<<
RATE_MCS_ANT_POS
;
rate
->
ant
=
new_ant_type
;
/* TODO: get rid of ucode_rate here. This should handle only rs_rate */
*
ucode_rate
&=
~
RATE_MCS_ANT_ABC_MSK
;
*
ucode_rate
|=
new_ant_type
<<
RATE_MCS_ANT_POS
;
return
1
;
}
/**
* rs_get_supported_rates - get the available rates
*
* if management frame or broadcast frame only return
* basic available rates.
*
*/
static
u16
rs_get_supported_rates
(
struct
iwl_lq_sta
*
lq_sta
,
struct
ieee80211_hdr
*
hdr
,
enum
iwl_table_type
rate_type
)
struct
rs_rate
*
rate
)
{
if
(
is_legacy
(
rate
_type
))
if
(
is_legacy
(
rate
))
return
lq_sta
->
active_legacy_rate
;
else
if
(
is_siso
(
rate
_type
))
else
if
(
is_siso
(
rate
))
return
lq_sta
->
active_siso_rate
;
else
if
(
is_mimo2
(
rate
_type
))
else
if
(
is_mimo2
(
rate
))
return
lq_sta
->
active_mimo2_rate
;
WARN_ON_ONCE
(
1
);
...
...
@@ -628,7 +835,7 @@ static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask,
/* 802.11A or ht walks to the next literal adjacent rate in
* the rate table */
if
(
is_
a_band
(
rate_type
)
||
!
is
_legacy
(
rate_type
))
{
if
(
is_
type_a_band
(
rate_type
)
||
!
is_type
_legacy
(
rate_type
))
{
int
i
;
u32
mask
;
...
...
@@ -677,7 +884,7 @@ static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask,
}
static
u32
rs_get_lower_rate
(
struct
iwl_lq_sta
*
lq_sta
,
struct
iwl_scale_tbl_info
*
tbl
,
struct
rs_rate
*
rate
,
u8
scale_index
,
u8
ht_possible
)
{
s32
low
;
...
...
@@ -689,27 +896,28 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
/* check if we need to switch from HT to legacy rates.
* assumption is that mandatory rates (1Mbps or 6Mbps)
* are always supported (spec demand) */
if
(
!
is_legacy
(
tbl
->
lq_typ
e
)
&&
(
!
ht_possible
||
!
scale_index
))
{
if
(
!
is_legacy
(
rat
e
)
&&
(
!
ht_possible
||
!
scale_index
))
{
switch_to_legacy
=
1
;
WARN_ON_ONCE
(
scale_index
<
IWL_RATE_MCS_0_INDEX
&&
scale_index
>
IWL_RATE_MCS_9_INDEX
);
scale_index
=
rs_ht_to_legacy
[
scale_index
];
if
(
lq_sta
->
band
==
IEEE80211_BAND_5GHZ
)
tbl
->
lq_
type
=
LQ_LEGACY_A
;
rate
->
type
=
LQ_LEGACY_A
;
else
tbl
->
lq_
type
=
LQ_LEGACY_G
;
rate
->
type
=
LQ_LEGACY_G
;
if
(
num_of_ant
(
tbl
->
ant_type
)
>
1
)
tbl
->
ant_type
=
if
(
num_of_ant
(
rate
->
ant
)
>
1
)
rate
->
ant
=
first_antenna
(
iwl_fw_valid_tx_ant
(
mvm
->
fw
));
tbl
->
bw
=
0
;
tbl
->
is_SGI
=
0
;
tbl
->
max_search
=
IWL_MAX_SEARCH
;
rate
->
bw
=
RATE_MCS_CHAN_WIDTH_20
;
rate
->
sgi
=
false
;
}
rate_mask
=
rs_get_supported_rates
(
lq_sta
,
NULL
,
tbl
->
lq_typ
e
);
rate_mask
=
rs_get_supported_rates
(
lq_sta
,
rat
e
);
/* Mask with station rate restriction */
if
(
is_legacy
(
tbl
->
lq_typ
e
))
{
if
(
is_legacy
(
rat
e
))
{
/* supp_rates has no CCK bits in A mode */
if
(
lq_sta
->
band
==
IEEE80211_BAND_5GHZ
)
rate_mask
=
(
u16
)(
rate_mask
&
...
...
@@ -725,24 +933,22 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
}
high_low
=
rs_get_adjacent_rate
(
lq_sta
->
drv
,
scale_index
,
rate_mask
,
tbl
->
lq_
type
);
rate
->
type
);
low
=
high_low
&
0xff
;
if
(
low
==
IWL_RATE_INVALID
)
low
=
scale_index
;
out:
return
rate_n_flags_from_tbl
(
lq_sta
->
drv
,
tbl
,
low
);
rate
->
index
=
low
;
return
ucode_rate_from_rs_rate
(
lq_sta
->
drv
,
rate
);
}
/*
* Simple function to compare two rate scale table types
*/
static
bool
table_type_matches
(
struct
iwl_scale_tbl_info
*
a
,
struct
iwl_scale_tbl_info
*
b
)
/* Simple function to compare two rate scale table types */
static
inline
bool
rs_rate_match
(
struct
rs_rate
*
a
,
struct
rs_rate
*
b
)
{
return
(
a
->
lq_type
==
b
->
lq_type
)
&&
(
a
->
ant_type
==
b
->
ant_type
)
&&
(
a
->
is_SGI
==
b
->
is_SGI
);
return
(
a
->
type
==
b
->
type
)
&&
(
a
->
ant
==
b
->
ant
)
&&
(
a
->
sgi
==
b
->
sgi
);
}
static
u32
rs_ch_width_from_mac_flags
(
enum
mac80211_rate_control_flags
flags
)
...
...
@@ -766,7 +972,7 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
{
int
legacy_success
;
int
retries
;
int
rs_index
,
mac_index
,
i
;
int
mac_index
,
i
;
struct
iwl_lq_sta
*
lq_sta
=
priv_sta
;
struct
iwl_lq_cmd
*
table
;
struct
ieee80211_hdr
*
hdr
=
(
struct
ieee80211_hdr
*
)
skb
->
data
;
...
...
@@ -774,13 +980,10 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
struct
iwl_mvm
*
mvm
=
IWL_OP_MODE_GET_MVM
(
op_mode
);
struct
ieee80211_tx_info
*
info
=
IEEE80211_SKB_CB
(
skb
);
enum
mac80211_rate_control_flags
mac_flags
;
u32
tx
_rate
;
struct
iwl_scale_tbl_info
tbl_typ
e
;
u32
ucode
_rate
;
struct
rs_rate
rat
e
;
struct
iwl_scale_tbl_info
*
curr_tbl
,
*
other_tbl
,
*
tmp_tbl
;
IWL_DEBUG_RATE_LIMIT
(
mvm
,
"get frame ack response, update rate scale window
\n
"
);
/* Treat uninitialized rate scaling data same as non-existing. */
if
(
!
lq_sta
)
{
IWL_DEBUG_RATE
(
mvm
,
"Station rate scaling not created yet.
\n
"
);
...
...
@@ -808,10 +1011,10 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
* to a new "search" mode (which might become the new "active" mode).
*/
table
=
&
lq_sta
->
lq
;
tx
_rate
=
le32_to_cpu
(
table
->
rs_table
[
0
]);
rs_
get_tbl_info_from_mcs
(
tx_rate
,
info
->
band
,
&
tbl_type
,
&
rs_index
);
ucode
_rate
=
le32_to_cpu
(
table
->
rs_table
[
0
]);
rs_
rate_from_ucode_rate
(
ucode_rate
,
info
->
band
,
&
rate
);
if
(
info
->
band
==
IEEE80211_BAND_5GHZ
)
r
s_
index
-=
IWL_FIRST_OFDM_RATE
;
r
ate
.
index
-=
IWL_FIRST_OFDM_RATE
;
mac_flags
=
info
->
status
.
rates
[
0
].
flags
;
mac_index
=
info
->
status
.
rates
[
0
].
idx
;
/* For HT packets, map MCS to PLCP */
...
...
@@ -834,19 +1037,19 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
/* Here we actually compare this rate to the latest LQ command */
if
((
mac_index
<
0
)
||
(
tbl_type
.
is_SGI
!=
!!
(
mac_flags
&
IEEE80211_TX_RC_SHORT_GI
))
||
(
tbl_typ
e
.
bw
!=
rs_ch_width_from_mac_flags
(
mac_flags
))
||
(
tbl_type
.
ant_type
!=
info
->
status
.
antenna
)
||
(
!!
(
tx
_rate
&
RATE_MCS_HT_MSK
)
!=
(
rate
.
sgi
!=
!!
(
mac_flags
&
IEEE80211_TX_RC_SHORT_GI
))
||
(
rat
e
.
bw
!=
rs_ch_width_from_mac_flags
(
mac_flags
))
||
(
rate
.
ant
!=
info
->
status
.
antenna
)
||
(
!!
(
ucode
_rate
&
RATE_MCS_HT_MSK
)
!=
!!
(
mac_flags
&
IEEE80211_TX_RC_MCS
))
||
(
!!
(
tx
_rate
&
RATE_MCS_VHT_MSK
)
!=
(
!!
(
ucode
_rate
&
RATE_MCS_VHT_MSK
)
!=
!!
(
mac_flags
&
IEEE80211_TX_RC_VHT_MCS
))
||
(
!!
(
tx
_rate
&
RATE_HT_MCS_GF_MSK
)
!=
(
!!
(
ucode
_rate
&
RATE_HT_MCS_GF_MSK
)
!=
!!
(
mac_flags
&
IEEE80211_TX_RC_GREEN_FIELD
))
||
(
r
s_
index
!=
mac_index
))
{
(
r
ate
.
index
!=
mac_index
))
{
IWL_DEBUG_RATE
(
mvm
,
"initial rate %d does not match %d (0x%x)
\n
"
,
mac_index
,
r
s_index
,
tx
_rate
);
mac_index
,
r
ate
.
index
,
ucode
_rate
);
/*
* Since rates mis-match, the last LQ command may have failed.
* After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with
...
...
@@ -855,7 +1058,10 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
lq_sta
->
missed_rate_counter
++
;
if
(
lq_sta
->
missed_rate_counter
>
IWL_MISSED_RATE_MAX
)
{
lq_sta
->
missed_rate_counter
=
0
;
iwl_mvm_send_lq_cmd
(
mvm
,
&
lq_sta
->
lq
,
CMD_ASYNC
,
false
);
IWL_DEBUG_RATE
(
mvm
,
"Too many rates mismatch. Send sync LQ. rs_state %d
\n
"
,
lq_sta
->
rs_state
);
iwl_mvm_send_lq_cmd
(
mvm
,
&
lq_sta
->
lq
,
false
);
}
/* Regardless, ignore this status info for outdated rate */
return
;
...
...
@@ -864,28 +1070,23 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
lq_sta
->
missed_rate_counter
=
0
;
/* Figure out if rate scale algorithm is in active or search table */
if
(
table_type_matches
(
&
tbl_typ
e
,
&
(
lq_sta
->
lq_info
[
lq_sta
->
active_tbl
]
)))
{
if
(
rs_rate_match
(
&
rat
e
,
&
(
lq_sta
->
lq_info
[
lq_sta
->
active_tbl
].
rate
)))
{
curr_tbl
=
&
(
lq_sta
->
lq_info
[
lq_sta
->
active_tbl
]);
other_tbl
=
&
(
lq_sta
->
lq_info
[
1
-
lq_sta
->
active_tbl
]);
}
else
if
(
table_type_matches
(
&
tbl_type
,
&
lq_sta
->
lq_info
[
1
-
lq_sta
->
active_tbl
]
))
{
}
else
if
(
rs_rate_match
(
&
rate
,
&
lq_sta
->
lq_info
[
1
-
lq_sta
->
active_tbl
].
rate
))
{
curr_tbl
=
&
(
lq_sta
->
lq_info
[
1
-
lq_sta
->
active_tbl
]);
other_tbl
=
&
(
lq_sta
->
lq_info
[
lq_sta
->
active_tbl
]);
}
else
{
IWL_DEBUG_RATE
(
mvm
,
"Neither active nor search matches tx rate
\n
"
);
tmp_tbl
=
&
(
lq_sta
->
lq_info
[
lq_sta
->
active_tbl
]);
IWL_DEBUG_RATE
(
mvm
,
"active- lq:%x, ant:%x, SGI:%d
\n
"
,
tmp_tbl
->
lq_type
,
tmp_tbl
->
ant_type
,
tmp_tbl
->
is_SGI
);
rs_dump_rate
(
mvm
,
&
tmp_tbl
->
rate
,
"ACTIVE"
);
tmp_tbl
=
&
(
lq_sta
->
lq_info
[
1
-
lq_sta
->
active_tbl
]);
IWL_DEBUG_RATE
(
mvm
,
"search- lq:%x, ant:%x, SGI:%d
\n
"
,
tmp_tbl
->
lq_type
,
tmp_tbl
->
ant_type
,
tmp_tbl
->
is_SGI
);
IWL_DEBUG_RATE
(
mvm
,
"actual- lq:%x, ant:%x, SGI:%d
\n
"
,
tbl_type
.
lq_type
,
tbl_type
.
ant_type
,
tbl_type
.
is_SGI
);
rs_dump_rate
(
mvm
,
&
tmp_tbl
->
rate
,
"SEARCH"
);
rs_dump_rate
(
mvm
,
&
rate
,
"ACTUAL"
);
/*
* no matching table found, let's by-pass the data collection
* and continue to perform rate scale to find the rate table
...
...
@@ -902,15 +1103,14 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
* first index into rate scale table.
*/
if
(
info
->
flags
&
IEEE80211_TX_STAT_AMPDU
)
{
tx_rate
=
le32_to_cpu
(
table
->
rs_table
[
0
]);
rs_get_tbl_info_from_mcs
(
tx_rate
,
info
->
band
,
&
tbl_type
,
&
rs_index
);
rs_collect_tx_data
(
curr_tbl
,
rs_index
,
ucode_rate
=
le32_to_cpu
(
table
->
rs_table
[
0
]);
rs_rate_from_ucode_rate
(
ucode_rate
,
info
->
band
,
&
rate
);
rs_collect_tx_data
(
curr_tbl
,
rate
.
index
,
info
->
status
.
ampdu_len
,
info
->
status
.
ampdu_ack_len
);
/* Update success/fail counts if not searching for new mode */
if
(
lq_sta
->
stay_in_tbl
)
{
if
(
lq_sta
->
rs_state
==
RS_STATE_STAY_IN_COLUMN
)
{
lq_sta
->
total_success
+=
info
->
status
.
ampdu_ack_len
;
lq_sta
->
total_failed
+=
(
info
->
status
.
ampdu_len
-
info
->
status
.
ampdu_ack_len
);
...
...
@@ -927,31 +1127,36 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
legacy_success
=
!!
(
info
->
flags
&
IEEE80211_TX_STAT_ACK
);
/* Collect data for each rate used during failed TX attempts */
for
(
i
=
0
;
i
<=
retries
;
++
i
)
{
tx_rate
=
le32_to_cpu
(
table
->
rs_table
[
i
]);
rs_get_tbl_info_from_mcs
(
tx_rate
,
info
->
band
,
&
tbl_type
,
&
rs_index
);
ucode_rate
=
le32_to_cpu
(
table
->
rs_table
[
i
]);
rs_rate_from_ucode_rate
(
ucode_rate
,
info
->
band
,
&
rate
);
/*
* Only collect stats if retried rate is in the same RS
* table as active/search.
*/
if
(
table_type_matches
(
&
tbl_type
,
curr_tbl
))
if
(
rs_rate_match
(
&
rate
,
&
curr_tbl
->
rate
))
tmp_tbl
=
curr_tbl
;
else
if
(
table_type_matches
(
&
tbl_type
,
other_tbl
))
else
if
(
rs_rate_match
(
&
rate
,
&
other_tbl
->
rate
))
tmp_tbl
=
other_tbl
;
else
else
{
IWL_DEBUG_RATE
(
mvm
,
"Tx packet rate doesn't match ACTIVE or SEARCH tables
\n
"
);
rs_dump_rate
(
mvm
,
&
rate
,
"Tx PACKET:"
);
rs_dump_rate
(
mvm
,
&
curr_tbl
->
rate
,
"CURRENT:"
);
rs_dump_rate
(
mvm
,
&
other_tbl
->
rate
,
"OTHER:"
);
continue
;
rs_collect_tx_data
(
tmp_tbl
,
rs_index
,
1
,
}
rs_collect_tx_data
(
tmp_tbl
,
rate
.
index
,
1
,
i
<
retries
?
0
:
legacy_success
);
}
/* Update success/fail counts if not searching for new mode */
if
(
lq_sta
->
stay_in_tbl
)
{
if
(
lq_sta
->
rs_state
==
RS_STATE_STAY_IN_COLUMN
)
{
lq_sta
->
total_success
+=
legacy_success
;
lq_sta
->
total_failed
+=
retries
+
(
1
-
legacy_success
);
}
}
/* The last TX rate is cached in lq_sta; it's set in if/else above */
lq_sta
->
last_rate_n_flags
=
tx
_rate
;
lq_sta
->
last_rate_n_flags
=
ucode
_rate
;
done:
/* See if there's a better rate or modulation mode to try. */
if
(
sta
&&
sta
->
supp_rates
[
sband
->
band
])
...
...
@@ -969,8 +1174,8 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
static
void
rs_set_stay_in_table
(
struct
iwl_mvm
*
mvm
,
u8
is_legacy
,
struct
iwl_lq_sta
*
lq_sta
)
{
IWL_DEBUG_RATE
(
mvm
,
"
we are staying in the same table
\n
"
);
lq_sta
->
stay_in_tbl
=
1
;
/* only place this gets set */
IWL_DEBUG_RATE
(
mvm
,
"
Moving to RS_STATE_STAY_IN_COLUMN
\n
"
);
lq_sta
->
rs_state
=
RS_STATE_STAY_IN_COLUMN
;
if
(
is_legacy
)
{
lq_sta
->
table_count_limit
=
IWL_LEGACY_TABLE_COUNT
;
lq_sta
->
max_failure_limit
=
IWL_LEGACY_FAILURE_LIMIT
;
...
...
@@ -984,37 +1189,31 @@ static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy,
lq_sta
->
total_failed
=
0
;
lq_sta
->
total_success
=
0
;
lq_sta
->
flush_timer
=
jiffies
;
lq_sta
->
action_counter
=
0
;
lq_sta
->
visited_columns
=
0
;
}
/*
* Find correct throughput table for given mode of modulation
*/
static
void
rs_set_expected_tpt_table
(
struct
iwl_lq_sta
*
lq_sta
,
struct
iwl_scale_tbl_info
*
tbl
)
static
s32
*
rs_get_expected_tpt_table
(
struct
iwl_lq_sta
*
lq_sta
,
const
struct
rs_tx_column
*
column
,
u32
bw
)
{
/* Used to choose among HT tables */
s32
(
*
ht_tbl_pointer
)[
IWL_RATE_COUNT
];
/* Check for invalid LQ type */
if
(
WARN_ON_ONCE
(
!
is_legacy
(
tbl
->
lq_type
)
&&
!
is_ht
(
tbl
->
lq_type
)
&&
!
(
is_vht
(
tbl
->
lq_type
))))
{
tbl
->
expected_tpt
=
expected_tpt_legacy
;
return
;
}
if
(
WARN_ON_ONCE
(
column
->
mode
!=
RS_LEGACY
&&
column
->
mode
!=
RS_SISO
&&
column
->
mode
!=
RS_MIMO2
))
return
expected_tpt_legacy
;
/* Legacy rates have only one table */
if
(
is_legacy
(
tbl
->
lq_type
))
{
tbl
->
expected_tpt
=
expected_tpt_legacy
;
return
;
}
if
(
column
->
mode
==
RS_LEGACY
)
return
expected_tpt_legacy
;
ht_tbl_pointer
=
expected_tpt_mimo2_20MHz
;
/* Choose among many HT tables depending on number of streams
* (SISO/MIMO2), channel width (20/40/80), SGI, and aggregation
* status */
if
(
is_siso
(
tbl
->
lq_type
)
)
{
switch
(
tbl
->
bw
)
{
if
(
column
->
mode
==
RS_SISO
)
{
switch
(
bw
)
{
case
RATE_MCS_CHAN_WIDTH_20
:
ht_tbl_pointer
=
expected_tpt_siso_20MHz
;
break
;
...
...
@@ -1027,8 +1226,8 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
default:
WARN_ON_ONCE
(
1
);
}
}
else
if
(
is_mimo2
(
tbl
->
lq_type
)
)
{
switch
(
tbl
->
bw
)
{
}
else
if
(
column
->
mode
==
RS_MIMO2
)
{
switch
(
bw
)
{
case
RATE_MCS_CHAN_WIDTH_20
:
ht_tbl_pointer
=
expected_tpt_mimo2_20MHz
;
break
;
...
...
@@ -1045,14 +1244,23 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
WARN_ON_ONCE
(
1
);
}
if
(
!
tbl
->
is_SGI
&&
!
lq_sta
->
is_agg
)
/* Normal */
tbl
->
expected_tpt
=
ht_tbl_pointer
[
0
];
else
if
(
tbl
->
is_SGI
&&
!
lq_sta
->
is_agg
)
/* SGI */
tbl
->
expected_tpt
=
ht_tbl_pointer
[
1
];
else
if
(
!
tbl
->
is_SGI
&&
lq_sta
->
is_agg
)
/* AGG */
tbl
->
expected_tpt
=
ht_tbl_pointer
[
2
];
if
(
!
column
->
sgi
&&
!
lq_sta
->
is_agg
)
/* Normal */
return
ht_tbl_pointer
[
0
];
else
if
(
column
->
sgi
&&
!
lq_sta
->
is_agg
)
/* SGI */
return
ht_tbl_pointer
[
1
];
else
if
(
!
column
->
sgi
&&
lq_sta
->
is_agg
)
/* AGG */
return
ht_tbl_pointer
[
2
];
else
/* AGG+SGI */
tbl
->
expected_tpt
=
ht_tbl_pointer
[
3
];
return
ht_tbl_pointer
[
3
];
}
static
void
rs_set_expected_tpt_table
(
struct
iwl_lq_sta
*
lq_sta
,
struct
iwl_scale_tbl_info
*
tbl
)
{
struct
rs_rate
*
rate
=
&
tbl
->
rate
;
const
struct
rs_tx_column
*
column
=
&
rs_tx_columns
[
tbl
->
column
];
tbl
->
expected_tpt
=
rs_get_expected_tpt_table
(
lq_sta
,
column
,
rate
->
bw
);
}
/*
...
...
@@ -1089,7 +1297,7 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm,
while
(
1
)
{
high_low
=
rs_get_adjacent_rate
(
mvm
,
rate
,
rate_mask
,
tbl
->
lq_
type
);
tbl
->
rate
.
type
);
low
=
high_low
&
0xff
;
high
=
(
high_low
>>
8
)
&
0xff
;
...
...
@@ -1110,7 +1318,7 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm,
* "active" throughput (under perfect conditions).
*/
if
((((
100
*
tpt_tbl
[
rate
])
>
lq_sta
->
last_tpt
)
&&
((
active_sr
>
IWL_RATE_DECREASE_TH
)
&&
((
active_sr
>
RS_SR_FORCE_DECREASE
)
&&
(
active_sr
<=
IWL_RATE_HIGH_TH
)
&&
(
tpt_tbl
[
rate
]
<=
active_tpt
)))
||
((
active_sr
>=
IWL_RATE_SCALE_SWITCH
)
&&
...
...
@@ -1157,535 +1365,291 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm,
return
new_rate
;
}
/* Move to the next action and wrap around to the first action in case
* we're at the last action. Assumes actions start at 0.
*/
static
inline
void
rs_move_next_action
(
struct
iwl_scale_tbl_info
*
tbl
,
u8
last_action
)
{
BUILD_BUG_ON
(
IWL_LEGACY_FIRST_ACTION
!=
0
);
BUILD_BUG_ON
(
IWL_SISO_FIRST_ACTION
!=
0
);
BUILD_BUG_ON
(
IWL_MIMO2_FIRST_ACTION
!=
0
);
tbl
->
action
=
(
tbl
->
action
+
1
)
%
(
last_action
+
1
);
}
static
void
rs_set_bw_from_sta
(
struct
iwl_scale_tbl_info
*
tbl
,
struct
ieee80211_sta
*
sta
)
static
u32
rs_bw_from_sta_bw
(
struct
ieee80211_sta
*
sta
)
{
if
(
sta
->
bandwidth
>=
IEEE80211_STA_RX_BW_80
)
tbl
->
bw
=
RATE_MCS_CHAN_WIDTH_80
;
return
RATE_MCS_CHAN_WIDTH_80
;
else
if
(
sta
->
bandwidth
>=
IEEE80211_STA_RX_BW_40
)
tbl
->
bw
=
RATE_MCS_CHAN_WIDTH_40
;
else
tbl
->
bw
=
RATE_MCS_CHAN_WIDTH_20
;
}
static
bool
rs_sgi_allowed
(
struct
iwl_scale_tbl_info
*
tbl
,
struct
ieee80211_sta
*
sta
)
{
struct
ieee80211_sta_ht_cap
*
ht_cap
=
&
sta
->
ht_cap
;
struct
ieee80211_sta_vht_cap
*
vht_cap
=
&
sta
->
vht_cap
;
if
(
is_ht20
(
tbl
)
&&
(
ht_cap
->
cap
&
IEEE80211_HT_CAP_SGI_20
))
return
true
;
if
(
is_ht40
(
tbl
)
&&
(
ht_cap
->
cap
&
IEEE80211_HT_CAP_SGI_40
))
return
true
;
if
(
is_ht80
(
tbl
)
&&
(
vht_cap
->
cap
&
IEEE80211_VHT_CAP_SHORT_GI_80
))
return
true
;
return
RATE_MCS_CHAN_WIDTH_40
;
return
false
;
return
RATE_MCS_CHAN_WIDTH_20
;
}
/*
* Set up search table for MIMO2
* Check whether we should continue using same modulation mode, or
* begin search for a new mode, based on:
* 1) # tx successes or failures while using this mode
* 2) # times calling this function
* 3) elapsed time in this mode (not used, for now)
*/
static
int
rs_switch_to_mimo2
(
struct
iwl_mvm
*
mvm
,
struct
iwl_lq_sta
*
lq_sta
,
struct
ieee80211_sta
*
sta
,
struct
iwl_scale_tbl_info
*
tbl
,
int
index
)
static
void
rs_stay_in_table
(
struct
iwl_lq_sta
*
lq_sta
,
bool
force_search
)
{
u16
rate_mask
;
s32
rate
;
if
(
!
sta
->
ht_cap
.
ht_supported
)
return
-
1
;
if
(
sta
->
smps_mode
==
IEEE80211_SMPS_STATIC
)
return
-
1
;
struct
iwl_scale_tbl_info
*
tbl
;
int
i
;
int
active_tbl
;
int
flush_interval_passed
=
0
;
struct
iwl_mvm
*
mvm
;
/* Need both Tx chains/antennas to support MIMO */
if
(
num_of_ant
(
iwl_fw_valid_tx_ant
(
mvm
->
fw
))
<
2
)
return
-
1
;
mvm
=
lq_sta
->
drv
;
active_tbl
=
lq_sta
->
active_tbl
;
IWL_DEBUG_RATE
(
mvm
,
"LQ: try to switch to MIMO2
\n
"
);
tbl
=
&
(
lq_sta
->
lq_info
[
active_tbl
]
);
tbl
->
lq_type
=
lq_sta
->
is_vht
?
LQ_VHT_MIMO2
:
LQ_HT_MIMO2
;
tbl
->
action
=
0
;
tbl
->
max_search
=
IWL_MAX_SEARCH
;
rate_mask
=
lq_sta
->
active_mimo2_rate
;
/* If we've been disallowing search, see if we should now allow it */
if
(
lq_sta
->
rs_state
==
RS_STATE_STAY_IN_COLUMN
)
{
/* Elapsed time using current modulation mode */
if
(
lq_sta
->
flush_timer
)
flush_interval_passed
=
time_after
(
jiffies
,
(
unsigned
long
)(
lq_sta
->
flush_timer
+
RS_STAY_IN_COLUMN_TIMEOUT
));
rs_set_bw_from_sta
(
tbl
,
sta
);
rs_set_expected_tpt_table
(
lq_sta
,
tbl
);
/*
* Check if we should allow search for new modulation mode.
* If many frames have failed or succeeded, or we've used
* this same modulation for a long time, allow search, and
* reset history stats that keep track of whether we should
* allow a new search. Also (below) reset all bitmaps and
* stats in active history.
*/
if
(
force_search
||
(
lq_sta
->
total_failed
>
lq_sta
->
max_failure_limit
)
||
(
lq_sta
->
total_success
>
lq_sta
->
max_success_limit
)
||
((
!
lq_sta
->
search_better_tbl
)
&&
(
lq_sta
->
flush_timer
)
&&
(
flush_interval_passed
)))
{
IWL_DEBUG_RATE
(
mvm
,
"LQ: stay is expired %d %d %d
\n
"
,
lq_sta
->
total_failed
,
lq_sta
->
total_success
,
flush_interval_passed
);
rate
=
rs_get_best_rate
(
mvm
,
lq_sta
,
tbl
,
rate_mask
,
index
);
/* Allow search for new mode */
lq_sta
->
rs_state
=
RS_STATE_SEARCH_CYCLE_STARTED
;
IWL_DEBUG_RATE
(
mvm
,
"Moving to RS_STATE_SEARCH_CYCLE_STARTED
\n
"
);
lq_sta
->
total_failed
=
0
;
lq_sta
->
total_success
=
0
;
lq_sta
->
flush_timer
=
0
;
/* mark the current column as visited */
lq_sta
->
visited_columns
=
BIT
(
tbl
->
column
);
/*
* Else if we've used this modulation mode enough repetitions
* (regardless of elapsed time or success/failure), reset
* history bitmaps and rate-specific stats for all rates in
* active table.
*/
}
else
{
lq_sta
->
table_count
++
;
if
(
lq_sta
->
table_count
>=
lq_sta
->
table_count_limit
)
{
lq_sta
->
table_count
=
0
;
IWL_DEBUG_RATE
(
mvm
,
"LQ: MIMO2 best rate %d mask %X
\n
"
,
rate
,
rate_mask
);
if
((
rate
==
IWL_RATE_INVALID
)
||
!
((
1
<<
rate
)
&
rate_mask
))
{
IWL_DEBUG_RATE
(
mvm
,
"Can't switch with index %d rate mask %x
\n
"
,
rate
,
rate_mask
);
return
-
1
;
IWL_DEBUG_RATE
(
mvm
,
"LQ: stay in table clear win
\n
"
);
for
(
i
=
0
;
i
<
IWL_RATE_COUNT
;
i
++
)
rs_rate_scale_clear_window
(
&
(
tbl
->
win
[
i
])
);
}
}
tbl
->
current_rate
=
rate_n_flags_from_tbl
(
mvm
,
tbl
,
rate
);
IWL_DEBUG_RATE
(
mvm
,
"LQ: Switch to new mcs %X index
\n
"
,
tbl
->
current_rate
);
return
0
;
/* If transitioning to allow "search", reset all history
* bitmaps and stats in active table (this will become the new
* "search" table). */
if
(
lq_sta
->
rs_state
==
RS_STATE_SEARCH_CYCLE_STARTED
)
{
IWL_DEBUG_RATE
(
mvm
,
"Clearing up window stats
\n
"
);
for
(
i
=
0
;
i
<
IWL_RATE_COUNT
;
i
++
)
rs_rate_scale_clear_window
(
&
(
tbl
->
win
[
i
]));
}
}
}
/*
*
Set up search table for SISO
*
setup rate table in uCode
*/
static
int
rs_switch_to_siso
(
struct
iwl_mvm
*
mvm
,
struct
iwl_lq_sta
*
lq_sta
,
static
void
rs_update_rate_tbl
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
,
struct
iwl_scale_tbl_info
*
tbl
,
int
index
)
struct
iwl_lq_sta
*
lq_sta
,
struct
rs_rate
*
rate
)
{
u16
rate_mask
;
s32
rate
;
u32
ucode_rate
;
if
(
!
sta
->
ht_cap
.
ht_supported
)
return
-
1
;
ucode_rate
=
ucode_rate_from_rs_rate
(
mvm
,
rate
);
rs_fill_link_cmd
(
mvm
,
sta
,
lq_sta
,
ucode_rate
);
iwl_mvm_send_lq_cmd
(
mvm
,
&
lq_sta
->
lq
,
false
);
}
IWL_DEBUG_RATE
(
mvm
,
"LQ: try to switch to SISO
\n
"
);
static
u8
rs_get_tid
(
struct
iwl_lq_sta
*
lq_data
,
struct
ieee80211_hdr
*
hdr
)
{
u8
tid
=
IWL_MAX_TID_COUNT
;
tbl
->
lq_type
=
lq_sta
->
is_vht
?
LQ_VHT_SISO
:
LQ_HT_SISO
;
tbl
->
action
=
0
;
tbl
->
max_search
=
IWL_MAX_SEARCH
;
rate_mask
=
lq_sta
->
active_siso_rate
;
if
(
ieee80211_is_data_qos
(
hdr
->
frame_control
))
{
u8
*
qc
=
ieee80211_get_qos_ctl
(
hdr
)
;
tid
=
qc
[
0
]
&
0xf
;
}
rs_set_bw_from_sta
(
tbl
,
sta
);
rs_set_expected_tpt_table
(
lq_sta
,
tbl
);
rate
=
rs_get_best_rate
(
mvm
,
lq_sta
,
tbl
,
rate_mask
,
index
);
if
(
unlikely
(
tid
>
IWL_MAX_TID_COUNT
))
tid
=
IWL_MAX_TID_COUNT
;
IWL_DEBUG_RATE
(
mvm
,
"LQ: get best rate %d mask %X
\n
"
,
rate
,
rate_mask
);
if
((
rate
==
IWL_RATE_INVALID
)
||
!
((
1
<<
rate
)
&
rate_mask
))
{
IWL_DEBUG_RATE
(
mvm
,
"can not switch with index %d rate mask %x
\n
"
,
rate
,
rate_mask
);
return
-
1
;
}
tbl
->
current_rate
=
rate_n_flags_from_tbl
(
mvm
,
tbl
,
rate
);
IWL_DEBUG_RATE
(
mvm
,
"LQ: Switch to new mcs %X index
\n
"
,
tbl
->
current_rate
);
return
0
;
return
tid
;
}
/*
* Try to switch to new modulation mode from legacy
*/
static
int
rs_move_legacy_other
(
struct
iwl_mvm
*
mvm
,
static
enum
rs_column
rs_get_next_column
(
struct
iwl_mvm
*
mvm
,
struct
iwl_lq_sta
*
lq_sta
,
struct
ieee80211_sta
*
sta
,
int
index
)
struct
iwl_scale_tbl_info
*
tbl
)
{
struct
iwl_scale_tbl_info
*
tbl
=
&
(
lq_sta
->
lq_info
[
lq_sta
->
active_tbl
]);
struct
iwl_scale_tbl_info
*
search_tbl
=
&
(
lq_sta
->
lq_info
[(
1
-
lq_sta
->
active_tbl
)]);
struct
iwl_rate_scale_data
*
window
=
&
(
tbl
->
win
[
index
]);
u32
sz
=
(
sizeof
(
struct
iwl_scale_tbl_info
)
-
(
sizeof
(
struct
iwl_rate_scale_data
)
*
IWL_RATE_COUNT
));
u8
start_action
;
u8
valid_tx_ant
=
iwl_fw_valid_tx_ant
(
mvm
->
fw
);
u8
tx_chains_num
=
num_of_ant
(
valid_tx_ant
);
int
ret
;
u8
update_search_tbl_counter
=
0
;
int
i
,
j
,
n
;
enum
rs_column
next_col_id
;
const
struct
rs_tx_column
*
curr_col
=
&
rs_tx_columns
[
tbl
->
column
];
const
struct
rs_tx_column
*
next_col
;
allow_column_func_t
allow_func
;
u8
valid_ants
=
iwl_fw_valid_tx_ant
(
mvm
->
fw
);
s32
*
expected_tpt_tbl
;
s32
tpt
,
max_expected_tpt
;
for
(
i
=
0
;
i
<
MAX_NEXT_COLUMNS
;
i
++
)
{
next_col_id
=
curr_col
->
next_columns
[
i
];
if
(
next_col_id
==
RS_COLUMN_INVALID
)
continue
;
start_action
=
tbl
->
action
;
while
(
1
)
{
lq_sta
->
action_counter
++
;
switch
(
tbl
->
action
)
{
case
IWL_LEGACY_SWITCH_ANTENNA
:
IWL_DEBUG_RATE
(
mvm
,
"LQ: Legacy toggle Antenna
\n
"
);
if
(
lq_sta
->
visited_columns
&
BIT
(
next_col_id
))
{
IWL_DEBUG_RATE
(
mvm
,
"Skip already visited column %d
\n
"
,
next_col_id
);
continue
;
}
if
(
tx_chains_num
<=
1
)
break
;
next_col
=
&
rs_tx_columns
[
next_col_id
];
if
(
!
rs_is_valid_ant
(
valid_ants
,
next_col
->
ant
))
{
IWL_DEBUG_RATE
(
mvm
,
"Skip column %d as ANT config isn't supported by chip. valid_ants 0x%x column ant 0x%x
\n
"
,
next_col_id
,
valid_ants
,
next_col
->
ant
);
continue
;
}
/* Don't change antenna if success has been great */
if
(
window
->
success_ratio
>=
IWL_RS_GOOD_RATIO
)
for
(
j
=
0
;
j
<
MAX_COLUMN_CHECKS
;
j
++
)
{
allow_func
=
next_col
->
checks
[
j
];
if
(
allow_func
&&
!
allow_func
(
mvm
,
sta
,
tbl
))
break
;
}
/* Set up search table to try other antenna */
memcpy
(
search_tbl
,
tbl
,
sz
);
if
(
j
!=
MAX_COLUMN_CHECKS
)
{
IWL_DEBUG_RATE
(
mvm
,
"Skip column %d: not allowed (check %d failed)
\n
"
,
next_col_id
,
j
);
if
(
rs_toggle_antenna
(
valid_tx_ant
,
&
search_tbl
->
current_rate
,
search_tbl
))
{
update_search_tbl_counter
=
1
;
rs_set_expected_tpt_table
(
lq_sta
,
search_tbl
);
goto
out
;
continue
;
}
break
;
case
IWL_LEGACY_SWITCH_SISO
:
IWL_DEBUG_RATE
(
mvm
,
"LQ: Legacy switch to SISO
\n
"
);
/* Set up search table to try SISO */
memcpy
(
search_tbl
,
tbl
,
sz
);
search_tbl
->
is_SGI
=
0
;
ret
=
rs_switch_to_siso
(
mvm
,
lq_sta
,
sta
,
search_tbl
,
index
);
if
(
!
ret
)
{
lq_sta
->
action_counter
=
0
;
goto
out
;
}
tpt
=
lq_sta
->
last_tpt
/
100
;
expected_tpt_tbl
=
rs_get_expected_tpt_table
(
lq_sta
,
next_col
,
tbl
->
rate
.
bw
);
if
(
WARN_ON_ONCE
(
!
expected_tpt_tbl
))
continue
;
break
;
case
IWL_LEGACY_SWITCH_MIMO2
:
IWL_DEBUG_RATE
(
mvm
,
"LQ: Legacy switch to MIMO2
\n
"
);
/* Set up search table to try MIMO */
memcpy
(
search_tbl
,
tbl
,
sz
);
search_tbl
->
is_SGI
=
0
;
search_tbl
->
ant_type
=
ANT_AB
;
if
(
!
rs_is_valid_ant
(
valid_tx_ant
,
search_tbl
->
ant_type
))
break
;
max_expected_tpt
=
0
;
for
(
n
=
0
;
n
<
IWL_RATE_COUNT
;
n
++
)
if
(
expected_tpt_tbl
[
n
]
>
max_expected_tpt
)
max_expected_tpt
=
expected_tpt_tbl
[
n
];
ret
=
rs_switch_to_mimo2
(
mvm
,
lq_sta
,
sta
,
search_tbl
,
index
);
if
(
!
ret
)
{
lq_sta
->
action_counter
=
0
;
goto
out
;
}
break
;
default:
WARN_ON_ONCE
(
1
);
if
(
tpt
>=
max_expected_tpt
)
{
IWL_DEBUG_RATE
(
mvm
,
"Skip column %d: can't beat current TPT. Max expected %d current %d
\n
"
,
next_col_id
,
max_expected_tpt
,
tpt
);
continue
;
}
rs_move_next_action
(
tbl
,
IWL_LEGACY_LAST_ACTION
);
if
(
tbl
->
action
==
start_action
)
break
;
}
search_tbl
->
lq_type
=
LQ_NONE
;
return
0
;
out:
lq_sta
->
search_better_tbl
=
1
;
rs_move_next_action
(
tbl
,
IWL_LEGACY_LAST_ACTION
);
if
(
update_search_tbl_counter
)
search_tbl
->
action
=
tbl
->
action
;
return
0
;
}
if
(
i
==
MAX_NEXT_COLUMNS
)
return
RS_COLUMN_INVALID
;
/*
* Try to switch to new modulation mode from SISO
*/
static
int
rs_move_siso_to_other
(
struct
iwl_mvm
*
mvm
,
struct
iwl_lq_sta
*
lq_sta
,
struct
ieee80211_sta
*
sta
,
int
index
)
{
struct
iwl_scale_tbl_info
*
tbl
=
&
(
lq_sta
->
lq_info
[
lq_sta
->
active_tbl
]);
struct
iwl_scale_tbl_info
*
search_tbl
=
&
(
lq_sta
->
lq_info
[(
1
-
lq_sta
->
active_tbl
)]);
struct
iwl_rate_scale_data
*
window
=
&
(
tbl
->
win
[
index
]);
u32
sz
=
(
sizeof
(
struct
iwl_scale_tbl_info
)
-
(
sizeof
(
struct
iwl_rate_scale_data
)
*
IWL_RATE_COUNT
));
u8
start_action
;
u8
valid_tx_ant
=
iwl_fw_valid_tx_ant
(
mvm
->
fw
);
u8
tx_chains_num
=
num_of_ant
(
valid_tx_ant
);
u8
update_search_tbl_counter
=
0
;
int
ret
;
if
(
tbl
->
action
==
IWL_SISO_SWITCH_MIMO2
&&
!
iwl_mvm_bt_coex_is_mimo_allowed
(
mvm
,
sta
))
tbl
->
action
=
IWL_SISO_SWITCH_ANTENNA
;
start_action
=
tbl
->
action
;
while
(
1
)
{
lq_sta
->
action_counter
++
;
switch
(
tbl
->
action
)
{
case
IWL_SISO_SWITCH_ANTENNA
:
IWL_DEBUG_RATE
(
mvm
,
"LQ: SISO toggle Antenna
\n
"
);
if
(
tx_chains_num
<=
1
)
break
;
if
(
window
->
success_ratio
>=
IWL_RS_GOOD_RATIO
&&
BT_MBOX_MSG
(
&
mvm
->
last_bt_notif
,
3
,
TRAFFIC_LOAD
)
==
0
)
break
;
IWL_DEBUG_RATE
(
mvm
,
"Found potential column %d
\n
"
,
next_col_id
);
memcpy
(
search_tbl
,
tbl
,
sz
);
if
(
rs_toggle_antenna
(
valid_tx_ant
,
&
search_tbl
->
current_rate
,
search_tbl
))
{
update_search_tbl_counter
=
1
;
goto
out
;
}
break
;
case
IWL_SISO_SWITCH_MIMO2
:
IWL_DEBUG_RATE
(
mvm
,
"LQ: SISO switch to MIMO2
\n
"
);
memcpy
(
search_tbl
,
tbl
,
sz
);
search_tbl
->
is_SGI
=
0
;
search_tbl
->
ant_type
=
ANT_AB
;
if
(
!
rs_is_valid_ant
(
valid_tx_ant
,
search_tbl
->
ant_type
))
break
;
ret
=
rs_switch_to_mimo2
(
mvm
,
lq_sta
,
sta
,
search_tbl
,
index
);
if
(
!
ret
)
goto
out
;
break
;
case
IWL_SISO_SWITCH_GI
:
if
(
!
rs_sgi_allowed
(
tbl
,
sta
))
break
;
IWL_DEBUG_RATE
(
mvm
,
"LQ: SISO toggle SGI/NGI
\n
"
);
memcpy
(
search_tbl
,
tbl
,
sz
);
search_tbl
->
is_SGI
=
!
tbl
->
is_SGI
;
rs_set_expected_tpt_table
(
lq_sta
,
search_tbl
);
if
(
tbl
->
is_SGI
)
{
s32
tpt
=
lq_sta
->
last_tpt
/
100
;
if
(
tpt
>=
search_tbl
->
expected_tpt
[
index
])
break
;
}
search_tbl
->
current_rate
=
rate_n_flags_from_tbl
(
mvm
,
search_tbl
,
index
);
update_search_tbl_counter
=
1
;
goto
out
;
default:
WARN_ON_ONCE
(
1
);
}
rs_move_next_action
(
tbl
,
IWL_SISO_LAST_ACTION
);
if
(
tbl
->
action
==
start_action
)
break
;
}
search_tbl
->
lq_type
=
LQ_NONE
;
return
0
;
out:
lq_sta
->
search_better_tbl
=
1
;
rs_move_next_action
(
tbl
,
IWL_SISO_LAST_ACTION
);
if
(
update_search_tbl_counter
)
search_tbl
->
action
=
tbl
->
action
;
return
0
;
return
next_col_id
;
}
/*
* Try to switch to new modulation mode from MIMO2
*/
static
int
rs_move_mimo2_to_other
(
struct
iwl_mvm
*
mvm
,
static
int
rs_switch_to_column
(
struct
iwl_mvm
*
mvm
,
struct
iwl_lq_sta
*
lq_sta
,
struct
ieee80211_sta
*
sta
,
int
index
)
struct
ieee80211_sta
*
sta
,
enum
rs_column
col_id
)
{
struct
iwl_scale_tbl_info
*
tbl
=
&
(
lq_sta
->
lq_info
[
lq_sta
->
active_tbl
]);
struct
iwl_scale_tbl_info
*
search_tbl
=
&
(
lq_sta
->
lq_info
[(
1
-
lq_sta
->
active_tbl
)]);
struct
rs_rate
*
rate
=
&
search_tbl
->
rate
;
const
struct
rs_tx_column
*
column
=
&
rs_tx_columns
[
col_id
];
const
struct
rs_tx_column
*
curr_column
=
&
rs_tx_columns
[
tbl
->
column
];
u32
sz
=
(
sizeof
(
struct
iwl_scale_tbl_info
)
-
(
sizeof
(
struct
iwl_rate_scale_data
)
*
IWL_RATE_COUNT
));
u8
start_action
;
u8
valid_tx_ant
=
iwl_fw_valid_tx_ant
(
mvm
->
fw
);
u8
update_search_tbl_counter
=
0
;
int
ret
;
u16
rate_mask
=
0
;
u32
rate_idx
=
0
;
start_action
=
tbl
->
action
;
while
(
1
)
{
lq_sta
->
action_counter
++
;
switch
(
tbl
->
action
)
{
case
IWL_MIMO2_SWITCH_SISO_A
:
case
IWL_MIMO2_SWITCH_SISO_B
:
IWL_DEBUG_RATE
(
mvm
,
"LQ: MIMO2 switch to SISO
\n
"
);
/* Set up new search table for SISO */
memcpy
(
search_tbl
,
tbl
,
sz
);
if
(
tbl
->
action
==
IWL_MIMO2_SWITCH_SISO_A
)
search_tbl
->
ant_type
=
ANT_A
;
else
/* tbl->action == IWL_MIMO2_SWITCH_SISO_B */
search_tbl
->
ant_type
=
ANT_B
;
rate
->
sgi
=
column
->
sgi
;
rate
->
ant
=
column
->
ant
;
if
(
!
rs_is_valid_ant
(
valid_tx_ant
,
search_tbl
->
ant_type
))
break
;
ret
=
rs_switch_to_siso
(
mvm
,
lq_sta
,
sta
,
search_tbl
,
index
);
if
(
!
ret
)
goto
out
;
break
;
case
IWL_MIMO2_SWITCH_GI
:
if
(
!
rs_sgi_allowed
(
tbl
,
sta
))
break
;
IWL_DEBUG_RATE
(
mvm
,
"LQ: MIMO2 toggle SGI/NGI
\n
"
);
/* Set up new search table for MIMO2 */
memcpy
(
search_tbl
,
tbl
,
sz
);
search_tbl
->
is_SGI
=
!
tbl
->
is_SGI
;
rs_set_expected_tpt_table
(
lq_sta
,
search_tbl
);
/*
* If active table already uses the fastest possible
* modulation (dual stream with short guard interval),
* and it's working well, there's no need to look
* for a better type of modulation!
*/
if
(
tbl
->
is_SGI
)
{
s32
tpt
=
lq_sta
->
last_tpt
/
100
;
if
(
tpt
>=
search_tbl
->
expected_tpt
[
index
])
break
;
}
search_tbl
->
current_rate
=
rate_n_flags_from_tbl
(
mvm
,
search_tbl
,
index
);
update_search_tbl_counter
=
1
;
goto
out
;
default:
WARN_ON_ONCE
(
1
);
}
rs_move_next_action
(
tbl
,
IWL_MIMO2_LAST_ACTION
);
if
(
column
->
mode
==
RS_LEGACY
)
{
if
(
lq_sta
->
band
==
IEEE80211_BAND_5GHZ
)
rate
->
type
=
LQ_LEGACY_A
;
else
rate
->
type
=
LQ_LEGACY_G
;
if
(
tbl
->
action
==
start_action
)
break
;
rate_mask
=
lq_sta
->
active_legacy_rate
;
}
else
if
(
column
->
mode
==
RS_SISO
)
{
rate
->
type
=
lq_sta
->
is_vht
?
LQ_VHT_SISO
:
LQ_HT_SISO
;
rate_mask
=
lq_sta
->
active_siso_rate
;
}
else
if
(
column
->
mode
==
RS_MIMO2
)
{
rate
->
type
=
lq_sta
->
is_vht
?
LQ_VHT_MIMO2
:
LQ_HT_MIMO2
;
rate_mask
=
lq_sta
->
active_mimo2_rate
;
}
else
{
WARN_ON_ONCE
(
"Bad column mode"
);
}
search_tbl
->
lq_type
=
LQ_NONE
;
return
0
;
out:
lq_sta
->
search_better_tbl
=
1
;
rs_move_next_action
(
tbl
,
IWL_MIMO2_LAST_ACTION
);
if
(
update_search_tbl_counter
)
search_tbl
->
action
=
tbl
->
action
;
return
0
;
}
rate
->
bw
=
rs_bw_from_sta_bw
(
sta
);
search_tbl
->
column
=
col_id
;
rs_set_expected_tpt_table
(
lq_sta
,
search_tbl
);
/*
* Check whether we should continue using same modulation mode, or
* begin search for a new mode, based on:
* 1) # tx successes or failures while using this mode
* 2) # times calling this function
* 3) elapsed time in this mode (not used, for now)
/* Get the best matching rate if we're changing modes. e.g.
* SISO->MIMO, LEGACY->SISO, MIMO->SISO
*/
static
void
rs_stay_in_table
(
struct
iwl_lq_sta
*
lq_sta
,
bool
force_search
)
{
struct
iwl_scale_tbl_info
*
tbl
;
int
i
;
int
active_tbl
;
int
flush_interval_passed
=
0
;
struct
iwl_mvm
*
mvm
;
if
(
curr_column
->
mode
!=
column
->
mode
)
{
rate_idx
=
rs_get_best_rate
(
mvm
,
lq_sta
,
search_tbl
,
rate_mask
,
rate
->
index
);
mvm
=
lq_sta
->
drv
;
active_tbl
=
lq_sta
->
active_tbl
;
tbl
=
&
(
lq_sta
->
lq_info
[
active_tbl
]);
/* If we've been disallowing search, see if we should now allow it */
if
(
lq_sta
->
stay_in_tbl
)
{
/* Elapsed time using current modulation mode */
if
(
lq_sta
->
flush_timer
)
flush_interval_passed
=
time_after
(
jiffies
,
(
unsigned
long
)(
lq_sta
->
flush_timer
+
IWL_RATE_SCALE_FLUSH_INTVL
));
/*
* Check if we should allow search for new modulation mode.
* If many frames have failed or succeeded, or we've used
* this same modulation for a long time, allow search, and
* reset history stats that keep track of whether we should
* allow a new search. Also (below) reset all bitmaps and
* stats in active history.
*/
if
(
force_search
||
(
lq_sta
->
total_failed
>
lq_sta
->
max_failure_limit
)
||
(
lq_sta
->
total_success
>
lq_sta
->
max_success_limit
)
||
((
!
lq_sta
->
search_better_tbl
)
&&
(
lq_sta
->
flush_timer
)
&&
(
flush_interval_passed
)))
{
if
((
rate_idx
==
IWL_RATE_INVALID
)
||
!
(
BIT
(
rate_idx
)
&
rate_mask
))
{
IWL_DEBUG_RATE
(
mvm
,
"LQ: stay is expired %d %d %d
\n
"
,
lq_sta
->
total_failed
,
lq_sta
->
total_success
,
flush_interval_passed
);
/* Allow search for new mode */
lq_sta
->
stay_in_tbl
=
0
;
/* only place reset */
lq_sta
->
total_failed
=
0
;
lq_sta
->
total_success
=
0
;
lq_sta
->
flush_timer
=
0
;
/*
* Else if we've used this modulation mode enough repetitions
* (regardless of elapsed time or success/failure), reset
* history bitmaps and rate-specific stats for all rates in
* active table.
*/
}
else
{
lq_sta
->
table_count
++
;
if
(
lq_sta
->
table_count
>=
lq_sta
->
table_count_limit
)
{
lq_sta
->
table_count
=
0
;
"can not switch with index %d"
" rate mask %x
\n
"
,
rate_idx
,
rate_mask
);
IWL_DEBUG_RATE
(
mvm
,
"LQ: stay in table clear win
\n
"
);
for
(
i
=
0
;
i
<
IWL_RATE_COUNT
;
i
++
)
rs_rate_scale_clear_window
(
&
(
tbl
->
win
[
i
]));
}
goto
err
;
}
/* If transitioning to allow "search", reset all history
* bitmaps and stats in active table (this will become the new
* "search" table). */
if
(
!
lq_sta
->
stay_in_tbl
)
{
for
(
i
=
0
;
i
<
IWL_RATE_COUNT
;
i
++
)
rs_rate_scale_clear_window
(
&
(
tbl
->
win
[
i
]));
rate
->
index
=
rate_idx
;
}
}
}
/*
* setup rate table in uCode
/* TODO: remove current_rate and keep using rs_rate all the way until
* we need to fill in the rs_table in the LQ command
*/
static
void
rs_update_rate_tbl
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
,
struct
iwl_lq_sta
*
lq_sta
,
struct
iwl_scale_tbl_info
*
tbl
,
int
index
)
{
u32
rate
;
/* Update uCode's rate table. */
rate
=
rate_n_flags_from_tbl
(
mvm
,
tbl
,
index
);
rs_fill_link_cmd
(
mvm
,
sta
,
lq_sta
,
rate
);
iwl_mvm_send_lq_cmd
(
mvm
,
&
lq_sta
->
lq
,
CMD_ASYNC
,
false
);
}
static
u8
rs_get_tid
(
struct
iwl_lq_sta
*
lq_data
,
struct
ieee80211_hdr
*
hdr
)
{
u8
tid
=
IWL_MAX_TID_COUNT
;
search_tbl
->
current_rate
=
ucode_rate_from_rs_rate
(
mvm
,
rate
);
IWL_DEBUG_RATE
(
mvm
,
"Switched to column %d: Index %d
\n
"
,
col_id
,
rate
->
index
);
if
(
ieee80211_is_data_qos
(
hdr
->
frame_control
))
{
u8
*
qc
=
ieee80211_get_qos_ctl
(
hdr
);
tid
=
qc
[
0
]
&
0xf
;
}
if
(
unlikely
(
tid
>
IWL_MAX_TID_COUNT
))
tid
=
IWL_MAX_TID_COUNT
;
lq_sta
->
visited_columns
|=
BIT
(
col_id
);
return
0
;
return
tid
;
err:
rate
->
type
=
LQ_NONE
;
return
-
1
;
}
/*
* Do rate scaling and search for new modulation mode.
*/
...
...
@@ -1715,10 +1679,10 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
u16
high_low
;
s32
sr
;
u8
tid
=
IWL_MAX_TID_COUNT
;
u8
prev_agg
=
lq_sta
->
is_agg
;
struct
iwl_mvm_sta
*
sta_priv
=
(
void
*
)
sta
->
drv_priv
;
struct
iwl_mvm_tid_data
*
tid_data
;
IWL_DEBUG_RATE
(
mvm
,
"rate scale calculate new rate for skb
\n
"
);
struct
rs_rate
*
rate
;
/* Send management frames and NO_ACK data using lowest rate. */
/* TODO: this could probably be improved.. */
...
...
@@ -1751,20 +1715,23 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
active_tbl
=
1
-
lq_sta
->
active_tbl
;
tbl
=
&
(
lq_sta
->
lq_info
[
active_tbl
]);
rate
=
&
tbl
->
rate
;
if
(
prev_agg
!=
lq_sta
->
is_agg
)
{
IWL_DEBUG_RATE
(
mvm
,
"Aggregation changed: prev %d current %d. Update expected TPT table
\n
"
,
prev_agg
,
lq_sta
->
is_agg
);
rs_set_expected_tpt_table
(
lq_sta
,
tbl
);
}
/* current tx rate */
index
=
lq_sta
->
last_txrate_idx
;
IWL_DEBUG_RATE
(
mvm
,
"Rate scale index %d for type %d
\n
"
,
index
,
tbl
->
lq_type
);
/* rates available for this association, and for modulation mode */
rate_mask
=
rs_get_supported_rates
(
lq_sta
,
hdr
,
tbl
->
lq_type
);
IWL_DEBUG_RATE
(
mvm
,
"mask 0x%04X
\n
"
,
rate_mask
);
rate_mask
=
rs_get_supported_rates
(
lq_sta
,
rate
);
/* mask with station rate restriction */
if
(
is_legacy
(
tbl
->
lq_typ
e
))
{
if
(
is_legacy
(
rat
e
))
{
if
(
lq_sta
->
band
==
IEEE80211_BAND_5GHZ
)
/* supp_rates has no CCK bits in A mode */
rate_scale_index_msk
=
(
u16
)
(
rate_mask
&
...
...
@@ -1780,16 +1747,17 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
if
(
!
rate_scale_index_msk
)
rate_scale_index_msk
=
rate_mask
;
if
(
!
((
1
<<
index
)
&
rate_scale_index_msk
))
{
if
(
!
((
BIT
(
index
)
&
rate_scale_index_msk
)
))
{
IWL_ERR
(
mvm
,
"Current Rate is not valid
\n
"
);
if
(
lq_sta
->
search_better_tbl
)
{
/* revert to active table if search table is not valid*/
tbl
->
lq_
type
=
LQ_NONE
;
rate
->
type
=
LQ_NONE
;
lq_sta
->
search_better_tbl
=
0
;
tbl
=
&
(
lq_sta
->
lq_info
[
lq_sta
->
active_tbl
]);
/* get "active" rate info */
index
=
iwl_hwrate_to_plcp_idx
(
tbl
->
current_rate
);
rs_update_rate_tbl
(
mvm
,
sta
,
lq_sta
,
tbl
,
index
);
tbl
->
rate
.
index
=
index
;
rs_update_rate_tbl
(
mvm
,
sta
,
lq_sta
,
&
tbl
->
rate
);
}
return
;
}
...
...
@@ -1806,6 +1774,9 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
index
=
lq_sta
->
max_rate_idx
;
update_lq
=
1
;
window
=
&
(
tbl
->
win
[
index
]);
IWL_DEBUG_RATE
(
mvm
,
"Forcing user max rate %d
\n
"
,
index
);
goto
lq_update
;
}
...
...
@@ -1822,8 +1793,9 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
if
((
fail_count
<
IWL_RATE_MIN_FAILURE_TH
)
&&
(
window
->
success_counter
<
IWL_RATE_MIN_SUCCESS_TH
))
{
IWL_DEBUG_RATE
(
mvm
,
"LQ: still below TH. succ=%d total=%d for index %d
\n
"
,
window
->
success_counter
,
window
->
counter
,
index
);
"(%s: %d): Test Window: succ %d total %d
\n
"
,
rs_pretty_lq_type
(
rate
->
type
),
index
,
window
->
success_counter
,
window
->
counter
);
/* Can't calculate this yet; not enough history */
window
->
average_tpt
=
IWL_INVALID_VALUE
;
...
...
@@ -1838,8 +1810,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
* actual average throughput */
if
(
window
->
average_tpt
!=
((
window
->
success_ratio
*
tbl
->
expected_tpt
[
index
]
+
64
)
/
128
))
{
IWL_ERR
(
mvm
,
"expected_tpt should have been calculated by now
\n
"
);
window
->
average_tpt
=
((
window
->
success_ratio
*
tbl
->
expected_tpt
[
index
]
+
64
)
/
128
);
}
...
...
@@ -1851,27 +1821,26 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
* continuing to use the setup that we've been trying. */
if
(
window
->
average_tpt
>
lq_sta
->
last_tpt
)
{
IWL_DEBUG_RATE
(
mvm
,
"LQ: SWITCHING TO NEW TABLE suc=%d cur-tpt=%d old-tpt=%d
\n
"
,
"SWITCHING TO NEW TABLE SR: %d "
"cur-tpt %d old-tpt %d
\n
"
,
window
->
success_ratio
,
window
->
average_tpt
,
lq_sta
->
last_tpt
);
if
(
!
is_legacy
(
tbl
->
lq_type
))
lq_sta
->
enable_counter
=
1
;
/* Swap tables; "search" becomes "active" */
lq_sta
->
active_tbl
=
active_tbl
;
current_tpt
=
window
->
average_tpt
;
/* Else poor success; go back to mode in "active" table */
}
else
{
IWL_DEBUG_RATE
(
mvm
,
"LQ: GOING BACK TO THE OLD TABLE suc=%d cur-tpt=%d old-tpt=%d
\n
"
,
"GOING BACK TO THE OLD TABLE: SR %d "
"cur-tpt %d old-tpt %d
\n
"
,
window
->
success_ratio
,
window
->
average_tpt
,
lq_sta
->
last_tpt
);
/* Nullify "search" table */
tbl
->
lq_
type
=
LQ_NONE
;
rate
->
type
=
LQ_NONE
;
/* Revert to "active" table */
active_tbl
=
lq_sta
->
active_tbl
;
...
...
@@ -1895,7 +1864,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
/* (Else) not in search of better modulation mode, try for better
* starting rate, while staying in this mode. */
high_low
=
rs_get_adjacent_rate
(
mvm
,
index
,
rate_scale_index_msk
,
tbl
->
lq_
type
);
rate
->
type
);
low
=
high_low
&
0xff
;
high
=
(
high_low
>>
8
)
&
0xff
;
...
...
@@ -1913,29 +1882,44 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
if
(
high
!=
IWL_RATE_INVALID
)
high_tpt
=
tbl
->
win
[
high
].
average_tpt
;
IWL_DEBUG_RATE
(
mvm
,
"(%s: %d): cur_tpt %d SR %d low %d high %d low_tpt %d high_tpt %d
\n
"
,
rs_pretty_lq_type
(
rate
->
type
),
index
,
current_tpt
,
sr
,
low
,
high
,
low_tpt
,
high_tpt
);
scale_action
=
0
;
/* Too many failures, decrease rate */
if
((
sr
<=
IWL_RATE_DECREASE_TH
)
||
(
current_tpt
==
0
))
{
if
((
sr
<=
RS_SR_FORCE_DECREASE
)
||
(
current_tpt
==
0
))
{
IWL_DEBUG_RATE
(
mvm
,
"decrease rate because of low
success_ratio
\n
"
);
"decrease rate because of low
SR
\n
"
);
scale_action
=
-
1
;
/* No throughput measured yet for adjacent rates; try increase. */
}
else
if
((
low_tpt
==
IWL_INVALID_VALUE
)
&&
(
high_tpt
==
IWL_INVALID_VALUE
))
{
if
(
high
!=
IWL_RATE_INVALID
&&
sr
>=
IWL_RATE_INCREASE_TH
)
if
(
high
!=
IWL_RATE_INVALID
&&
sr
>=
IWL_RATE_INCREASE_TH
)
{
IWL_DEBUG_RATE
(
mvm
,
"Good SR and no high rate measurement. "
"Increase rate
\n
"
);
scale_action
=
1
;
else
if
(
low
!=
IWL_RATE_INVALID
)
}
else
if
(
low
!=
IWL_RATE_INVALID
)
{
IWL_DEBUG_RATE
(
mvm
,
"Remain in current rate
\n
"
);
scale_action
=
0
;
}
}
/* Both adjacent throughputs are measured, but neither one has better
* throughput; we're using the best rate, don't change it! */
else
if
((
low_tpt
!=
IWL_INVALID_VALUE
)
&&
(
high_tpt
!=
IWL_INVALID_VALUE
)
&&
(
low_tpt
<
current_tpt
)
&&
(
high_tpt
<
current_tpt
))
(
high_tpt
<
current_tpt
))
{
IWL_DEBUG_RATE
(
mvm
,
"Both high and low are worse. "
"Maintain rate
\n
"
);
scale_action
=
0
;
}
/* At least one adjacent rate's throughput is measured,
* and may have better performance. */
...
...
@@ -1945,8 +1929,14 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
/* Higher rate has better throughput */
if
(
high_tpt
>
current_tpt
&&
sr
>=
IWL_RATE_INCREASE_TH
)
{
IWL_DEBUG_RATE
(
mvm
,
"Higher rate is better and good "
"SR. Increate rate
\n
"
);
scale_action
=
1
;
}
else
{
IWL_DEBUG_RATE
(
mvm
,
"Higher rate isn't better OR "
"no good SR. Maintain rate
\n
"
);
scale_action
=
0
;
}
...
...
@@ -1955,9 +1945,13 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
/* Lower rate has better throughput */
if
(
low_tpt
>
current_tpt
)
{
IWL_DEBUG_RATE
(
mvm
,
"decrease rate because of low tpt
\n
"
);
"Lower rate is better. "
"Decrease rate
\n
"
);
scale_action
=
-
1
;
}
else
if
(
sr
>=
IWL_RATE_INCREASE_TH
)
{
IWL_DEBUG_RATE
(
mvm
,
"Lower rate isn't better and "
"good SR. Increase rate
\n
"
);
scale_action
=
1
;
}
}
...
...
@@ -1967,29 +1961,17 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
* has been good at old rate. Don't change it. */
if
((
scale_action
==
-
1
)
&&
(
low
!=
IWL_RATE_INVALID
)
&&
((
sr
>
IWL_RATE_HIGH_TH
)
||
(
current_tpt
>
(
100
*
tbl
->
expected_tpt
[
low
]))))
(
current_tpt
>
(
100
*
tbl
->
expected_tpt
[
low
]))))
{
IWL_DEBUG_RATE
(
mvm
,
"Sanity check failed. Maintain rate
\n
"
);
scale_action
=
0
;
if
((
le32_to_cpu
(
mvm
->
last_bt_notif
.
bt_activity_grading
)
>=
IWL_BT_COEX_TRAFFIC_LOAD_HIGH
)
&&
(
is_mimo
(
tbl
->
lq_type
)))
{
if
(
lq_sta
->
last_bt_traffic
>
le32_to_cpu
(
mvm
->
last_bt_notif
.
bt_activity_grading
))
{
/*
* don't set scale_action, don't want to scale up if
* the rate scale doesn't otherwise think that is a
* good idea.
*/
}
else
if
(
lq_sta
->
last_bt_traffic
<=
le32_to_cpu
(
mvm
->
last_bt_notif
.
bt_activity_grading
))
{
scale_action
=
-
1
;
}
}
lq_sta
->
last_bt_traffic
=
le32_to_cpu
(
mvm
->
last_bt_notif
.
bt_activity_grading
);
if
((
le32_to_cpu
(
mvm
->
last_bt_notif
.
bt_activity_grading
)
>=
IWL_BT_COEX_TRAFFIC_LOAD_HIGH
)
&&
is_mimo
(
tbl
->
lq_type
))
{
/* search for a new modulation */
/* Force a search in case BT doesn't like us being in MIMO */
if
(
is_mimo
(
rate
)
&&
!
iwl_mvm_bt_coex_is_mimo_allowed
(
mvm
,
sta
))
{
IWL_DEBUG_RATE
(
mvm
,
"BT Coex forbids MIMO. Search for new config
\n
"
);
rs_stay_in_table
(
lq_sta
,
true
);
goto
lq_update
;
}
...
...
@@ -2000,6 +1982,9 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
if
(
low
!=
IWL_RATE_INVALID
)
{
update_lq
=
1
;
index
=
low
;
}
else
{
IWL_DEBUG_RATE
(
mvm
,
"At the bottom rate. Can't decrease
\n
"
);
}
break
;
...
...
@@ -2008,6 +1993,9 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
if
(
high
!=
IWL_RATE_INVALID
)
{
update_lq
=
1
;
index
=
high
;
}
else
{
IWL_DEBUG_RATE
(
mvm
,
"At the top rate. Can't increase
\n
"
);
}
break
;
...
...
@@ -2017,14 +2005,12 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
break
;
}
IWL_DEBUG_RATE
(
mvm
,
"choose rate scale index %d action %d low %d high %d type %d
\n
"
,
index
,
scale_action
,
low
,
high
,
tbl
->
lq_type
);
lq_update:
/* Replace uCode's rate table for the destination station. */
if
(
update_lq
)
rs_update_rate_tbl
(
mvm
,
sta
,
lq_sta
,
tbl
,
index
);
if
(
update_lq
)
{
tbl
->
rate
.
index
=
index
;
rs_update_rate_tbl
(
mvm
,
sta
,
lq_sta
,
&
tbl
->
rate
);
}
rs_stay_in_table
(
lq_sta
,
false
);
...
...
@@ -2035,20 +2021,29 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
* 3) Allowing a new search
*/
if
(
!
update_lq
&&
!
done_search
&&
!
lq_sta
->
stay_in_tbl
&&
window
->
counter
)
{
lq_sta
->
rs_state
==
RS_STATE_SEARCH_CYCLE_STARTED
&&
window
->
counter
)
{
enum
rs_column
next_column
;
/* Save current throughput to compare with "search" throughput*/
lq_sta
->
last_tpt
=
current_tpt
;
/* Select a new "search" modulation mode to try.
* If one is found, set up the new "search" table. */
if
(
is_legacy
(
tbl
->
lq_type
))
rs_move_legacy_other
(
mvm
,
lq_sta
,
sta
,
index
);
else
if
(
is_siso
(
tbl
->
lq_type
))
rs_move_siso_to_other
(
mvm
,
lq_sta
,
sta
,
index
);
else
if
(
is_mimo2
(
tbl
->
lq_type
))
rs_move_mimo2_to_other
(
mvm
,
lq_sta
,
sta
,
index
);
else
WARN_ON_ONCE
(
1
);
IWL_DEBUG_RATE
(
mvm
,
"Start Search: update_lq %d done_search %d rs_state %d win->counter %d
\n
"
,
update_lq
,
done_search
,
lq_sta
->
rs_state
,
window
->
counter
);
next_column
=
rs_get_next_column
(
mvm
,
lq_sta
,
sta
,
tbl
);
if
(
next_column
!=
RS_COLUMN_INVALID
)
{
int
ret
=
rs_switch_to_column
(
mvm
,
lq_sta
,
sta
,
next_column
);
if
(
!
ret
)
lq_sta
->
search_better_tbl
=
1
;
}
else
{
IWL_DEBUG_RATE
(
mvm
,
"No more columns to explore in search cycle. Go to RS_STATE_SEARCH_CYCLE_ENDED
\n
"
);
lq_sta
->
rs_state
=
RS_STATE_SEARCH_CYCLE_ENDED
;
}
/* If new "search" mode was selected, set up in uCode table */
if
(
lq_sta
->
search_better_tbl
)
{
...
...
@@ -2060,34 +2055,29 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
/* Use new "search" start rate */
index
=
iwl_hwrate_to_plcp_idx
(
tbl
->
current_rate
);
IWL_DEBUG_RATE
(
mvm
,
"Switch current mcs: %X index: %d
\n
"
,
tbl
->
current_rate
,
index
);
rs_dump_rate
(
mvm
,
&
tbl
->
rate
,
"Switch to SEARCH TABLE:"
);
rs_fill_link_cmd
(
mvm
,
sta
,
lq_sta
,
tbl
->
current_rate
);
iwl_mvm_send_lq_cmd
(
mvm
,
&
lq_sta
->
lq
,
CMD_ASYNC
,
false
);
iwl_mvm_send_lq_cmd
(
mvm
,
&
lq_sta
->
lq
,
false
);
}
else
{
done_search
=
1
;
}
}
if
(
done_search
&&
!
lq_sta
->
stay_in_tbl
)
{
if
(
done_search
&&
lq_sta
->
rs_state
==
RS_STATE_SEARCH_CYCLE_ENDED
)
{
/* If the "active" (non-search) mode was legacy,
* and we've tried switching antennas,
* but we haven't been able to try HT modes (not available),
* stay with best antenna legacy modulation for a while
* before next round of mode comparisons. */
tbl1
=
&
(
lq_sta
->
lq_info
[
lq_sta
->
active_tbl
]);
if
(
is_legacy
(
tbl1
->
lq_type
)
&&
!
sta
->
ht_cap
.
ht_supported
&&
lq_sta
->
action_counter
>
tbl1
->
max_search
)
{
if
(
is_legacy
(
&
tbl1
->
rate
)
&&
!
sta
->
ht_cap
.
ht_supported
)
{
IWL_DEBUG_RATE
(
mvm
,
"LQ: STAY in legacy table
\n
"
);
rs_set_stay_in_table
(
mvm
,
1
,
lq_sta
);
}
}
else
{
/* If we're in an HT mode, and all 3 mode switch actions
* have been tried and compared, stay in this best modulation
* mode for a while before next round of mode comparisons. */
if
(
lq_sta
->
enable_counter
&&
(
lq_sta
->
action_counter
>=
tbl1
->
max_search
))
{
if
((
lq_sta
->
last_tpt
>
IWL_AGG_TPT_THREHOLD
)
&&
(
lq_sta
->
tx_agg_tid_en
&
(
1
<<
tid
))
&&
(
tid
!=
IWL_MAX_TID_COUNT
))
{
...
...
@@ -2105,7 +2095,8 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
}
out:
tbl
->
current_rate
=
rate_n_flags_from_tbl
(
mvm
,
tbl
,
index
);
tbl
->
rate
.
index
=
index
;
tbl
->
current_rate
=
ucode_rate_from_rs_rate
(
mvm
,
&
tbl
->
rate
);
lq_sta
->
last_txrate_idx
=
index
;
}
...
...
@@ -2126,12 +2117,13 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
static
void
rs_initialize_lq
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
,
struct
iwl_lq_sta
*
lq_sta
,
enum
ieee80211_band
band
)
enum
ieee80211_band
band
,
bool
init
)
{
struct
iwl_scale_tbl_info
*
tbl
;
int
rate_idx
;
struct
rs_rate
*
rate
;
int
i
;
u32
rate
;
u32
ucode_
rate
;
u8
active_tbl
=
0
;
u8
valid_tx_ant
;
...
...
@@ -2148,27 +2140,33 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
active_tbl
=
1
-
lq_sta
->
active_tbl
;
tbl
=
&
(
lq_sta
->
lq_info
[
active_tbl
]);
rate
=
&
tbl
->
rate
;
if
((
i
<
0
)
||
(
i
>=
IWL_RATE_COUNT
))
i
=
0
;
rate
=
iwl_rates
[
i
].
plcp
;
tbl
->
ant_type
=
first_antenna
(
valid_tx_ant
);
rate
|=
tbl
->
ant_type
<<
RATE_MCS_ANT_POS
;
rate
->
index
=
i
;
rate
->
ant
=
first_antenna
(
valid_tx_ant
);
rate
->
sgi
=
false
;
rate
->
bw
=
RATE_MCS_CHAN_WIDTH_20
;
if
(
band
==
IEEE80211_BAND_5GHZ
)
rate
->
type
=
LQ_LEGACY_A
;
else
rate
->
type
=
LQ_LEGACY_G
;
if
(
i
>=
IWL_FIRST_CCK_RATE
&&
i
<=
IWL_LAST_CCK_RATE
)
rate
|=
RATE_MCS_CCK_MSK
;
ucode_rate
=
ucode_rate_from_rs_rate
(
mvm
,
rate
);
tbl
->
current_rate
=
ucode_rate
;
rs_get_tbl_info_from_mcs
(
rate
,
band
,
tbl
,
&
rate_idx
);
if
(
!
rs_is_valid_ant
(
valid_tx_ant
,
tbl
->
ant_type
))
rs_toggle_antenna
(
valid_tx_ant
,
&
rate
,
tbl
);
WARN_ON_ONCE
(
rate
->
ant
!=
ANT_A
&&
rate
->
ant
!=
ANT_B
);
if
(
rate
->
ant
==
ANT_A
)
tbl
->
column
=
RS_COLUMN_LEGACY_ANT_A
;
else
tbl
->
column
=
RS_COLUMN_LEGACY_ANT_B
;
rate
=
rate_n_flags_from_tbl
(
mvm
,
tbl
,
rate_idx
);
tbl
->
current_rate
=
rate
;
rs_set_expected_tpt_table
(
lq_sta
,
tbl
);
rs_fill_link_cmd
(
NULL
,
NULL
,
lq_sta
,
rate
);
rs_fill_link_cmd
(
NULL
,
NULL
,
lq_sta
,
ucode_
rate
);
/* TODO restore station should remember the lq cmd */
iwl_mvm_send_lq_cmd
(
mvm
,
&
lq_sta
->
lq
,
CMD_SYNC
,
true
);
iwl_mvm_send_lq_cmd
(
mvm
,
&
lq_sta
->
lq
,
init
);
}
static
void
rs_get_rate
(
void
*
mvm_r
,
struct
ieee80211_sta
*
sta
,
void
*
mvm_sta
,
...
...
@@ -2182,8 +2180,6 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta,
struct
ieee80211_tx_info
*
info
=
IEEE80211_SKB_CB
(
skb
);
struct
iwl_lq_sta
*
lq_sta
=
mvm_sta
;
IWL_DEBUG_RATE_LIMIT
(
mvm
,
"rate scale calculate new rate for skb
\n
"
);
/* Get max rate if user set max rate */
if
(
lq_sta
)
{
lq_sta
->
max_rate_idx
=
txrc
->
max_rate_idx
;
...
...
@@ -2242,11 +2238,51 @@ static int rs_vht_highest_rx_mcs_index(struct ieee80211_sta_vht_cap *vht_cap,
return
-
1
;
}
static
void
rs_vht_set_enabled_rates
(
struct
ieee80211_sta
*
sta
,
struct
ieee80211_sta_vht_cap
*
vht_cap
,
struct
iwl_lq_sta
*
lq_sta
)
{
int
i
;
int
highest_mcs
=
rs_vht_highest_rx_mcs_index
(
vht_cap
,
1
);
if
(
highest_mcs
>=
IWL_RATE_MCS_0_INDEX
)
{
for
(
i
=
IWL_RATE_MCS_0_INDEX
;
i
<=
highest_mcs
;
i
++
)
{
if
(
i
==
IWL_RATE_9M_INDEX
)
continue
;
/* VHT MCS9 isn't valid for 20Mhz for NSS=1,2 */
if
(
i
==
IWL_RATE_MCS_9_INDEX
&&
sta
->
bandwidth
==
IEEE80211_STA_RX_BW_20
)
continue
;
lq_sta
->
active_siso_rate
|=
BIT
(
i
);
}
}
if
(
sta
->
rx_nss
<
2
)
return
;
highest_mcs
=
rs_vht_highest_rx_mcs_index
(
vht_cap
,
2
);
if
(
highest_mcs
>=
IWL_RATE_MCS_0_INDEX
)
{
for
(
i
=
IWL_RATE_MCS_0_INDEX
;
i
<=
highest_mcs
;
i
++
)
{
if
(
i
==
IWL_RATE_9M_INDEX
)
continue
;
/* VHT MCS9 isn't valid for 20Mhz for NSS=1,2 */
if
(
i
==
IWL_RATE_MCS_9_INDEX
&&
sta
->
bandwidth
==
IEEE80211_STA_RX_BW_20
)
continue
;
lq_sta
->
active_mimo2_rate
|=
BIT
(
i
);
}
}
}
/*
* Called after adding a new station to initialize rate scaling
*/
void
iwl_mvm_rs_rate_init
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
,
enum
ieee80211_band
band
)
enum
ieee80211_band
band
,
bool
init
)
{
int
i
,
j
;
struct
ieee80211_hw
*
hw
=
mvm
->
hw
;
...
...
@@ -2259,6 +2295,8 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
sta_priv
=
(
struct
iwl_mvm_sta
*
)
sta
->
drv_priv
;
lq_sta
=
&
sta_priv
->
lq_sta
;
memset
(
lq_sta
,
0
,
sizeof
(
*
lq_sta
));
sband
=
hw
->
wiphy
->
bands
[
band
];
lq_sta
->
lq
.
sta_id
=
sta_priv
->
sta_id
;
...
...
@@ -2308,27 +2346,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
lq_sta
->
is_vht
=
false
;
}
else
{
int
highest_mcs
=
rs_vht_highest_rx_mcs_index
(
vht_cap
,
1
);
if
(
highest_mcs
>=
IWL_RATE_MCS_0_INDEX
)
{
for
(
i
=
IWL_RATE_MCS_0_INDEX
;
i
<=
highest_mcs
;
i
++
)
{
if
(
i
==
IWL_RATE_9M_INDEX
)
continue
;
lq_sta
->
active_siso_rate
|=
BIT
(
i
);
}
}
highest_mcs
=
rs_vht_highest_rx_mcs_index
(
vht_cap
,
2
);
if
(
highest_mcs
>=
IWL_RATE_MCS_0_INDEX
)
{
for
(
i
=
IWL_RATE_MCS_0_INDEX
;
i
<=
highest_mcs
;
i
++
)
{
if
(
i
==
IWL_RATE_9M_INDEX
)
continue
;
lq_sta
->
active_mimo2_rate
|=
BIT
(
i
);
}
}
/* TODO: avoid MCS9 in 20Mhz which isn't valid for 11ac */
rs_vht_set_enabled_rates
(
sta
,
vht_cap
,
lq_sta
);
lq_sta
->
is_vht
=
true
;
}
...
...
@@ -2341,15 +2359,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
/* These values will be overridden later */
lq_sta
->
lq
.
single_stream_ant_msk
=
first_antenna
(
iwl_fw_valid_tx_ant
(
mvm
->
fw
));
lq_sta
->
lq
.
dual_stream_ant_msk
=
iwl_fw_valid_tx_ant
(
mvm
->
fw
)
&
~
first_antenna
(
iwl_fw_valid_tx_ant
(
mvm
->
fw
));
if
(
!
lq_sta
->
lq
.
dual_stream_ant_msk
)
{
lq_sta
->
lq
.
dual_stream_ant_msk
=
ANT_AB
;
}
else
if
(
num_of_ant
(
iwl_fw_valid_tx_ant
(
mvm
->
fw
))
==
2
)
{
lq_sta
->
lq
.
dual_stream_ant_msk
=
iwl_fw_valid_tx_ant
(
mvm
->
fw
);
}
/* as default allow aggregation for all tids */
lq_sta
->
tx_agg_tid_en
=
IWL_AGG_ALL_TID
;
...
...
@@ -2364,16 +2374,33 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
lq_sta
->
dbg_fixed_rate
=
0
;
#endif
rs_initialize_lq
(
mvm
,
sta
,
lq_sta
,
band
);
rs_initialize_lq
(
mvm
,
sta
,
lq_sta
,
band
,
init
);
}
static
void
rs_rate_update
(
void
*
mvm_r
,
struct
ieee80211_supported_band
*
sband
,
struct
cfg80211_chan_def
*
chandef
,
struct
ieee80211_sta
*
sta
,
void
*
priv_sta
,
u32
changed
)
{
u8
tid
;
struct
iwl_op_mode
*
op_mode
=
(
struct
iwl_op_mode
*
)
mvm_r
;
struct
iwl_mvm
*
mvm
=
IWL_OP_MODE_GET_MVM
(
op_mode
);
/* Stop any ongoing aggregations as rs starts off assuming no agg */
for
(
tid
=
0
;
tid
<
IWL_MAX_TID_COUNT
;
tid
++
)
ieee80211_stop_tx_ba_session
(
sta
,
tid
);
iwl_mvm_rs_rate_init
(
mvm
,
sta
,
sband
->
band
,
false
);
}
static
void
rs_fill_link_cmd
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
,
struct
iwl_lq_sta
*
lq_sta
,
u32
new_rate
)
{
struct
iwl_scale_tbl_info
tbl_typ
e
;
struct
rs_rate
rat
e
;
int
index
=
0
;
int
rate_idx
;
int
repeat_rate
=
0
;
u8
ant_toggle_cnt
=
0
;
u8
use_ht_possible
=
1
;
...
...
@@ -2383,12 +2410,10 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
/* Override starting rate (index 0) if needed for debug purposes */
rs_dbgfs_set_mcs
(
lq_sta
,
&
new_rate
);
/* Interpret new_rate (rate_n_flags) */
rs_get_tbl_info_from_mcs
(
new_rate
,
lq_sta
->
band
,
&
tbl_type
,
&
rate_idx
);
rs_rate_from_ucode_rate
(
new_rate
,
lq_sta
->
band
,
&
rate
);
/* How many times should we repeat the initial rate? */
if
(
is_legacy
(
tbl_type
.
lq_typ
e
))
{
if
(
is_legacy
(
&
rat
e
))
{
ant_toggle_cnt
=
1
;
repeat_rate
=
IWL_NUMBER_TRY
;
}
else
{
...
...
@@ -2396,15 +2421,13 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
LINK_QUAL_AGG_DISABLE_START_DEF
-
1
);
}
lq_cmd
->
mimo_delim
=
is_mimo
(
tbl_type
.
lq_typ
e
)
?
1
:
0
;
lq_cmd
->
mimo_delim
=
is_mimo
(
&
rat
e
)
?
1
:
0
;
/* Fill 1st table entry (index 0) */
lq_cmd
->
rs_table
[
index
]
=
cpu_to_le32
(
new_rate
);
if
(
num_of_ant
(
tbl_type
.
ant_type
)
==
1
)
lq_cmd
->
single_stream_ant_msk
=
tbl_type
.
ant_type
;
else
if
(
num_of_ant
(
tbl_type
.
ant_type
)
==
2
)
lq_cmd
->
dual_stream_ant_msk
=
tbl_type
.
ant_type
;
if
(
num_of_ant
(
rate
.
ant
)
==
1
)
lq_cmd
->
single_stream_ant_msk
=
rate
.
ant
;
/* otherwise we don't modify the existing value */
index
++
;
...
...
@@ -2418,12 +2441,12 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
* For legacy IWL_NUMBER_TRY == 1, this loop will not execute.
* For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */
while
(
repeat_rate
>
0
&&
(
index
<
LINK_QUAL_MAX_RETRY_NUM
))
{
if
(
is_legacy
(
tbl_type
.
lq_typ
e
))
{
if
(
is_legacy
(
&
rat
e
))
{
if
(
ant_toggle_cnt
<
NUM_TRY_BEFORE_ANT_TOGGLE
)
ant_toggle_cnt
++
;
else
if
(
mvm
&&
rs_toggle_antenna
(
valid_tx_ant
,
&
new_rate
,
&
tbl_typ
e
))
&
new_rate
,
&
rat
e
))
ant_toggle_cnt
=
1
;
}
...
...
@@ -2437,26 +2460,25 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
index
++
;
}
rs_get_tbl_info_from_mcs
(
new_rate
,
lq_sta
->
band
,
&
tbl_type
,
&
rate_idx
);
rs_rate_from_ucode_rate
(
new_rate
,
lq_sta
->
band
,
&
rate
);
/* Indicate to uCode which entries might be MIMO.
* If initial rate was MIMO, this will finally end up
* as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */
if
(
is_mimo
(
tbl_type
.
lq_typ
e
))
if
(
is_mimo
(
&
rat
e
))
lq_cmd
->
mimo_delim
=
index
;
/* Get next rate */
new_rate
=
rs_get_lower_rate
(
lq_sta
,
&
tbl_type
,
rate_id
x
,
new_rate
=
rs_get_lower_rate
(
lq_sta
,
&
rate
,
rate
.
inde
x
,
use_ht_possible
);
/* How many times should we repeat the next rate? */
if
(
is_legacy
(
tbl_type
.
lq_typ
e
))
{
if
(
is_legacy
(
&
rat
e
))
{
if
(
ant_toggle_cnt
<
NUM_TRY_BEFORE_ANT_TOGGLE
)
ant_toggle_cnt
++
;
else
if
(
mvm
&&
rs_toggle_antenna
(
valid_tx_ant
,
&
new_rate
,
&
tbl_typ
e
))
&
new_rate
,
&
rat
e
))
ant_toggle_cnt
=
1
;
repeat_rate
=
IWL_NUMBER_TRY
;
...
...
@@ -2527,7 +2549,6 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
>>
RATE_MCS_ANT_POS
);
if
((
valid_tx_ant
&
ant_sel_tx
)
==
ant_sel_tx
)
{
*
rate_n_flags
=
lq_sta
->
dbg_fixed_rate
;
IWL_DEBUG_RATE
(
mvm
,
"Fixed rate ON
\n
"
);
}
else
{
lq_sta
->
dbg_fixed_rate
=
0
;
IWL_ERR
(
mvm
,
...
...
@@ -2535,9 +2556,60 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
ant_sel_tx
,
valid_tx_ant
);
IWL_DEBUG_RATE
(
mvm
,
"Fixed rate OFF
\n
"
);
}
}
}
static
int
rs_pretty_print_rate
(
char
*
buf
,
const
u32
rate
)
{
char
*
type
,
*
bw
;
u8
mcs
=
0
,
nss
=
0
;
u8
ant
=
(
rate
&
RATE_MCS_ANT_ABC_MSK
)
>>
RATE_MCS_ANT_POS
;
if
(
!
(
rate
&
RATE_MCS_HT_MSK
)
&&
!
(
rate
&
RATE_MCS_VHT_MSK
))
{
int
index
=
iwl_hwrate_to_plcp_idx
(
rate
);
return
sprintf
(
buf
,
"Legacy | ANT: %s Rate: %s Mbps
\n
"
,
rs_pretty_ant
(
ant
),
iwl_rate_mcs
[
index
].
mbps
);
}
if
(
rate
&
RATE_MCS_VHT_MSK
)
{
type
=
"VHT"
;
mcs
=
rate
&
RATE_VHT_MCS_RATE_CODE_MSK
;
nss
=
((
rate
&
RATE_VHT_MCS_NSS_MSK
)
>>
RATE_VHT_MCS_NSS_POS
)
+
1
;
}
else
if
(
rate
&
RATE_MCS_HT_MSK
)
{
type
=
"HT"
;
mcs
=
rate
&
RATE_HT_MCS_INDEX_MSK
;
}
else
{
IWL_DEBUG_RATE
(
mvm
,
"Fixed rate OFF
\n
"
);
type
=
"Unknown"
;
/* shouldn't happen */
}
switch
(
rate
&
RATE_MCS_CHAN_WIDTH_MSK
)
{
case
RATE_MCS_CHAN_WIDTH_20
:
bw
=
"20Mhz"
;
break
;
case
RATE_MCS_CHAN_WIDTH_40
:
bw
=
"40Mhz"
;
break
;
case
RATE_MCS_CHAN_WIDTH_80
:
bw
=
"80Mhz"
;
break
;
case
RATE_MCS_CHAN_WIDTH_160
:
bw
=
"160Mhz"
;
break
;
default:
bw
=
"BAD BW"
;
}
return
sprintf
(
buf
,
"%s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s%s
\n
"
,
type
,
rs_pretty_ant
(
ant
),
bw
,
mcs
,
nss
,
(
rate
&
RATE_MCS_SGI_MSK
)
?
"SGI "
:
"NGI "
,
(
rate
&
RATE_MCS_STBC_MSK
)
?
"STBC "
:
""
,
(
rate
&
RATE_MCS_LDPC_MSK
)
?
"LDPC "
:
""
,
(
rate
&
RATE_MCS_BF_MSK
)
?
"BF "
:
""
,
(
rate
&
RATE_MCS_ZLF_MSK
)
?
"ZLF "
:
""
);
}
static
ssize_t
rs_sta_dbgfs_scale_table_write
(
struct
file
*
file
,
...
...
@@ -2572,15 +2644,14 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
char
*
buff
;
int
desc
=
0
;
int
i
=
0
;
int
index
=
0
;
ssize_t
ret
;
struct
iwl_lq_sta
*
lq_sta
=
file
->
private_data
;
struct
iwl_mvm
*
mvm
;
struct
iwl_scale_tbl_info
*
tbl
=
&
(
lq_sta
->
lq_info
[
lq_sta
->
active_tbl
]);
struct
rs_rate
*
rate
=
&
tbl
->
rate
;
mvm
=
lq_sta
->
drv
;
buff
=
kmalloc
(
1024
,
GFP_KERNEL
);
buff
=
kmalloc
(
2048
,
GFP_KERNEL
);
if
(
!
buff
)
return
-
ENOMEM
;
...
...
@@ -2595,23 +2666,23 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
(
iwl_fw_valid_tx_ant
(
mvm
->
fw
)
&
ANT_B
)
?
"ANT_B,"
:
""
,
(
iwl_fw_valid_tx_ant
(
mvm
->
fw
)
&
ANT_C
)
?
"ANT_C"
:
""
);
desc
+=
sprintf
(
buff
+
desc
,
"lq type %s
\n
"
,
(
is_legacy
(
tbl
->
lq_typ
e
))
?
"legacy"
:
is_vht
(
tbl
->
lq_typ
e
)
?
"VHT"
:
"HT"
);
if
(
is_ht
(
tbl
->
lq_typ
e
))
{
(
is_legacy
(
rat
e
))
?
"legacy"
:
is_vht
(
rat
e
)
?
"VHT"
:
"HT"
);
if
(
!
is_legacy
(
rat
e
))
{
desc
+=
sprintf
(
buff
+
desc
,
" %s"
,
(
is_siso
(
tbl
->
lq_typ
e
))
?
"SISO"
:
"MIMO2"
);
(
is_siso
(
rat
e
))
?
"SISO"
:
"MIMO2"
);
desc
+=
sprintf
(
buff
+
desc
,
" %s"
,
(
is_ht20
(
tbl
))
?
"20MHz"
:
(
is_ht40
(
tbl
))
?
"40MHz"
:
(
is_ht80
(
tbl
))
?
"80Mhz"
:
"BAD BW"
);
(
is_ht20
(
rate
))
?
"20MHz"
:
(
is_ht40
(
rate
))
?
"40MHz"
:
(
is_ht80
(
rate
))
?
"80Mhz"
:
"BAD BW"
);
desc
+=
sprintf
(
buff
+
desc
,
" %s %s
\n
"
,
(
tbl
->
is_SGI
)
?
"SGI"
:
"
"
,
(
rate
->
sgi
)
?
"SGI"
:
"NGI
"
,
(
lq_sta
->
is_agg
)
?
"AGG on"
:
""
);
}
desc
+=
sprintf
(
buff
+
desc
,
"last tx rate=0x%X
\n
"
,
lq_sta
->
last_rate_n_flags
);
desc
+=
sprintf
(
buff
+
desc
,
"general: flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x
\n
"
,
"general: flags=0x%X mimo-d=%d s-ant
=
0x%x d-ant=0x%x
\n
"
,
lq_sta
->
lq
.
flags
,
lq_sta
->
lq
.
mimo_delim
,
lq_sta
->
lq
.
single_stream_ant_msk
,
...
...
@@ -2631,19 +2702,12 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
lq_sta
->
lq
.
initial_rate_index
[
3
]);
for
(
i
=
0
;
i
<
LINK_QUAL_MAX_RETRY_NUM
;
i
++
)
{
index
=
iwl_hwrate_to_plcp_idx
(
le32_to_cpu
(
lq_sta
->
lq
.
rs_table
[
i
]));
if
(
is_legacy
(
tbl
->
lq_type
))
{
desc
+=
sprintf
(
buff
+
desc
,
" rate[%d] 0x%X %smbps
\n
"
,
i
,
le32_to_cpu
(
lq_sta
->
lq
.
rs_table
[
i
]),
iwl_rate_mcs
[
index
].
mbps
);
}
else
{
u32
rate
=
le32_to_cpu
(
lq_sta
->
lq
.
rs_table
[
i
]);
desc
+=
sprintf
(
buff
+
desc
,
" rate[%d] 0x%X %smbps (%s)
\n
"
,
i
,
le32_to_cpu
(
lq_sta
->
lq
.
rs_table
[
i
]),
iwl_rate_mcs
[
index
].
mbps
,
iwl_rate_mcs
[
index
].
mcs
);
}
" rate[%d] 0x%X "
,
i
,
rate
);
desc
+=
rs_pretty_print_rate
(
buff
+
desc
,
rate
);
}
ret
=
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buff
,
desc
);
...
...
@@ -2665,6 +2729,7 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
int
i
,
j
;
ssize_t
ret
;
struct
iwl_scale_tbl_info
*
tbl
;
struct
rs_rate
*
rate
;
struct
iwl_lq_sta
*
lq_sta
=
file
->
private_data
;
buff
=
kmalloc
(
1024
,
GFP_KERNEL
);
...
...
@@ -2673,15 +2738,16 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
for
(
i
=
0
;
i
<
LQ_SIZE
;
i
++
)
{
tbl
=
&
(
lq_sta
->
lq_info
[
i
]);
rate
=
&
tbl
->
rate
;
desc
+=
sprintf
(
buff
+
desc
,
"%s type=%d SGI=%d BW=%s DUP=0
\n
"
"rate=0x%X
\n
"
,
lq_sta
->
active_tbl
==
i
?
"*"
:
"x"
,
tbl
->
lq_
type
,
tbl
->
is_SGI
,
is_ht20
(
tbl
)
?
"20Mhz"
:
is_ht40
(
tbl
)
?
"40Mhz"
:
is_ht80
(
tbl
)
?
"80Mhz"
:
"ERR"
,
rate
->
type
,
rate
->
sgi
,
is_ht20
(
rate
)
?
"20Mhz"
:
is_ht40
(
rate
)
?
"40Mhz"
:
is_ht80
(
rate
)
?
"80Mhz"
:
"ERR"
,
tbl
->
current_rate
);
for
(
j
=
0
;
j
<
IWL_RATE_COUNT
;
j
++
)
{
desc
+=
sprintf
(
buff
+
desc
,
...
...
@@ -2746,6 +2812,7 @@ static struct rate_control_ops rs_mvm_ops = {
.
free
=
rs_free
,
.
alloc_sta
=
rs_alloc_sta
,
.
free_sta
=
rs_free_sta
,
.
rate_update
=
rs_rate_update
,
#ifdef CONFIG_MAC80211_DEBUGFS
.
add_sta_debugfs
=
rs_add_debugfs
,
.
remove_sta_debugfs
=
rs_remove_debugfs
,
...
...
@@ -2778,13 +2845,13 @@ int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
if
(
enable
)
{
if
(
mvmsta
->
tx_protection
==
0
)
lq
->
flags
|=
LQ_FLAG_
SET_STA_TLC
_RTS_MSK
;
lq
->
flags
|=
LQ_FLAG_
USE
_RTS_MSK
;
mvmsta
->
tx_protection
++
;
}
else
{
mvmsta
->
tx_protection
--
;
if
(
mvmsta
->
tx_protection
==
0
)
lq
->
flags
&=
~
LQ_FLAG_
SET_STA_TLC
_RTS_MSK
;
lq
->
flags
&=
~
LQ_FLAG_
USE
_RTS_MSK
;
}
return
iwl_mvm_send_lq_cmd
(
mvm
,
lq
,
CMD_ASYNC
,
false
);
return
iwl_mvm_send_lq_cmd
(
mvm
,
lq
,
false
);
}
drivers/net/wireless/iwlwifi/mvm/rs.h
View file @
d9a577c3
...
...
@@ -155,38 +155,7 @@ enum {
#define IWL_RATE_SCALE_SWITCH 10880
/* 85% */
#define IWL_RATE_HIGH_TH 10880
/* 85% */
#define IWL_RATE_INCREASE_TH 6400
/* 50% */
#define IWL_RATE_DECREASE_TH 1920
/* 15% */
/* possible actions when in legacy mode */
enum
{
IWL_LEGACY_SWITCH_ANTENNA
,
IWL_LEGACY_SWITCH_SISO
,
IWL_LEGACY_SWITCH_MIMO2
,
IWL_LEGACY_FIRST_ACTION
=
IWL_LEGACY_SWITCH_ANTENNA
,
IWL_LEGACY_LAST_ACTION
=
IWL_LEGACY_SWITCH_MIMO2
,
};
/* possible actions when in siso mode */
enum
{
IWL_SISO_SWITCH_ANTENNA
,
IWL_SISO_SWITCH_MIMO2
,
IWL_SISO_SWITCH_GI
,
IWL_SISO_FIRST_ACTION
=
IWL_SISO_SWITCH_ANTENNA
,
IWL_SISO_LAST_ACTION
=
IWL_SISO_SWITCH_GI
,
};
/* possible actions when in mimo mode */
enum
{
IWL_MIMO2_SWITCH_SISO_A
,
IWL_MIMO2_SWITCH_SISO_B
,
IWL_MIMO2_SWITCH_GI
,
IWL_MIMO2_FIRST_ACTION
=
IWL_MIMO2_SWITCH_SISO_A
,
IWL_MIMO2_LAST_ACTION
=
IWL_MIMO2_SWITCH_GI
,
};
#define IWL_MAX_SEARCH IWL_MIMO2_LAST_ACTION
#define IWL_ACTION_LIMIT 3
/* # possible actions */
#define RS_SR_FORCE_DECREASE 1920
/* 15% */
#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000)
/* 4 milliseconds */
#define LINK_QUAL_AGG_TIME_LIMIT_MAX (8000)
...
...
@@ -224,22 +193,45 @@ enum iwl_table_type {
LQ_MAX
,
};
#define is_legacy(tbl) (((tbl) == LQ_LEGACY_G) || ((tbl) == LQ_LEGACY_A))
#define is_ht_siso(tbl) ((tbl) == LQ_HT_SISO)
#define is_ht_mimo2(tbl) ((tbl) == LQ_HT_MIMO2)
#define is_vht_siso(tbl) ((tbl) == LQ_VHT_SISO)
#define is_vht_mimo2(tbl) ((tbl) == LQ_VHT_MIMO2)
#define is_siso(tbl) (is_ht_siso(tbl) || is_vht_siso(tbl))
#define is_mimo2(tbl) (is_ht_mimo2(tbl) || is_vht_mimo2(tbl))
#define is_mimo(tbl) (is_mimo2(tbl))
#define is_ht(tbl) (is_ht_siso(tbl) || is_ht_mimo2(tbl))
#define is_vht(tbl) (is_vht_siso(tbl) || is_vht_mimo2(tbl))
#define is_a_band(tbl) ((tbl) == LQ_LEGACY_A)
#define is_g_band(tbl) ((tbl) == LQ_LEGACY_G)
#define is_ht20(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_20)
#define is_ht40(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_40)
#define is_ht80(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_80)
struct
rs_rate
{
int
index
;
enum
iwl_table_type
type
;
u8
ant
;
u32
bw
;
bool
sgi
;
};
#define is_type_legacy(type) (((type) == LQ_LEGACY_G) || \
((type) == LQ_LEGACY_A))
#define is_type_ht_siso(type) ((type) == LQ_HT_SISO)
#define is_type_ht_mimo2(type) ((type) == LQ_HT_MIMO2)
#define is_type_vht_siso(type) ((type) == LQ_VHT_SISO)
#define is_type_vht_mimo2(type) ((type) == LQ_VHT_MIMO2)
#define is_type_siso(type) (is_type_ht_siso(type) || is_type_vht_siso(type))
#define is_type_mimo2(type) (is_type_ht_mimo2(type) || is_type_vht_mimo2(type))
#define is_type_mimo(type) (is_type_mimo2(type))
#define is_type_ht(type) (is_type_ht_siso(type) || is_type_ht_mimo2(type))
#define is_type_vht(type) (is_type_vht_siso(type) || is_type_vht_mimo2(type))
#define is_type_a_band(type) ((type) == LQ_LEGACY_A)
#define is_type_g_band(type) ((type) == LQ_LEGACY_G)
#define is_legacy(rate) is_type_legacy((rate)->type)
#define is_ht_siso(rate) is_type_ht_siso((rate)->type)
#define is_ht_mimo2(rate) is_type_ht_mimo2((rate)->type)
#define is_vht_siso(rate) is_type_vht_siso((rate)->type)
#define is_vht_mimo2(rate) is_type_vht_mimo2((rate)->type)
#define is_siso(rate) is_type_siso((rate)->type)
#define is_mimo2(rate) is_type_mimo2((rate)->type)
#define is_mimo(rate) is_type_mimo((rate)->type)
#define is_ht(rate) is_type_ht((rate)->type)
#define is_vht(rate) is_type_vht((rate)->type)
#define is_a_band(rate) is_type_a_band((rate)->type)
#define is_g_band(rate) is_type_g_band((rate)->type)
#define is_ht20(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_20)
#define is_ht40(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_40)
#define is_ht80(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_80)
#define IWL_MAX_MCS_DISPLAY_SIZE 12
...
...
@@ -257,7 +249,23 @@ struct iwl_rate_scale_data {
s32
success_ratio
;
/* per-cent * 128 */
s32
counter
;
/* number of frames attempted */
s32
average_tpt
;
/* success ratio * expected throughput */
unsigned
long
stamp
;
};
/* Possible Tx columns
* Tx Column = a combo of legacy/siso/mimo x antenna x SGI
*/
enum
rs_column
{
RS_COLUMN_LEGACY_ANT_A
=
0
,
RS_COLUMN_LEGACY_ANT_B
,
RS_COLUMN_SISO_ANT_A
,
RS_COLUMN_SISO_ANT_B
,
RS_COLUMN_SISO_ANT_A_SGI
,
RS_COLUMN_SISO_ANT_B_SGI
,
RS_COLUMN_MIMO2
,
RS_COLUMN_MIMO2_SGI
,
RS_COLUMN_LAST
=
RS_COLUMN_MIMO2_SGI
,
RS_COLUMN_INVALID
,
};
/**
...
...
@@ -267,17 +275,19 @@ struct iwl_rate_scale_data {
* one for "active", and one for "search".
*/
struct
iwl_scale_tbl_info
{
enum
iwl_table_type
lq_type
;
u8
ant_type
;
u8
is_SGI
;
/* 1 = short guard interval */
u32
bw
;
/* channel bandwidth; RATE_MCS_CHAN_WIDTH_XX */
u8
action
;
/* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
u8
max_search
;
/* maximun number of tables we can search */
struct
rs_rate
rate
;
enum
rs_column
column
;
s32
*
expected_tpt
;
/* throughput metrics; expected_tpt_G, etc. */
u32
current_rate
;
/* rate_n_flags, uCode API format */
struct
iwl_rate_scale_data
win
[
IWL_RATE_COUNT
];
/* rate histories */
};
enum
{
RS_STATE_SEARCH_CYCLE_STARTED
,
RS_STATE_SEARCH_CYCLE_ENDED
,
RS_STATE_STAY_IN_COLUMN
,
};
/**
* struct iwl_lq_sta -- driver's rate scaling private structure
*
...
...
@@ -285,8 +295,7 @@ struct iwl_scale_tbl_info {
*/
struct
iwl_lq_sta
{
u8
active_tbl
;
/* index of active table, range 0-1 */
u8
enable_counter
;
/* indicates HT mode */
u8
stay_in_tbl
;
/* 1: disallow, 0: allow search for new mode */
u8
rs_state
;
/* RS_STATE_* */
u8
search_better_tbl
;
/* 1: currently trying alternate mode */
s32
last_tpt
;
...
...
@@ -299,7 +308,9 @@ struct iwl_lq_sta {
u32
total_success
;
/* total successful frames, any/all rates */
u64
flush_timer
;
/* time staying in mode before new search */
u8
action_counter
;
/* # mode-switch actions tried */
u32
visited_columns
;
/* Bitmask marking which Tx columns were
* explored during a search cycle
*/
bool
is_vht
;
enum
ieee80211_band
band
;
...
...
@@ -328,32 +339,11 @@ struct iwl_lq_sta {
u32
last_rate_n_flags
;
/* packets destined for this STA are aggregated */
u8
is_agg
;
/* BT traffic this sta was last updated in */
u8
last_bt_traffic
;
};
enum
iwl_bt_coex_profile_traffic_load
{
IWL_BT_COEX_TRAFFIC_LOAD_NONE
=
0
,
IWL_BT_COEX_TRAFFIC_LOAD_LOW
=
1
,
IWL_BT_COEX_TRAFFIC_LOAD_HIGH
=
2
,
IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS
=
3
,
/*
* There are no more even though below is a u8, the
* indication from the BT device only has two bits.
*/
};
static
inline
u8
num_of_ant
(
u8
mask
)
{
return
!!
((
mask
)
&
ANT_A
)
+
!!
((
mask
)
&
ANT_B
)
+
!!
((
mask
)
&
ANT_C
);
}
/* Initialize station's rate scaling information after adding station */
void
iwl_mvm_rs_rate_init
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
,
enum
ieee80211_band
band
);
enum
ieee80211_band
band
,
bool
init
);
/**
* iwl_rate_control_register - Register the rate control algorithm callbacks
...
...
drivers/net/wireless/iwlwifi/mvm/scan.c
View file @
d9a577c3
...
...
@@ -70,6 +70,9 @@
#define IWL_PLCP_QUIET_THRESH 1
#define IWL_ACTIVE_QUIET_TIME 10
#define LONG_OUT_TIME_PERIOD 600
#define SHORT_OUT_TIME_PERIOD 200
#define SUSPEND_TIME_PERIOD 100
static
inline
__le16
iwl_mvm_scan_rx_chain
(
struct
iwl_mvm
*
mvm
)
{
...
...
@@ -87,20 +90,22 @@ static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm)
return
cpu_to_le16
(
rx_chain
);
}
static
inline
__le32
iwl_mvm_scan_max_out_time
(
struct
ieee80211_vif
*
vif
)
static
inline
__le32
iwl_mvm_scan_max_out_time
(
struct
ieee80211_vif
*
vif
,
u32
flags
,
bool
is_assoc
)
{
if
(
vif
->
bss_conf
.
assoc
)
return
cpu_to_le32
(
200
*
1024
);
else
if
(
!
is_assoc
)
return
0
;
if
(
flags
&
NL80211_SCAN_FLAG_LOW_PRIORITY
)
return
cpu_to_le32
(
ieee80211_tu_to_usec
(
SHORT_OUT_TIME_PERIOD
));
return
cpu_to_le32
(
ieee80211_tu_to_usec
(
LONG_OUT_TIME_PERIOD
));
}
static
inline
__le32
iwl_mvm_scan_suspend_time
(
struct
ieee80211_vif
*
vif
)
static
inline
__le32
iwl_mvm_scan_suspend_time
(
struct
ieee80211_vif
*
vif
,
bool
is_assoc
)
{
if
(
!
vif
->
bss_conf
.
assoc
)
if
(
!
is_
assoc
)
return
0
;
return
cpu_to_le32
(
ieee80211_tu_to_usec
(
vif
->
bss_conf
.
beacon_int
));
return
cpu_to_le32
(
ieee80211_tu_to_usec
(
SUSPEND_TIME_PERIOD
));
}
static
inline
__le32
...
...
@@ -262,6 +267,15 @@ static u16 iwl_mvm_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta,
return
(
u16
)
len
;
}
static
void
iwl_mvm_vif_assoc_iterator
(
void
*
data
,
u8
*
mac
,
struct
ieee80211_vif
*
vif
)
{
bool
*
is_assoc
=
data
;
if
(
vif
->
bss_conf
.
assoc
)
*
is_assoc
=
true
;
}
int
iwl_mvm_scan_request
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
cfg80211_scan_request
*
req
)
...
...
@@ -274,6 +288,7 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
.
dataflags
=
{
IWL_HCMD_DFL_NOCOPY
,
},
};
struct
iwl_scan_cmd
*
cmd
=
mvm
->
scan_cmd
;
bool
is_assoc
=
false
;
int
ret
;
u32
status
;
int
ssid_len
=
0
;
...
...
@@ -289,13 +304,17 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
memset
(
cmd
,
0
,
sizeof
(
struct
iwl_scan_cmd
)
+
mvm
->
fw
->
ucode_capa
.
max_probe_length
+
(
MAX_NUM_SCAN_CHANNELS
*
sizeof
(
struct
iwl_scan_channel
)));
ieee80211_iterate_active_interfaces_atomic
(
mvm
->
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
iwl_mvm_vif_assoc_iterator
,
&
is_assoc
);
cmd
->
channel_count
=
(
u8
)
req
->
n_channels
;
cmd
->
quiet_time
=
cpu_to_le16
(
IWL_ACTIVE_QUIET_TIME
);
cmd
->
quiet_plcp_th
=
cpu_to_le16
(
IWL_PLCP_QUIET_THRESH
);
cmd
->
rxchain_sel_flags
=
iwl_mvm_scan_rx_chain
(
mvm
);
cmd
->
max_out_time
=
iwl_mvm_scan_max_out_time
(
vif
);
cmd
->
suspend_time
=
iwl_mvm_scan_suspend_time
(
vif
);
cmd
->
max_out_time
=
iwl_mvm_scan_max_out_time
(
vif
,
req
->
flags
,
is_assoc
);
cmd
->
suspend_time
=
iwl_mvm_scan_suspend_time
(
vif
,
is_assoc
);
cmd
->
rxon_flags
=
iwl_mvm_scan_rxon_flags
(
req
);
cmd
->
filter_flags
=
cpu_to_le32
(
MAC_FILTER_ACCEPT_GRP
|
MAC_FILTER_IN_BEACON
);
...
...
@@ -522,6 +541,12 @@ static void iwl_build_scan_cmd(struct iwl_mvm *mvm,
struct
cfg80211_sched_scan_request
*
req
,
struct
iwl_scan_offload_cmd
*
scan
)
{
bool
is_assoc
=
false
;
ieee80211_iterate_active_interfaces_atomic
(
mvm
->
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
iwl_mvm_vif_assoc_iterator
,
&
is_assoc
);
scan
->
channel_count
=
mvm
->
nvm_data
->
bands
[
IEEE80211_BAND_2GHZ
].
n_channels
+
mvm
->
nvm_data
->
bands
[
IEEE80211_BAND_5GHZ
].
n_channels
;
...
...
@@ -529,8 +554,9 @@ static void iwl_build_scan_cmd(struct iwl_mvm *mvm,
scan
->
quiet_plcp_th
=
cpu_to_le16
(
IWL_PLCP_QUIET_THRESH
);
scan
->
good_CRC_th
=
IWL_GOOD_CRC_TH_DEFAULT
;
scan
->
rx_chain
=
iwl_mvm_scan_rx_chain
(
mvm
);
scan
->
max_out_time
=
cpu_to_le32
(
200
*
1024
);
scan
->
suspend_time
=
iwl_mvm_scan_suspend_time
(
vif
);
scan
->
max_out_time
=
iwl_mvm_scan_max_out_time
(
vif
,
req
->
flags
,
is_assoc
);
scan
->
suspend_time
=
iwl_mvm_scan_suspend_time
(
vif
,
is_assoc
);
scan
->
filter_flags
|=
cpu_to_le32
(
MAC_FILTER_ACCEPT_GRP
|
MAC_FILTER_IN_BEACON
);
scan
->
scan_type
=
cpu_to_le32
(
SCAN_TYPE_BACKGROUND
);
...
...
@@ -817,11 +843,10 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
IWL_DEBUG_SCAN
(
mvm
,
"Sending scheduled scan with filtering, filter len %d
\n
"
,
req
->
n_match_sets
);
scan_req
.
flags
|=
cpu_to_le16
(
IWL_SCAN_OFFLOAD_FLAG_FILTER_SSID
);
}
else
{
IWL_DEBUG_SCAN
(
mvm
,
"Sending Scheduled scan without filtering
\n
"
);
scan_req
.
flags
|=
cpu_to_le16
(
IWL_SCAN_OFFLOAD_FLAG_PASS_ALL
);
}
return
iwl_mvm_send_cmd_pdu
(
mvm
,
SCAN_OFFLOAD_REQUEST_CMD
,
CMD_SYNC
,
...
...
drivers/net/wireless/iwlwifi/mvm/sta.c
View file @
d9a577c3
...
...
@@ -840,7 +840,7 @@ static const u8 tid_to_ac[] = {
int
iwl_mvm_sta_tx_agg_start
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_sta
*
sta
,
u16
tid
,
u16
*
ssn
)
{
struct
iwl_mvm_sta
*
mvmsta
=
(
void
*
)
sta
->
drv_priv
;
struct
iwl_mvm_sta
*
mvmsta
=
iwl_mvm_sta_from_mac80211
(
sta
)
;
struct
iwl_mvm_tid_data
*
tid_data
;
int
txq_id
;
...
...
@@ -895,7 +895,7 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
int
iwl_mvm_sta_tx_agg_oper
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_sta
*
sta
,
u16
tid
,
u8
buf_size
)
{
struct
iwl_mvm_sta
*
mvmsta
=
(
void
*
)
sta
->
drv_priv
;
struct
iwl_mvm_sta
*
mvmsta
=
iwl_mvm_sta_from_mac80211
(
sta
)
;
struct
iwl_mvm_tid_data
*
tid_data
=
&
mvmsta
->
tid_data
[
tid
];
int
queue
,
fifo
,
ret
;
u16
ssn
;
...
...
@@ -945,13 +945,13 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
*/
}
return
iwl_mvm_send_lq_cmd
(
mvm
,
&
mvmsta
->
lq_sta
.
lq
,
CMD_ASYNC
,
false
);
return
iwl_mvm_send_lq_cmd
(
mvm
,
&
mvmsta
->
lq_sta
.
lq
,
false
);
}
int
iwl_mvm_sta_tx_agg_stop
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_sta
*
sta
,
u16
tid
)
{
struct
iwl_mvm_sta
*
mvmsta
=
(
void
*
)
sta
->
drv_priv
;
struct
iwl_mvm_sta
*
mvmsta
=
iwl_mvm_sta_from_mac80211
(
sta
)
;
struct
iwl_mvm_tid_data
*
tid_data
=
&
mvmsta
->
tid_data
[
tid
];
u16
txq_id
;
int
err
;
...
...
@@ -1023,7 +1023,7 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
int
iwl_mvm_sta_tx_agg_flush
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_sta
*
sta
,
u16
tid
)
{
struct
iwl_mvm_sta
*
mvmsta
=
(
void
*
)
sta
->
drv_priv
;
struct
iwl_mvm_sta
*
mvmsta
=
iwl_mvm_sta_from_mac80211
(
sta
)
;
struct
iwl_mvm_tid_data
*
tid_data
=
&
mvmsta
->
tid_data
[
tid
];
u16
txq_id
;
enum
iwl_mvm_agg_state
old_state
;
...
...
@@ -1416,7 +1416,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
void
iwl_mvm_sta_modify_ps_wake
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
)
{
struct
iwl_mvm_sta
*
mvmsta
=
(
void
*
)
sta
->
drv_priv
;
struct
iwl_mvm_sta
*
mvmsta
=
iwl_mvm_sta_from_mac80211
(
sta
)
;
struct
iwl_mvm_add_sta_cmd_v6
cmd
=
{
.
add_modify
=
STA_MODE_MODIFY
,
.
sta_id
=
mvmsta
->
sta_id
,
...
...
@@ -1438,7 +1438,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
u16
sleep_state_flags
=
(
reason
==
IEEE80211_FRAME_RELEASE_UAPSD
)
?
STA_SLEEP_STATE_UAPSD
:
STA_SLEEP_STATE_PS_POLL
;
struct
iwl_mvm_sta
*
mvmsta
=
(
void
*
)
sta
->
drv_priv
;
struct
iwl_mvm_sta
*
mvmsta
=
iwl_mvm_sta_from_mac80211
(
sta
)
;
struct
iwl_mvm_add_sta_cmd_v6
cmd
=
{
.
add_modify
=
STA_MODE_MODIFY
,
.
sta_id
=
mvmsta
->
sta_id
,
...
...
drivers/net/wireless/iwlwifi/mvm/sta.h
View file @
d9a577c3
...
...
@@ -298,6 +298,12 @@ struct iwl_mvm_sta {
bool
tt_tx_protection
;
};
static
inline
struct
iwl_mvm_sta
*
iwl_mvm_sta_from_mac80211
(
struct
ieee80211_sta
*
sta
)
{
return
(
void
*
)
sta
->
drv_priv
;
}
/**
* struct iwl_mvm_int_sta - representation of an internal station (auxiliary or
* broadcast)
...
...
drivers/net/wireless/iwlwifi/mvm/tt.c
View file @
d9a577c3
...
...
@@ -388,7 +388,7 @@ static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable)
lockdep_is_held
(
&
mvm
->
mutex
));
if
(
IS_ERR_OR_NULL
(
sta
))
continue
;
mvmsta
=
(
void
*
)
sta
->
drv_priv
;
mvmsta
=
iwl_mvm_sta_from_mac80211
(
sta
)
;
if
(
enable
==
mvmsta
->
tt_tx_protection
)
continue
;
err
=
iwl_mvm_tx_protection
(
mvm
,
mvmsta
,
enable
);
...
...
drivers/net/wireless/iwlwifi/mvm/tx.c
View file @
d9a577c3
...
...
@@ -276,6 +276,7 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,
return
NULL
;
memset
(
dev_cmd
,
0
,
sizeof
(
*
dev_cmd
));
dev_cmd
->
hdr
.
cmd
=
TX_CMD
;
tx_cmd
=
(
struct
iwl_tx_cmd
*
)
dev_cmd
->
payload
;
if
(
info
->
control
.
hw_key
)
...
...
@@ -361,7 +362,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
u8
txq_id
=
info
->
hw_queue
;
bool
is_data_qos
=
false
,
is_ampdu
=
false
;
mvmsta
=
(
void
*
)
sta
->
drv_priv
;
mvmsta
=
iwl_mvm_sta_from_mac80211
(
sta
)
;
fc
=
hdr
->
frame_control
;
if
(
WARN_ON_ONCE
(
!
mvmsta
))
...
...
@@ -432,7 +433,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
static
void
iwl_mvm_check_ratid_empty
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
,
u8
tid
)
{
struct
iwl_mvm_sta
*
mvmsta
=
(
void
*
)
sta
->
drv_priv
;
struct
iwl_mvm_sta
*
mvmsta
=
iwl_mvm_sta_from_mac80211
(
sta
)
;
struct
iwl_mvm_tid_data
*
tid_data
=
&
mvmsta
->
tid_data
[
tid
];
struct
ieee80211_vif
*
vif
=
mvmsta
->
vif
;
...
...
@@ -662,7 +663,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
sta
=
rcu_dereference
(
mvm
->
fw_id_to_mac_id
[
sta_id
]);
if
(
!
IS_ERR_OR_NULL
(
sta
))
{
mvmsta
=
(
void
*
)
sta
->
drv_priv
;
mvmsta
=
iwl_mvm_sta_from_mac80211
(
sta
)
;
if
(
tid
!=
IWL_TID_NON_QOS
)
{
struct
iwl_mvm_tid_data
*
tid_data
=
...
...
@@ -793,7 +794,7 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,
sta
=
rcu_dereference
(
mvm
->
fw_id_to_mac_id
[
sta_id
]);
if
(
!
WARN_ON_ONCE
(
IS_ERR_OR_NULL
(
sta
)))
{
struct
iwl_mvm_sta
*
mvmsta
=
(
void
*
)
sta
->
drv_priv
;
struct
iwl_mvm_sta
*
mvmsta
=
iwl_mvm_sta_from_mac80211
(
sta
)
;
mvmsta
->
tid_data
[
tid
].
rate_n_flags
=
le32_to_cpu
(
tx_resp
->
initial_rate
);
}
...
...
@@ -849,7 +850,7 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
return
0
;
}
mvmsta
=
(
void
*
)
sta
->
drv_priv
;
mvmsta
=
iwl_mvm_sta_from_mac80211
(
sta
)
;
tid_data
=
&
mvmsta
->
tid_data
[
tid
];
if
(
WARN_ONCE
(
tid_data
->
txq_id
!=
scd_flow
,
"Q %d, tid %d, flow %d"
,
...
...
drivers/net/wireless/iwlwifi/mvm/utils.c
View file @
d9a577c3
...
...
@@ -486,22 +486,18 @@ void iwl_mvm_dump_sram(struct iwl_mvm *mvm)
* this case to clear the state indicating that station creation is in
* progress.
*/
int
iwl_mvm_send_lq_cmd
(
struct
iwl_mvm
*
mvm
,
struct
iwl_lq_cmd
*
lq
,
u8
flags
,
bool
init
)
int
iwl_mvm_send_lq_cmd
(
struct
iwl_mvm
*
mvm
,
struct
iwl_lq_cmd
*
lq
,
bool
init
)
{
struct
iwl_host_cmd
cmd
=
{
.
id
=
LQ_CMD
,
.
len
=
{
sizeof
(
struct
iwl_lq_cmd
),
},
.
flags
=
flags
,
.
flags
=
init
?
CMD_SYNC
:
CMD_ASYNC
,
.
data
=
{
lq
,
},
};
if
(
WARN_ON
(
lq
->
sta_id
==
IWL_MVM_STATION_COUNT
))
return
-
EINVAL
;
if
(
WARN_ON
(
init
&&
(
cmd
.
flags
&
CMD_ASYNC
)))
return
-
EINVAL
;
return
iwl_mvm_send_cmd
(
mvm
,
&
cmd
);
}
...
...
drivers/net/wireless/iwlwifi/pcie/drv.c
View file @
d9a577c3
...
...
@@ -297,6 +297,9 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{
IWL_PCI_DEVICE
(
0x08B2
,
0x4370
,
iwl7260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x08B2
,
0x4360
,
iwl7260_2n_cfg
)},
{
IWL_PCI_DEVICE
(
0x08B1
,
0x5070
,
iwl7260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x08B1
,
0x5072
,
iwl7260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x08B1
,
0x5170
,
iwl7260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x08B1
,
0x5770
,
iwl7260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x08B1
,
0x4020
,
iwl7260_2n_cfg
)},
{
IWL_PCI_DEVICE
(
0x08B1
,
0x402A
,
iwl7260_2n_cfg
)},
{
IWL_PCI_DEVICE
(
0x08B2
,
0x4220
,
iwl7260_2n_cfg
)},
...
...
@@ -350,6 +353,8 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{
IWL_PCI_DEVICE
(
0x08B4
,
0x8270
,
iwl3160_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x08B3
,
0x8470
,
iwl3160_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x08B3
,
0x8570
,
iwl3160_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x08B3
,
0x1070
,
iwl3160_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x08B3
,
0x1170
,
iwl3160_2ac_cfg
)},
/* 7265 Series */
{
IWL_PCI_DEVICE
(
0x095A
,
0x5010
,
iwl7265_2ac_cfg
)},
...
...
drivers/net/wireless/iwlwifi/pcie/rx.c
View file @
d9a577c3
...
...
@@ -1126,7 +1126,6 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data)
struct
iwl_trans
*
trans
=
data
;
struct
iwl_trans_pcie
*
trans_pcie
=
IWL_TRANS_GET_PCIE_TRANS
(
trans
);
u32
inta
,
inta_mask
;
irqreturn_t
ret
=
IRQ_NONE
;
lockdep_assert_held
(
&
trans_pcie
->
irq_lock
);
...
...
@@ -1155,7 +1154,16 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data)
* or due to sporadic interrupts thrown from our NIC. */
if
(
!
inta
)
{
IWL_DEBUG_ISR
(
trans
,
"Ignore interrupt, inta == 0
\n
"
);
goto
none
;
/*
* Re-enable interrupts here since we don't have anything to
* service, but only in case the handler won't run. Note that
* the handler can be scheduled because of a previous
* interrupt.
*/
if
(
test_bit
(
STATUS_INT_ENABLED
,
&
trans_pcie
->
status
)
&&
!
trans_pcie
->
inta
)
iwl_enable_interrupts
(
trans
);
return
IRQ_NONE
;
}
if
((
inta
==
0xFFFFFFFF
)
||
((
inta
&
0xFFFFFFF0
)
==
0xa5a5a5a0
))
{
...
...
@@ -1173,19 +1181,7 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data)
trans_pcie
->
inta
|=
inta
;
/* the thread will service interrupts and re-enable them */
if
(
likely
(
inta
))
return
IRQ_WAKE_THREAD
;
ret
=
IRQ_HANDLED
;
none:
/* re-enable interrupts here since we don't have anything to service. */
/* only Re-enable if disabled by irq and no schedules tasklet. */
if
(
test_bit
(
STATUS_INT_ENABLED
,
&
trans_pcie
->
status
)
&&
!
trans_pcie
->
inta
)
iwl_enable_interrupts
(
trans
);
return
ret
;
}
/* interrupt handler using ict table, with this interrupt driver will
...
...
drivers/net/wireless/iwlwifi/pcie/tx.c
View file @
d9a577c3
...
...
@@ -1542,23 +1542,18 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
}
if
(
!
ret
)
{
if
(
test_bit
(
STATUS_HCMD_ACTIVE
,
&
trans_pcie
->
status
))
{
struct
iwl_txq
*
txq
=
&
trans_pcie
->
txq
[
trans_pcie
->
cmd_queue
];
struct
iwl_txq
*
txq
=
&
trans_pcie
->
txq
[
trans_pcie
->
cmd_queue
];
struct
iwl_queue
*
q
=
&
txq
->
q
;
IWL_ERR
(
trans
,
"Error sending %s: time out after %dms.
\n
"
,
IWL_ERR
(
trans
,
"Error sending %s: time out after %dms.
\n
"
,
get_cmd_string
(
trans_pcie
,
cmd
->
id
),
jiffies_to_msecs
(
HOST_COMPLETE_TIMEOUT
));
IWL_ERR
(
trans
,
"Current CMD queue read_ptr %d write_ptr %d
\n
"
,
IWL_ERR
(
trans
,
"Current CMD queue read_ptr %d write_ptr %d
\n
"
,
q
->
read_ptr
,
q
->
write_ptr
);
clear_bit
(
STATUS_HCMD_ACTIVE
,
&
trans_pcie
->
status
);
IWL_DEBUG_INFO
(
trans
,
"Clearing HCMD_ACTIVE for command %s
\n
"
,
IWL_DEBUG_INFO
(
trans
,
"Clearing HCMD_ACTIVE for command %s
\n
"
,
get_cmd_string
(
trans_pcie
,
cmd
->
id
));
ret
=
-
ETIMEDOUT
;
...
...
@@ -1566,7 +1561,6 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
goto
cancel
;
}
}
if
(
test_bit
(
STATUS_FW_ERROR
,
&
trans_pcie
->
status
))
{
IWL_ERR
(
trans
,
"FW error in SYNC CMD %s
\n
"
,
...
...
@@ -1674,7 +1668,6 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
txq
->
entries
[
q
->
write_ptr
].
skb
=
skb
;
txq
->
entries
[
q
->
write_ptr
].
cmd
=
dev_cmd
;
dev_cmd
->
hdr
.
cmd
=
REPLY_TX
;
dev_cmd
->
hdr
.
sequence
=
cpu_to_le16
((
u16
)(
QUEUE_TO_SEQ
(
txq_id
)
|
INDEX_TO_SEQ
(
q
->
write_ptr
)));
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment