Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
kernel_linux
提交
d9a577c3
K
kernel_linux
项目概览
OpenHarmony
/
kernel_linux
上一次同步 4 年多
通知
15
Star
8
Fork
2
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
kernel_linux
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
d9a577c3
编写于
12月 11, 2013
作者:
J
John W. Linville
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'for-john' of
git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
上级
d6b5075d
9d10849e
变更
30
隐藏空白更改
内联
并排
Showing
30 changed file
with
1538 addition
and
1592 deletion
+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
未找到文件。
drivers/net/wireless/iwlwifi/dvm/rs.h
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
)
{
pme_asserted
=
iwl_trans_read_mem32
(
mvm
->
trans
,
mvm
->
d3_test_pme_ptr
);
if
(
pme_asserted
)
break
;
/* 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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
,
enum
ieee80211_band
band
,
struct
iwl_scale_tbl_info
*
tbl
,
int
*
rate_idx
)
/* 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
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,30 +896,31 @@ 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
&
rate_mask
=
(
u16
)(
rate_mask
&
(
lq_sta
->
supp_rates
<<
IWL_FIRST_OFDM_RATE
));
else
rate_mask
=
(
u16
)(
rate_mask
&
lq_sta
->
supp_rates
);
...
...
@@ -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,417 +1365,14 @@ 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
false
;
}
/*
* Set up search table for MIMO2
*/
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
)
{
u16
rate_mask
;
s32
rate
;
if
(
!
sta
->
ht_cap
.
ht_supported
)
return
-
1
;
if
(
sta
->
smps_mode
==
IEEE80211_SMPS_STATIC
)
return
-
1
;
/* Need both Tx chains/antennas to support MIMO */
if
(
num_of_ant
(
iwl_fw_valid_tx_ant
(
mvm
->
fw
))
<
2
)
return
-
1
;
IWL_DEBUG_RATE
(
mvm
,
"LQ: try to switch to MIMO2
\n
"
);
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
;
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
);
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
;
}
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
;
}
/*
* Set up search table for SISO
*/
static
int
rs_switch_to_siso
(
struct
iwl_mvm
*
mvm
,
struct
iwl_lq_sta
*
lq_sta
,
struct
ieee80211_sta
*
sta
,
struct
iwl_scale_tbl_info
*
tbl
,
int
index
)
{
u16
rate_mask
;
s32
rate
;
if
(
!
sta
->
ht_cap
.
ht_supported
)
return
-
1
;
IWL_DEBUG_RATE
(
mvm
,
"LQ: try to switch to SISO
\n
"
);
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
;
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
);
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
;
}
/*
* Try to switch to new modulation mode from legacy
*/
static
int
rs_move_legacy_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
);
int
ret
;
u8
update_search_tbl_counter
=
0
;
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
(
tx_chains_num
<=
1
)
break
;
/* Don't change antenna if success has been great */
if
(
window
->
success_ratio
>=
IWL_RS_GOOD_RATIO
)
break
;
/* Set up search table to try other antenna */
memcpy
(
search_tbl
,
tbl
,
sz
);
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
;
}
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
;
}
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
;
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
);
}
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
;
}
/*
* 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
;
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
;
}
/*
* Try to switch to new modulation mode from MIMO2
*/
static
int
rs_move_mimo2_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
)]);
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
;
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
;
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
(
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_MIMO2_LAST_ACTION
);
if
(
update_search_tbl_counter
)
search_tbl
->
action
=
tbl
->
action
;
return
RATE_MCS_CHAN_WIDTH_40
;
return
0
;
return
RATE_MCS_CHAN_WIDTH_2
0
;
}
/*
...
...
@@ -1591,13 +1396,13 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
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
)
{
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
+
IWL_RATE_SCALE_FLUSH_INTVL
));
RS_STAY_IN_COLUMN_TIMEOUT
));
/*
* Check if we should allow search for new modulation mode.
...
...
@@ -1619,10 +1424,14 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
flush_interval_passed
);
/* Allow search for new mode */
lq_sta
->
stay_in_tbl
=
0
;
/* only place reset */
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
...
...
@@ -1646,7 +1455,8 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
/* 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
)
{
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
]));
}
...
...
@@ -1659,15 +1469,13 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
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
)
struct
rs_rate
*
rate
)
{
u32
rate
;
u32
ucode_
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
);
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
);
}
static
u8
rs_get_tid
(
struct
iwl_lq_sta
*
lq_data
,
...
...
@@ -1686,6 +1494,162 @@ static u8 rs_get_tid(struct iwl_lq_sta *lq_data,
return
tid
;
}
static
enum
rs_column
rs_get_next_column
(
struct
iwl_mvm
*
mvm
,
struct
iwl_lq_sta
*
lq_sta
,
struct
ieee80211_sta
*
sta
,
struct
iwl_scale_tbl_info
*
tbl
)
{
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
;
if
(
lq_sta
->
visited_columns
&
BIT
(
next_col_id
))
{
IWL_DEBUG_RATE
(
mvm
,
"Skip already visited column %d
\n
"
,
next_col_id
);
continue
;
}
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
;
}
for
(
j
=
0
;
j
<
MAX_COLUMN_CHECKS
;
j
++
)
{
allow_func
=
next_col
->
checks
[
j
];
if
(
allow_func
&&
!
allow_func
(
mvm
,
sta
,
tbl
))
break
;
}
if
(
j
!=
MAX_COLUMN_CHECKS
)
{
IWL_DEBUG_RATE
(
mvm
,
"Skip column %d: not allowed (check %d failed)
\n
"
,
next_col_id
,
j
);
continue
;
}
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
;
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
];
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
;
}
break
;
}
if
(
i
==
MAX_NEXT_COLUMNS
)
return
RS_COLUMN_INVALID
;
IWL_DEBUG_RATE
(
mvm
,
"Found potential column %d
\n
"
,
next_col_id
);
return
next_col_id
;
}
static
int
rs_switch_to_column
(
struct
iwl_mvm
*
mvm
,
struct
iwl_lq_sta
*
lq_sta
,
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
));
u16
rate_mask
=
0
;
u32
rate_idx
=
0
;
memcpy
(
search_tbl
,
tbl
,
sz
);
rate
->
sgi
=
column
->
sgi
;
rate
->
ant
=
column
->
ant
;
if
(
column
->
mode
==
RS_LEGACY
)
{
if
(
lq_sta
->
band
==
IEEE80211_BAND_5GHZ
)
rate
->
type
=
LQ_LEGACY_A
;
else
rate
->
type
=
LQ_LEGACY_G
;
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"
);
}
rate
->
bw
=
rs_bw_from_sta_bw
(
sta
);
search_tbl
->
column
=
col_id
;
rs_set_expected_tpt_table
(
lq_sta
,
search_tbl
);
/* Get the best matching rate if we're changing modes. e.g.
* SISO->MIMO, LEGACY->SISO, MIMO->SISO
*/
if
(
curr_column
->
mode
!=
column
->
mode
)
{
rate_idx
=
rs_get_best_rate
(
mvm
,
lq_sta
,
search_tbl
,
rate_mask
,
rate
->
index
);
if
((
rate_idx
==
IWL_RATE_INVALID
)
||
!
(
BIT
(
rate_idx
)
&
rate_mask
))
{
IWL_DEBUG_RATE
(
mvm
,
"can not switch with index %d"
" rate mask %x
\n
"
,
rate_idx
,
rate_mask
);
goto
err
;
}
rate
->
index
=
rate_idx
;
}
/* 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
*/
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
);
lq_sta
->
visited_columns
|=
BIT
(
col_id
);
return
0
;
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,20 +1882,31 @@ 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
...
...
@@ -1934,8 +1914,12 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
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
);
}
lq_sta
->
lq
.
dual_stream_ant_msk
=
ANT_AB
;
/* 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
{
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
);
}
u32
rate
=
le32_to_cpu
(
lq_sta
->
lq
.
rs_table
[
i
]);
desc
+=
sprintf
(
buff
+
desc
,
" 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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
;
return
IRQ_WAKE_THREAD
;
}
/* interrupt handler using ict table, with this interrupt driver will
...
...
drivers/net/wireless/iwlwifi/pcie/tx.c
浏览文件 @
d9a577c3
...
...
@@ -1542,30 +1542,24 @@ 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_queue
*
q
=
&
txq
->
q
;
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
"
,
get_cmd_string
(
trans_pcie
,
cmd
->
id
),
jiffies_to_msecs
(
HOST_COMPLETE_TIMEOUT
));
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
"
,
q
->
read_ptr
,
q
->
write_ptr
);
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
"
,
get_cmd_string
(
trans_pcie
,
cmd
->
id
));
ret
=
-
ETIMEDOUT
;
clear_bit
(
STATUS_HCMD_ACTIVE
,
&
trans_pcie
->
status
);
IWL_DEBUG_INFO
(
trans
,
"Clearing HCMD_ACTIVE for command %s
\n
"
,
get_cmd_string
(
trans_pcie
,
cmd
->
id
));
ret
=
-
ETIMEDOUT
;
iwl_nic_error
(
trans
);
iwl_nic_error
(
trans
);
goto
cancel
;
}
goto
cancel
;
}
if
(
test_bit
(
STATUS_FW_ERROR
,
&
trans_pcie
->
status
))
{
...
...
@@ -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
)));
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录