Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
kernel_linux
提交
cbe1bc23
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看板
提交
cbe1bc23
编写于
12月 01, 2014
作者:
J
John W. Linville
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'for-linville' of
git://github.com/kvalo/ath
上级
992066c8
fe2407a8
变更
16
显示空白变更内容
内联
并排
Showing
16 changed file
with
1257 addition
and
749 deletion
+1257
-749
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/ath/ath10k/core.c
+13
-0
drivers/net/wireless/ath/ath10k/core.h
drivers/net/wireless/ath/ath10k/core.h
+11
-2
drivers/net/wireless/ath/ath10k/debug.c
drivers/net/wireless/ath/ath10k/debug.c
+248
-14
drivers/net/wireless/ath/ath10k/debug.h
drivers/net/wireless/ath/ath10k/debug.h
+1
-9
drivers/net/wireless/ath/ath10k/hif.h
drivers/net/wireless/ath/ath10k/hif.h
+39
-4
drivers/net/wireless/ath/ath10k/htc.c
drivers/net/wireless/ath/ath10k/htc.c
+8
-5
drivers/net/wireless/ath/ath10k/htt.h
drivers/net/wireless/ath/ath10k/htt.h
+6
-1
drivers/net/wireless/ath/ath10k/htt_rx.c
drivers/net/wireless/ath/ath10k/htt_rx.c
+594
-575
drivers/net/wireless/ath/ath10k/htt_tx.c
drivers/net/wireless/ath/ath10k/htt_tx.c
+4
-3
drivers/net/wireless/ath/ath10k/hw.h
drivers/net/wireless/ath/ath10k/hw.h
+10
-5
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath10k/mac.c
+162
-40
drivers/net/wireless/ath/ath10k/mac.h
drivers/net/wireless/ath/ath10k/mac.h
+4
-0
drivers/net/wireless/ath/ath10k/pci.c
drivers/net/wireless/ath/ath10k/pci.c
+20
-8
drivers/net/wireless/ath/ath10k/trace.h
drivers/net/wireless/ath/ath10k/trace.h
+17
-14
drivers/net/wireless/ath/ath10k/wmi.c
drivers/net/wireless/ath/ath10k/wmi.c
+52
-9
drivers/net/wireless/ath/ath10k/wmi.h
drivers/net/wireless/ath/ath10k/wmi.h
+68
-60
未找到文件。
drivers/net/wireless/ath/ath10k/core.c
浏览文件 @
cbe1bc23
...
...
@@ -799,6 +799,17 @@ static void ath10k_core_restart(struct work_struct *work)
mutex_unlock
(
&
ar
->
conf_mutex
);
}
static
void
ath10k_core_init_max_sta_count
(
struct
ath10k
*
ar
)
{
if
(
test_bit
(
ATH10K_FW_FEATURE_WMI_10X
,
ar
->
fw_features
))
{
ar
->
max_num_peers
=
TARGET_10X_NUM_PEERS
;
ar
->
max_num_stations
=
TARGET_10X_NUM_STATIONS
;
}
else
{
ar
->
max_num_peers
=
TARGET_NUM_PEERS
;
ar
->
max_num_stations
=
TARGET_NUM_STATIONS
;
}
}
int
ath10k_core_start
(
struct
ath10k
*
ar
,
enum
ath10k_firmware_mode
mode
)
{
int
status
;
...
...
@@ -1035,6 +1046,8 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
return
ret
;
}
ath10k_core_init_max_sta_count
(
ar
);
mutex_lock
(
&
ar
->
conf_mutex
);
ret
=
ath10k_core_start
(
ar
,
ATH10K_FIRMWARE_MODE_NORMAL
);
...
...
drivers/net/wireless/ath/ath10k/core.h
浏览文件 @
cbe1bc23
...
...
@@ -79,10 +79,12 @@ static inline const char *ath10k_bus_str(enum ath10k_bus bus)
struct
ath10k_skb_cb
{
dma_addr_t
paddr
;
u8
eid
;
u8
vdev_id
;
struct
{
u8
tid
;
u16
freq
;
bool
is_offchan
;
struct
ath10k_htt_txbuf
*
txbuf
;
u32
txbuf_paddr
;
...
...
@@ -122,6 +124,7 @@ struct ath10k_wmi {
struct
completion
service_ready
;
struct
completion
unified_ready
;
wait_queue_head_t
tx_credits_wq
;
DECLARE_BITMAP
(
svc_map
,
WMI_SERVICE_MAX
);
struct
wmi_cmd_map
*
cmd
;
struct
wmi_vdev_param_map
*
vdev_param
;
struct
wmi_pdev_param_map
*
pdev_param
;
...
...
@@ -218,6 +221,8 @@ struct ath10k_peer {
int
vdev_id
;
u8
addr
[
ETH_ALEN
];
DECLARE_BITMAP
(
peer_ids
,
ATH10K_MAX_NUM_PEER_IDS
);
/* protected by ar->data_lock */
struct
ieee80211_key_conf
*
keys
[
WMI_MAX_KEY_INDEX
+
1
];
};
...
...
@@ -310,7 +315,6 @@ struct ath10k_debug {
struct
ath10k_fw_stats
fw_stats
;
struct
completion
fw_stats_complete
;
bool
fw_stats_done
;
DECLARE_BITMAP
(
wmi_service_bitmap
,
WMI_SERVICE_MAX
);
unsigned
long
htt_stats_mask
;
struct
delayed_work
htt_stats_dwork
;
...
...
@@ -320,6 +324,7 @@ struct ath10k_debug {
/* protected by conf_mutex */
u32
fw_dbglog_mask
;
u32
pktlog_filter
;
u32
reg_addr
;
u8
htt_max_amsdu
;
u8
htt_max_ampdu
;
...
...
@@ -560,8 +565,12 @@ struct ath10k {
struct
list_head
peers
;
wait_queue_head_t
peer_mapping_wq
;
/*
number of created peers; protected by data_lock
*/
/*
protected by conf_mutex
*/
int
num_peers
;
int
num_stations
;
int
max_num_peers
;
int
max_num_stations
;
struct
work_struct
offchan_tx_work
;
struct
sk_buff_head
offchan_tx_queue
;
...
...
drivers/net/wireless/ath/ath10k/debug.c
浏览文件 @
cbe1bc23
...
...
@@ -17,9 +17,8 @@
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/version.h>
#include <linux/vermagic.h>
#include <linux/vmalloc.h>
#include <linux/utsname.h>
#include "core.h"
#include "debug.h"
...
...
@@ -124,7 +123,7 @@ EXPORT_SYMBOL(ath10k_info);
void
ath10k_print_driver_info
(
struct
ath10k
*
ar
)
{
ath10k_info
(
ar
,
"%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d.%d.%d.%d cal %s
\n
"
,
ath10k_info
(
ar
,
"%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d.%d.%d.%d cal %s
max_sta %d
\n
"
,
ar
->
hw_params
.
name
,
ar
->
target_version
,
ar
->
chip_id
,
...
...
@@ -136,7 +135,8 @@ void ath10k_print_driver_info(struct ath10k *ar)
ar
->
fw_version_minor
,
ar
->
fw_version_release
,
ar
->
fw_version_build
,
ath10k_cal_mode_str
(
ar
->
cal_mode
));
ath10k_cal_mode_str
(
ar
->
cal_mode
),
ar
->
max_num_stations
);
ath10k_info
(
ar
,
"debug %d debugfs %d tracing %d dfs %d testmode %d
\n
"
,
config_enabled
(
CONFIG_ATH10K_DEBUG
),
config_enabled
(
CONFIG_ATH10K_DEBUGFS
),
...
...
@@ -179,13 +179,6 @@ EXPORT_SYMBOL(ath10k_warn);
#ifdef CONFIG_ATH10K_DEBUGFS
void
ath10k_debug_read_service_map
(
struct
ath10k
*
ar
,
const
void
*
service_map
,
size_t
map_size
)
{
memcpy
(
ar
->
debug
.
wmi_service_bitmap
,
service_map
,
map_size
);
}
static
ssize_t
ath10k_read_wmi_services
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
...
...
@@ -207,8 +200,9 @@ static ssize_t ath10k_read_wmi_services(struct file *file,
if
(
len
>
buf_len
)
len
=
buf_len
;
spin_lock_bh
(
&
ar
->
data_lock
);
for
(
i
=
0
;
i
<
WMI_SERVICE_MAX
;
i
++
)
{
enabled
=
test_bit
(
i
,
ar
->
debug
.
wmi_service_bit
map
);
enabled
=
test_bit
(
i
,
ar
->
wmi
.
svc_
map
);
name
=
wmi_service_name
(
i
);
if
(
!
name
)
{
...
...
@@ -224,6 +218,7 @@ static ssize_t ath10k_read_wmi_services(struct file *file,
"%-40s %s
\n
"
,
name
,
enabled
?
"enabled"
:
"-"
);
}
spin_unlock_bh
(
&
ar
->
data_lock
);
ret_cnt
=
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
len
);
...
...
@@ -866,8 +861,8 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
strlcpy
(
dump_data
->
fw_ver
,
ar
->
hw
->
wiphy
->
fw_version
,
sizeof
(
dump_data
->
fw_ver
));
dump_data
->
kernel_ver_code
=
cpu_to_le32
(
LINUX_VERSION_CODE
)
;
strlcpy
(
dump_data
->
kernel_ver
,
VERMAGIC_STRING
,
dump_data
->
kernel_ver_code
=
0
;
strlcpy
(
dump_data
->
kernel_ver
,
init_utsname
()
->
release
,
sizeof
(
dump_data
->
kernel_ver
));
dump_data
->
tv_sec
=
cpu_to_le64
(
crash_data
->
timestamp
.
tv_sec
);
...
...
@@ -929,6 +924,236 @@ static const struct file_operations fops_fw_crash_dump = {
.
llseek
=
default_llseek
,
};
static
ssize_t
ath10k_reg_addr_read
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ath10k
*
ar
=
file
->
private_data
;
u8
buf
[
32
];
unsigned
int
len
=
0
;
u32
reg_addr
;
mutex_lock
(
&
ar
->
conf_mutex
);
reg_addr
=
ar
->
debug
.
reg_addr
;
mutex_unlock
(
&
ar
->
conf_mutex
);
len
+=
scnprintf
(
buf
+
len
,
sizeof
(
buf
)
-
len
,
"0x%x
\n
"
,
reg_addr
);
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
len
);
}
static
ssize_t
ath10k_reg_addr_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ath10k
*
ar
=
file
->
private_data
;
u32
reg_addr
;
int
ret
;
ret
=
kstrtou32_from_user
(
user_buf
,
count
,
0
,
&
reg_addr
);
if
(
ret
)
return
ret
;
if
(
!
IS_ALIGNED
(
reg_addr
,
4
))
return
-
EFAULT
;
mutex_lock
(
&
ar
->
conf_mutex
);
ar
->
debug
.
reg_addr
=
reg_addr
;
mutex_unlock
(
&
ar
->
conf_mutex
);
return
count
;
}
static
const
struct
file_operations
fops_reg_addr
=
{
.
read
=
ath10k_reg_addr_read
,
.
write
=
ath10k_reg_addr_write
,
.
open
=
simple_open
,
.
owner
=
THIS_MODULE
,
.
llseek
=
default_llseek
,
};
static
ssize_t
ath10k_reg_value_read
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ath10k
*
ar
=
file
->
private_data
;
u8
buf
[
48
];
unsigned
int
len
;
u32
reg_addr
,
reg_val
;
int
ret
;
mutex_lock
(
&
ar
->
conf_mutex
);
if
(
ar
->
state
!=
ATH10K_STATE_ON
&&
ar
->
state
!=
ATH10K_STATE_UTF
)
{
ret
=
-
ENETDOWN
;
goto
exit
;
}
reg_addr
=
ar
->
debug
.
reg_addr
;
reg_val
=
ath10k_hif_read32
(
ar
,
reg_addr
);
len
=
scnprintf
(
buf
,
sizeof
(
buf
),
"0x%08x:0x%08x
\n
"
,
reg_addr
,
reg_val
);
ret
=
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
len
);
exit:
mutex_unlock
(
&
ar
->
conf_mutex
);
return
ret
;
}
static
ssize_t
ath10k_reg_value_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ath10k
*
ar
=
file
->
private_data
;
u32
reg_addr
,
reg_val
;
int
ret
;
mutex_lock
(
&
ar
->
conf_mutex
);
if
(
ar
->
state
!=
ATH10K_STATE_ON
&&
ar
->
state
!=
ATH10K_STATE_UTF
)
{
ret
=
-
ENETDOWN
;
goto
exit
;
}
reg_addr
=
ar
->
debug
.
reg_addr
;
ret
=
kstrtou32_from_user
(
user_buf
,
count
,
0
,
&
reg_val
);
if
(
ret
)
goto
exit
;
ath10k_hif_write32
(
ar
,
reg_addr
,
reg_val
);
ret
=
count
;
exit:
mutex_unlock
(
&
ar
->
conf_mutex
);
return
ret
;
}
static
const
struct
file_operations
fops_reg_value
=
{
.
read
=
ath10k_reg_value_read
,
.
write
=
ath10k_reg_value_write
,
.
open
=
simple_open
,
.
owner
=
THIS_MODULE
,
.
llseek
=
default_llseek
,
};
static
ssize_t
ath10k_mem_value_read
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ath10k
*
ar
=
file
->
private_data
;
u8
*
buf
;
int
ret
;
if
(
*
ppos
<
0
)
return
-
EINVAL
;
if
(
!
count
)
return
0
;
mutex_lock
(
&
ar
->
conf_mutex
);
buf
=
vmalloc
(
count
);
if
(
!
buf
)
{
ret
=
-
ENOMEM
;
goto
exit
;
}
if
(
ar
->
state
!=
ATH10K_STATE_ON
&&
ar
->
state
!=
ATH10K_STATE_UTF
)
{
ret
=
-
ENETDOWN
;
goto
exit
;
}
ret
=
ath10k_hif_diag_read
(
ar
,
*
ppos
,
buf
,
count
);
if
(
ret
)
{
ath10k_warn
(
ar
,
"failed to read address 0x%08x via diagnose window fnrom debugfs: %d
\n
"
,
(
u32
)(
*
ppos
),
ret
);
goto
exit
;
}
ret
=
copy_to_user
(
user_buf
,
buf
,
count
);
if
(
ret
)
{
ret
=
-
EFAULT
;
goto
exit
;
}
count
-=
ret
;
*
ppos
+=
count
;
ret
=
count
;
exit:
vfree
(
buf
);
mutex_unlock
(
&
ar
->
conf_mutex
);
return
ret
;
}
static
ssize_t
ath10k_mem_value_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ath10k
*
ar
=
file
->
private_data
;
u8
*
buf
;
int
ret
;
if
(
*
ppos
<
0
)
return
-
EINVAL
;
if
(
!
count
)
return
0
;
mutex_lock
(
&
ar
->
conf_mutex
);
buf
=
vmalloc
(
count
);
if
(
!
buf
)
{
ret
=
-
ENOMEM
;
goto
exit
;
}
if
(
ar
->
state
!=
ATH10K_STATE_ON
&&
ar
->
state
!=
ATH10K_STATE_UTF
)
{
ret
=
-
ENETDOWN
;
goto
exit
;
}
ret
=
copy_from_user
(
buf
,
user_buf
,
count
);
if
(
ret
)
{
ret
=
-
EFAULT
;
goto
exit
;
}
ret
=
ath10k_hif_diag_write
(
ar
,
*
ppos
,
buf
,
count
);
if
(
ret
)
{
ath10k_warn
(
ar
,
"failed to write address 0x%08x via diagnose window from debugfs: %d
\n
"
,
(
u32
)(
*
ppos
),
ret
);
goto
exit
;
}
*
ppos
+=
count
;
ret
=
count
;
exit:
vfree
(
buf
);
mutex_unlock
(
&
ar
->
conf_mutex
);
return
ret
;
}
static
const
struct
file_operations
fops_mem_value
=
{
.
read
=
ath10k_mem_value_read
,
.
write
=
ath10k_mem_value_write
,
.
open
=
simple_open
,
.
owner
=
THIS_MODULE
,
.
llseek
=
default_llseek
,
};
static
int
ath10k_debug_htt_stats_req
(
struct
ath10k
*
ar
)
{
u64
cookie
;
...
...
@@ -1630,6 +1855,15 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file
(
"fw_crash_dump"
,
S_IRUSR
,
ar
->
debug
.
debugfs_phy
,
ar
,
&
fops_fw_crash_dump
);
debugfs_create_file
(
"reg_addr"
,
S_IRUSR
|
S_IWUSR
,
ar
->
debug
.
debugfs_phy
,
ar
,
&
fops_reg_addr
);
debugfs_create_file
(
"reg_value"
,
S_IRUSR
|
S_IWUSR
,
ar
->
debug
.
debugfs_phy
,
ar
,
&
fops_reg_value
);
debugfs_create_file
(
"mem_value"
,
S_IRUSR
|
S_IWUSR
,
ar
->
debug
.
debugfs_phy
,
ar
,
&
fops_mem_value
);
debugfs_create_file
(
"chip_id"
,
S_IRUSR
,
ar
->
debug
.
debugfs_phy
,
ar
,
&
fops_chip_id
);
...
...
drivers/net/wireless/ath/ath10k/debug.h
浏览文件 @
cbe1bc23
...
...
@@ -35,6 +35,7 @@ enum ath10k_debug_mask {
ATH10K_DBG_BMI
=
0x00000400
,
ATH10K_DBG_REGULATORY
=
0x00000800
,
ATH10K_DBG_TESTMODE
=
0x00001000
,
ATH10K_DBG_WMI_PRINT
=
0x00002000
,
ATH10K_DBG_ANY
=
0xffffffff
,
};
...
...
@@ -61,9 +62,6 @@ int ath10k_debug_create(struct ath10k *ar);
void
ath10k_debug_destroy
(
struct
ath10k
*
ar
);
int
ath10k_debug_register
(
struct
ath10k
*
ar
);
void
ath10k_debug_unregister
(
struct
ath10k
*
ar
);
void
ath10k_debug_read_service_map
(
struct
ath10k
*
ar
,
const
void
*
service_map
,
size_t
map_size
);
void
ath10k_debug_fw_stats_process
(
struct
ath10k
*
ar
,
struct
sk_buff
*
skb
);
struct
ath10k_fw_crash_data
*
ath10k_debug_get_new_fw_crash_data
(
struct
ath10k
*
ar
);
...
...
@@ -108,12 +106,6 @@ static inline void ath10k_debug_unregister(struct ath10k *ar)
{
}
static
inline
void
ath10k_debug_read_service_map
(
struct
ath10k
*
ar
,
const
void
*
service_map
,
size_t
map_size
)
{
}
static
inline
void
ath10k_debug_fw_stats_process
(
struct
ath10k
*
ar
,
struct
sk_buff
*
skb
)
{
...
...
drivers/net/wireless/ath/ath10k/hif.h
浏览文件 @
cbe1bc23
...
...
@@ -20,6 +20,7 @@
#include <linux/kernel.h>
#include "core.h"
#include "debug.h"
struct
ath10k_hif_sg_item
{
u16
transfer_id
;
...
...
@@ -31,11 +32,9 @@ struct ath10k_hif_sg_item {
struct
ath10k_hif_cb
{
int
(
*
tx_completion
)(
struct
ath10k
*
ar
,
struct
sk_buff
*
wbuf
,
unsigned
transfer_id
);
struct
sk_buff
*
wbuf
);
int
(
*
rx_completion
)(
struct
ath10k
*
ar
,
struct
sk_buff
*
wbuf
,
u8
pipe_id
);
struct
sk_buff
*
wbuf
);
};
struct
ath10k_hif_ops
{
...
...
@@ -47,6 +46,8 @@ struct ath10k_hif_ops {
int
(
*
diag_read
)(
struct
ath10k
*
ar
,
u32
address
,
void
*
buf
,
size_t
buf_len
);
int
(
*
diag_write
)(
struct
ath10k
*
ar
,
u32
address
,
const
void
*
data
,
int
nbytes
);
/*
* API to handle HIF-specific BMI message exchanges, this API is
* synchronous and only allowed to be called from a context that
...
...
@@ -84,6 +85,10 @@ struct ath10k_hif_ops {
u16
(
*
get_free_queue_number
)(
struct
ath10k
*
ar
,
u8
pipe_id
);
u32
(
*
read32
)(
struct
ath10k
*
ar
,
u32
address
);
void
(
*
write32
)(
struct
ath10k
*
ar
,
u32
address
,
u32
value
);
/* Power up the device and enter BMI transfer mode for FW download */
int
(
*
power_up
)(
struct
ath10k
*
ar
);
...
...
@@ -108,6 +113,15 @@ static inline int ath10k_hif_diag_read(struct ath10k *ar, u32 address, void *buf
return
ar
->
hif
.
ops
->
diag_read
(
ar
,
address
,
buf
,
buf_len
);
}
static
inline
int
ath10k_hif_diag_write
(
struct
ath10k
*
ar
,
u32
address
,
const
void
*
data
,
int
nbytes
)
{
if
(
!
ar
->
hif
.
ops
->
diag_write
)
return
-
EOPNOTSUPP
;
return
ar
->
hif
.
ops
->
diag_write
(
ar
,
address
,
data
,
nbytes
);
}
static
inline
int
ath10k_hif_exchange_bmi_msg
(
struct
ath10k
*
ar
,
void
*
request
,
u32
request_len
,
void
*
response
,
u32
*
response_len
)
...
...
@@ -187,4 +201,25 @@ static inline int ath10k_hif_resume(struct ath10k *ar)
return
ar
->
hif
.
ops
->
resume
(
ar
);
}
static
inline
u32
ath10k_hif_read32
(
struct
ath10k
*
ar
,
u32
address
)
{
if
(
!
ar
->
hif
.
ops
->
read32
)
{
ath10k_warn
(
ar
,
"hif read32 not supported
\n
"
);
return
0xdeaddead
;
}
return
ar
->
hif
.
ops
->
read32
(
ar
,
address
);
}
static
inline
void
ath10k_hif_write32
(
struct
ath10k
*
ar
,
u32
address
,
u32
data
)
{
if
(
!
ar
->
hif
.
ops
->
write32
)
{
ath10k_warn
(
ar
,
"hif write32 not supported
\n
"
);
return
;
}
ar
->
hif
.
ops
->
write32
(
ar
,
address
,
data
);
}
#endif
/* _HIF_H_ */
drivers/net/wireless/ath/ath10k/htc.c
浏览文件 @
cbe1bc23
...
...
@@ -160,6 +160,7 @@ int ath10k_htc_send(struct ath10k_htc *htc,
ath10k_htc_prepare_tx_skb
(
ep
,
skb
);
skb_cb
->
eid
=
eid
;
skb_cb
->
paddr
=
dma_map_single
(
dev
,
skb
->
data
,
skb
->
len
,
DMA_TO_DEVICE
);
ret
=
dma_mapping_error
(
dev
,
skb_cb
->
paddr
);
if
(
ret
)
...
...
@@ -197,15 +198,18 @@ int ath10k_htc_send(struct ath10k_htc *htc,
}
static
int
ath10k_htc_tx_completion_handler
(
struct
ath10k
*
ar
,
struct
sk_buff
*
skb
,
unsigned
int
eid
)
struct
sk_buff
*
skb
)
{
struct
ath10k_htc
*
htc
=
&
ar
->
htc
;
struct
ath10k_htc_ep
*
ep
=
&
htc
->
endpoint
[
eid
];
struct
ath10k_skb_cb
*
skb_cb
;
struct
ath10k_htc_ep
*
ep
;
if
(
WARN_ON_ONCE
(
!
skb
))
return
0
;
skb_cb
=
ATH10K_SKB_CB
(
skb
);
ep
=
&
htc
->
endpoint
[
skb_cb
->
eid
];
ath10k_htc_notify_tx_completion
(
ep
,
skb
);
/* the skb now belongs to the completion handler */
...
...
@@ -317,8 +321,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc,
}
static
int
ath10k_htc_rx_completion_handler
(
struct
ath10k
*
ar
,
struct
sk_buff
*
skb
,
u8
pipe_id
)
struct
sk_buff
*
skb
)
{
int
status
=
0
;
struct
ath10k_htc
*
htc
=
&
ar
->
htc
;
...
...
drivers/net/wireless/ath/ath10k/htt.h
浏览文件 @
cbe1bc23
...
...
@@ -126,6 +126,7 @@ enum htt_data_tx_ext_tid {
* (HL hosts manage queues on the host )
* more_in_batch: only for HL hosts. indicates if more packets are
* pending. this allows target to wait and aggregate
* freq: 0 means home channel of given vdev. intended for offchannel
*/
struct
htt_data_tx_desc
{
u8
flags0
;
/* %HTT_DATA_TX_DESC_FLAGS0_ */
...
...
@@ -133,7 +134,8 @@ struct htt_data_tx_desc {
__le16
len
;
__le16
id
;
__le32
frags_paddr
;
__le32
peerid
;
__le16
peerid
;
__le16
freq
;
u8
prefetch
[
0
];
/* start of frame, for FW classification engine */
}
__packed
;
...
...
@@ -156,6 +158,9 @@ enum htt_rx_ring_flags {
HTT_RX_RING_FLAGS_PHY_DATA_RX
=
1
<<
15
};
#define HTT_RX_RING_SIZE_MIN 128
#define HTT_RX_RING_SIZE_MAX 2048
struct
htt_rx_ring_setup_ring
{
__le32
fw_idx_shadow_reg_paddr
;
__le32
rx_ring_base_paddr
;
...
...
drivers/net/wireless/ath/ath10k/htt_rx.c
浏览文件 @
cbe1bc23
...
...
@@ -25,19 +25,8 @@
#include <linux/log2.h>
/* slightly larger than one large A-MPDU */
#define HTT_RX_RING_SIZE_MIN 128
/* roughly 20 ms @ 1 Gbps of 1500B MSDUs */
#define HTT_RX_RING_SIZE_MAX 2048
#define HTT_RX_AVG_FRM_BYTES 1000
/* ms, very conservative */
#define HTT_RX_HOST_LATENCY_MAX_MS 20
/* ms, conservative */
#define HTT_RX_HOST_LATENCY_WORST_LIKELY_MS 10
#define HTT_RX_RING_SIZE 1024
#define HTT_RX_RING_FILL_LEVEL 1000
/* when under memory pressure rx ring refill may fail and needs a retry */
#define HTT_RX_RING_REFILL_RETRY_MS 50
...
...
@@ -45,68 +34,6 @@
static
int
ath10k_htt_rx_get_csum_state
(
struct
sk_buff
*
skb
);
static
void
ath10k_htt_txrx_compl_task
(
unsigned
long
ptr
);
static
int
ath10k_htt_rx_ring_size
(
struct
ath10k_htt
*
htt
)
{
int
size
;
/*
* It is expected that the host CPU will typically be able to
* service the rx indication from one A-MPDU before the rx
* indication from the subsequent A-MPDU happens, roughly 1-2 ms
* later. However, the rx ring should be sized very conservatively,
* to accomodate the worst reasonable delay before the host CPU
* services a rx indication interrupt.
*
* The rx ring need not be kept full of empty buffers. In theory,
* the htt host SW can dynamically track the low-water mark in the
* rx ring, and dynamically adjust the level to which the rx ring
* is filled with empty buffers, to dynamically meet the desired
* low-water mark.
*
* In contrast, it's difficult to resize the rx ring itself, once
* it's in use. Thus, the ring itself should be sized very
* conservatively, while the degree to which the ring is filled
* with empty buffers should be sized moderately conservatively.
*/
/* 1e6 bps/mbps / 1e3 ms per sec = 1000 */
size
=
htt
->
max_throughput_mbps
+
1000
/
(
8
*
HTT_RX_AVG_FRM_BYTES
)
*
HTT_RX_HOST_LATENCY_MAX_MS
;
if
(
size
<
HTT_RX_RING_SIZE_MIN
)
size
=
HTT_RX_RING_SIZE_MIN
;
if
(
size
>
HTT_RX_RING_SIZE_MAX
)
size
=
HTT_RX_RING_SIZE_MAX
;
size
=
roundup_pow_of_two
(
size
);
return
size
;
}
static
int
ath10k_htt_rx_ring_fill_level
(
struct
ath10k_htt
*
htt
)
{
int
size
;
/* 1e6 bps/mbps / 1e3 ms per sec = 1000 */
size
=
htt
->
max_throughput_mbps
*
1000
/
(
8
*
HTT_RX_AVG_FRM_BYTES
)
*
HTT_RX_HOST_LATENCY_WORST_LIKELY_MS
;
/*
* Make sure the fill level is at least 1 less than the ring size.
* Leaving 1 element empty allows the SW to easily distinguish
* between a full ring vs. an empty ring.
*/
if
(
size
>=
htt
->
rx_ring
.
size
)
size
=
htt
->
rx_ring
.
size
-
1
;
return
size
;
}
static
void
ath10k_htt_rx_ring_free
(
struct
ath10k_htt
*
htt
)
{
struct
sk_buff
*
skb
;
...
...
@@ -301,39 +228,28 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt)
return
msdu
;
}
static
void
ath10k_htt_rx_free_msdu_chain
(
struct
sk_buff
*
skb
)
{
struct
sk_buff
*
next
;
while
(
skb
)
{
next
=
skb
->
next
;
dev_kfree_skb_any
(
skb
);
skb
=
next
;
}
}
/* return: < 0 fatal error, 0 - non chained msdu, 1 chained msdu */
static
int
ath10k_htt_rx_amsdu_pop
(
struct
ath10k_htt
*
htt
,
u8
**
fw_desc
,
int
*
fw_desc_len
,
struct
sk_buff
**
head_msdu
,
struct
sk_buff
**
tail_msdu
,
u32
*
attention
)
struct
sk_buff_head
*
amsdu
)
{
struct
ath10k
*
ar
=
htt
->
ar
;
int
msdu_len
,
msdu_chaining
=
0
;
struct
sk_buff
*
msdu
,
*
next
;
struct
sk_buff
*
msdu
;
struct
htt_rx_desc
*
rx_desc
;
lockdep_assert_held
(
&
htt
->
rx_ring
.
lock
);
if
(
htt
->
rx_confused
)
{
ath10k_warn
(
ar
,
"htt is confused. refusing rx
\n
"
);
return
-
1
;
for
(;;)
{
int
last_msdu
,
msdu_len_invalid
,
msdu_chained
;
msdu
=
ath10k_htt_rx_netbuf_pop
(
htt
);
if
(
!
msdu
)
{
__skb_queue_purge
(
amsdu
);
return
-
ENOENT
;
}
msdu
=
*
head_msdu
=
ath10k_htt_rx_netbuf_pop
(
htt
);
while
(
msdu
)
{
int
last_msdu
,
msdu_len_invalid
,
msdu_chained
;
__skb_queue_tail
(
amsdu
,
msdu
);
rx_desc
=
(
struct
htt_rx_desc
*
)
msdu
->
data
;
...
...
@@ -352,19 +268,10 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
*/
if
(
!
(
__le32_to_cpu
(
rx_desc
->
attention
.
flags
)
&
RX_ATTENTION_FLAGS_MSDU_DONE
))
{
ath10k_htt_rx_free_msdu_chain
(
*
head_msdu
);
*
head_msdu
=
NULL
;
msdu
=
NULL
;
ath10k_err
(
ar
,
"htt rx stopped. cannot recover
\n
"
);
htt
->
rx_confused
=
true
;
break
;
__skb_queue_purge
(
amsdu
);
return
-
EIO
;
}
*
attention
|=
__le32_to_cpu
(
rx_desc
->
attention
.
flags
)
&
(
RX_ATTENTION_FLAGS_TKIP_MIC_ERR
|
RX_ATTENTION_FLAGS_DECRYPT_ERR
|
RX_ATTENTION_FLAGS_FCS_ERR
|
RX_ATTENTION_FLAGS_MGMT_TYPE
);
/*
* Copy the FW rx descriptor for this MSDU from the rx
* indication message into the MSDU's netbuf. HL uses the
...
...
@@ -421,25 +328,18 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
skb_put
(
msdu
,
min
(
msdu_len
,
HTT_RX_MSDU_SIZE
));
msdu_len
-=
msdu
->
len
;
/*
FIXME: Do chained buffers include htt_rx_desc or not?
*/
/*
Note: Chained buffers do not contain rx descriptor
*/
while
(
msdu_chained
--
)
{
struct
sk_buff
*
next
=
ath10k_htt_rx_netbuf_pop
(
htt
);
if
(
!
next
)
{
ath10k_warn
(
ar
,
"failed to pop chained msdu
\n
"
);
ath10k_htt_rx_free_msdu_chain
(
*
head_msdu
);
*
head_msdu
=
NULL
;
msdu
=
NULL
;
htt
->
rx_confused
=
true
;
break
;
msdu
=
ath10k_htt_rx_netbuf_pop
(
htt
);
if
(
!
msdu
)
{
__skb_queue_purge
(
amsdu
);
return
-
ENOENT
;
}
skb_trim
(
next
,
0
);
skb_put
(
next
,
min
(
msdu_len
,
HTT_RX_BUF_SIZE
));
msdu_len
-=
next
->
len
;
msdu
->
next
=
next
;
msdu
=
next
;
__skb_queue_tail
(
amsdu
,
msdu
);
skb_trim
(
msdu
,
0
);
skb_put
(
msdu
,
min
(
msdu_len
,
HTT_RX_BUF_SIZE
));
msdu_len
-=
msdu
->
len
;
msdu_chaining
=
1
;
}
...
...
@@ -448,18 +348,12 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
trace_ath10k_htt_rx_desc
(
ar
,
&
rx_desc
->
attention
,
sizeof
(
*
rx_desc
)
-
sizeof
(
u32
));
if
(
last_msdu
)
{
msdu
->
next
=
NULL
;
break
;
}
next
=
ath10k_htt_rx_netbuf_pop
(
htt
);
msdu
->
next
=
next
;
msdu
=
next
;
if
(
last_msdu
)
break
;
}
*
tail_msdu
=
msdu
;
if
(
*
head_msdu
==
NULL
)
if
(
skb_queue_empty
(
amsdu
)
)
msdu_chaining
=
-
1
;
/*
...
...
@@ -495,25 +389,18 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
htt
->
rx_confused
=
false
;
htt
->
rx_ring
.
size
=
ath10k_htt_rx_ring_size
(
htt
);
/* XXX: The fill level could be changed during runtime in response to
* the host processing latency. Is this really worth it?
*/
htt
->
rx_ring
.
size
=
HTT_RX_RING_SIZE
;
htt
->
rx_ring
.
size_mask
=
htt
->
rx_ring
.
size
-
1
;
htt
->
rx_ring
.
fill_level
=
HTT_RX_RING_FILL_LEVEL
;
if
(
!
is_power_of_2
(
htt
->
rx_ring
.
size
))
{
ath10k_warn
(
ar
,
"htt rx ring size is not power of 2
\n
"
);
return
-
EINVAL
;
}
htt
->
rx_ring
.
size_mask
=
htt
->
rx_ring
.
size
-
1
;
/*
* Set the initial value for the level to which the rx ring
* should be filled, based on the max throughput and the
* worst likely latency for the host to fill the rx ring
* with new buffers. In theory, this fill level can be
* dynamically adjusted from the initial value set here, to
* reflect the actual host latency rather than a
* conservative assumption about the host latency.
*/
htt
->
rx_ring
.
fill_level
=
ath10k_htt_rx_ring_fill_level
(
htt
);
htt
->
rx_ring
.
netbufs_ring
=
kzalloc
(
htt
->
rx_ring
.
size
*
sizeof
(
struct
sk_buff
*
),
GFP_KERNEL
);
...
...
@@ -628,35 +515,6 @@ static int ath10k_htt_rx_crypto_tail_len(struct ath10k *ar,
return
0
;
}
/* Applies for first msdu in chain, before altering it. */
static
struct
ieee80211_hdr
*
ath10k_htt_rx_skb_get_hdr
(
struct
sk_buff
*
skb
)
{
struct
htt_rx_desc
*
rxd
;
enum
rx_msdu_decap_format
fmt
;
rxd
=
(
void
*
)
skb
->
data
-
sizeof
(
*
rxd
);
fmt
=
MS
(
__le32_to_cpu
(
rxd
->
msdu_start
.
info1
),
RX_MSDU_START_INFO1_DECAP_FORMAT
);
if
(
fmt
==
RX_MSDU_DECAP_RAW
)
return
(
void
*
)
skb
->
data
;
return
(
void
*
)
skb
->
data
-
RX_HTT_HDR_STATUS_LEN
;
}
/* This function only applies for first msdu in an msdu chain */
static
bool
ath10k_htt_rx_hdr_is_amsdu
(
struct
ieee80211_hdr
*
hdr
)
{
u8
*
qc
;
if
(
ieee80211_is_data_qos
(
hdr
->
frame_control
))
{
qc
=
ieee80211_get_qos_ctl
(
hdr
);
if
(
qc
[
0
]
&
0x80
)
return
true
;
}
return
false
;
}
struct
rfc1042_hdr
{
u8
llc_dsap
;
u8
llc_ssap
;
...
...
@@ -691,23 +549,34 @@ static const u8 rx_legacy_rate_idx[] = {
};
static
void
ath10k_htt_rx_h_rates
(
struct
ath10k
*
ar
,
enum
ieee80211_band
band
,
u8
info0
,
u32
info1
,
u32
info2
,
struct
ieee80211_rx_status
*
status
)
struct
ieee80211_rx_status
*
status
,
struct
htt_rx_desc
*
rxd
)
{
enum
ieee80211_band
band
;
u8
cck
,
rate
,
rate_idx
,
bw
,
sgi
,
mcs
,
nss
;
u8
preamble
=
0
;
u32
info1
,
info2
,
info3
;
/* Check if valid fields */
if
(
!
(
info0
&
HTT_RX_INDICATION_INFO0_START_VALID
))
/* Band value can't be set as undefined but freq can be 0 - use that to
* determine whether band is provided.
*
* FIXME: Perhaps this can go away if CCK rate reporting is a little
* reworked?
*/
if
(
!
status
->
freq
)
return
;
preamble
=
MS
(
info1
,
HTT_RX_INDICATION_INFO1_PREAMBLE_TYPE
);
band
=
status
->
band
;
info1
=
__le32_to_cpu
(
rxd
->
ppdu_start
.
info1
);
info2
=
__le32_to_cpu
(
rxd
->
ppdu_start
.
info2
);
info3
=
__le32_to_cpu
(
rxd
->
ppdu_start
.
info3
);
preamble
=
MS
(
info1
,
RX_PPDU_START_INFO1_PREAMBLE_TYPE
);
switch
(
preamble
)
{
case
HTT_RX_LEGACY
:
cck
=
info
0
&
HTT_RX_INDICATION_INFO0_LEGACY_RATE_CCK
;
rate
=
MS
(
info
0
,
HTT_RX_INDICATION_INFO0_LEGACY
_RATE
);
cck
=
info
1
&
RX_PPDU_START_INFO1_L_SIG_RATE_SELECT
;
rate
=
MS
(
info
1
,
RX_PPDU_START_INFO1_L_SIG
_RATE
);
rate_idx
=
0
;
if
(
rate
<
0x08
||
rate
>
0x0F
)
...
...
@@ -734,11 +603,11 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
break
;
case
HTT_RX_HT
:
case
HTT_RX_HT_WITH_TXBF
:
/* HT-SIG - Table 20-11 in info
1 and info2
*/
mcs
=
info
1
&
0x1F
;
/* HT-SIG - Table 20-11 in info
2 and info3
*/
mcs
=
info
2
&
0x1F
;
nss
=
mcs
>>
3
;
bw
=
(
info
1
>>
7
)
&
1
;
sgi
=
(
info
2
>>
7
)
&
1
;
bw
=
(
info
2
>>
7
)
&
1
;
sgi
=
(
info
3
>>
7
)
&
1
;
status
->
rate_idx
=
mcs
;
status
->
flag
|=
RX_FLAG_HT
;
...
...
@@ -749,12 +618,12 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
break
;
case
HTT_RX_VHT
:
case
HTT_RX_VHT_WITH_TXBF
:
/* VHT-SIG-A1 in info
1, VHT-SIG-A2 in info2
/* VHT-SIG-A1 in info
2, VHT-SIG-A2 in info3
TODO check this */
mcs
=
(
info
2
>>
4
)
&
0x0F
;
nss
=
((
info
1
>>
10
)
&
0x07
)
+
1
;
bw
=
info
1
&
3
;
sgi
=
info
2
&
1
;
mcs
=
(
info
3
>>
4
)
&
0x0F
;
nss
=
((
info
2
>>
10
)
&
0x07
)
+
1
;
bw
=
info
2
&
3
;
sgi
=
info
3
&
1
;
status
->
rate_idx
=
mcs
;
status
->
vht_nss
=
nss
;
...
...
@@ -782,41 +651,6 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
}
}
static
void
ath10k_htt_rx_h_protected
(
struct
ath10k_htt
*
htt
,
struct
ieee80211_rx_status
*
rx_status
,
struct
sk_buff
*
skb
,
enum
htt_rx_mpdu_encrypt_type
enctype
,
enum
rx_msdu_decap_format
fmt
,
bool
dot11frag
)
{
struct
ieee80211_hdr
*
hdr
=
(
struct
ieee80211_hdr
*
)
skb
->
data
;
rx_status
->
flag
&=
~
(
RX_FLAG_DECRYPTED
|
RX_FLAG_IV_STRIPPED
|
RX_FLAG_MMIC_STRIPPED
);
if
(
enctype
==
HTT_RX_MPDU_ENCRYPT_NONE
)
return
;
/*
* There's no explicit rx descriptor flag to indicate whether a given
* frame has been decrypted or not. We're forced to use the decap
* format as an implicit indication. However fragmentation rx is always
* raw and it probably never reports undecrypted raws.
*
* This makes sure sniffed frames are reported as-is without stripping
* the protected flag.
*/
if
(
fmt
==
RX_MSDU_DECAP_RAW
&&
!
dot11frag
)
return
;
rx_status
->
flag
|=
RX_FLAG_DECRYPTED
|
RX_FLAG_IV_STRIPPED
|
RX_FLAG_MMIC_STRIPPED
;
hdr
->
frame_control
=
__cpu_to_le16
(
__le16_to_cpu
(
hdr
->
frame_control
)
&
~
IEEE80211_FCTL_PROTECTED
);
}
static
bool
ath10k_htt_rx_h_channel
(
struct
ath10k
*
ar
,
struct
ieee80211_rx_status
*
status
)
{
...
...
@@ -837,6 +671,72 @@ static bool ath10k_htt_rx_h_channel(struct ath10k *ar,
return
true
;
}
static
void
ath10k_htt_rx_h_signal
(
struct
ath10k
*
ar
,
struct
ieee80211_rx_status
*
status
,
struct
htt_rx_desc
*
rxd
)
{
/* FIXME: Get real NF */
status
->
signal
=
ATH10K_DEFAULT_NOISE_FLOOR
+
rxd
->
ppdu_start
.
rssi_comb
;
status
->
flag
&=
~
RX_FLAG_NO_SIGNAL_VAL
;
}
static
void
ath10k_htt_rx_h_mactime
(
struct
ath10k
*
ar
,
struct
ieee80211_rx_status
*
status
,
struct
htt_rx_desc
*
rxd
)
{
/* FIXME: TSF is known only at the end of PPDU, in the last MPDU. This
* means all prior MSDUs in a PPDU are reported to mac80211 without the
* TSF. Is it worth holding frames until end of PPDU is known?
*
* FIXME: Can we get/compute 64bit TSF?
*/
status
->
mactime
=
__le32_to_cpu
(
rxd
->
ppdu_end
.
tsf_timestamp
);
status
->
flag
|=
RX_FLAG_MACTIME_END
;
}
static
void
ath10k_htt_rx_h_ppdu
(
struct
ath10k
*
ar
,
struct
sk_buff_head
*
amsdu
,
struct
ieee80211_rx_status
*
status
)
{
struct
sk_buff
*
first
;
struct
htt_rx_desc
*
rxd
;
bool
is_first_ppdu
;
bool
is_last_ppdu
;
if
(
skb_queue_empty
(
amsdu
))
return
;
first
=
skb_peek
(
amsdu
);
rxd
=
(
void
*
)
first
->
data
-
sizeof
(
*
rxd
);
is_first_ppdu
=
!!
(
rxd
->
attention
.
flags
&
__cpu_to_le32
(
RX_ATTENTION_FLAGS_FIRST_MPDU
));
is_last_ppdu
=
!!
(
rxd
->
attention
.
flags
&
__cpu_to_le32
(
RX_ATTENTION_FLAGS_LAST_MPDU
));
if
(
is_first_ppdu
)
{
/* New PPDU starts so clear out the old per-PPDU status. */
status
->
freq
=
0
;
status
->
rate_idx
=
0
;
status
->
vht_nss
=
0
;
status
->
vht_flag
&=
~
RX_VHT_FLAG_80MHZ
;
status
->
flag
&=
~
(
RX_FLAG_HT
|
RX_FLAG_VHT
|
RX_FLAG_SHORT_GI
|
RX_FLAG_40MHZ
|
RX_FLAG_MACTIME_END
);
status
->
flag
|=
RX_FLAG_NO_SIGNAL_VAL
;
ath10k_htt_rx_h_signal
(
ar
,
status
,
rxd
);
ath10k_htt_rx_h_channel
(
ar
,
status
);
ath10k_htt_rx_h_rates
(
ar
,
status
,
rxd
);
}
if
(
is_last_ppdu
)
ath10k_htt_rx_h_mactime
(
ar
,
status
,
rxd
);
}
static
const
char
*
const
tid_to_ac
[]
=
{
"BE"
,
"BK"
,
...
...
@@ -913,187 +813,263 @@ static int ath10k_htt_rx_nwifi_hdrlen(struct ieee80211_hdr *hdr)
return
round_up
(
ieee80211_hdrlen
(
hdr
->
frame_control
),
4
);
}
static
void
ath10k_htt_rx_amsdu
(
struct
ath10k_htt
*
htt
,
struct
ieee80211_rx_status
*
rx_status
,
struct
sk_buff
*
skb_in
)
static
void
ath10k_htt_rx_h_undecap_raw
(
struct
ath10k
*
ar
,
struct
sk_buff
*
msdu
,
struct
ieee80211_rx_status
*
status
,
enum
htt_rx_mpdu_encrypt_type
enctype
,
bool
is_decrypted
)
{
struct
ath10k
*
ar
=
htt
->
ar
;
struct
htt_rx_desc
*
rxd
;
struct
sk_buff
*
skb
=
skb_in
;
struct
sk_buff
*
first
;
enum
rx_msdu_decap_format
fmt
;
enum
htt_rx_mpdu_encrypt_type
enctype
;
struct
ieee80211_hdr
*
hdr
;
u8
hdr_buf
[
64
],
da
[
ETH_ALEN
],
sa
[
ETH_ALEN
],
*
qos
;
unsigned
int
hdr_len
;
struct
htt_rx_desc
*
rxd
;
size_t
hdr_len
;
size_t
crypto_len
;
bool
is_first
;
bool
is_last
;
rxd
=
(
void
*
)
msdu
->
data
-
sizeof
(
*
rxd
);
is_first
=
!!
(
rxd
->
msdu_end
.
info0
&
__cpu_to_le32
(
RX_MSDU_END_INFO0_FIRST_MSDU
));
is_last
=
!!
(
rxd
->
msdu_end
.
info0
&
__cpu_to_le32
(
RX_MSDU_END_INFO0_LAST_MSDU
));
/* Delivered decapped frame:
* [802.11 header]
* [crypto param] <-- can be trimmed if !fcs_err &&
* !decrypt_err && !peer_idx_invalid
* [amsdu header] <-- only if A-MSDU
* [rfc1042/llc]
* [payload]
* [FCS] <-- at end, needs to be trimmed
*/
rxd
=
(
void
*
)
skb
->
data
-
sizeof
(
*
rxd
);
enctype
=
MS
(
__le32_to_cpu
(
rxd
->
mpdu_start
.
info0
),
RX_MPDU_START_INFO0_ENCRYPT_TYPE
)
;
/* This probably shouldn't happen but warn just in case */
if
(
unlikely
(
WARN_ON_ONCE
(
!
is_first
)))
return
;
hdr
=
(
struct
ieee80211_hdr
*
)
rxd
->
rx_hdr_status
;
hdr_len
=
ieee80211_hdrlen
(
hdr
->
frame_control
);
memcpy
(
hdr_buf
,
hdr
,
hdr_len
);
hdr
=
(
struct
ieee80211_hdr
*
)
hdr_buf
;
/* This probably shouldn't happen but warn just in case */
if
(
unlikely
(
WARN_ON_ONCE
(
!
(
is_first
&&
is_last
))))
return
;
first
=
skb
;
while
(
skb
)
{
void
*
decap_hdr
;
int
len
;
skb_trim
(
msdu
,
msdu
->
len
-
FCS_LEN
);
rxd
=
(
void
*
)
skb
->
data
-
sizeof
(
*
rxd
);
fmt
=
MS
(
__le32_to_cpu
(
rxd
->
msdu_start
.
info1
),
RX_MSDU_START_INFO1_DECAP_FORMAT
);
decap_hdr
=
(
void
*
)
rxd
->
rx_hdr_status
;
/* In most cases this will be true for sniffed frames. It makes sense
* to deliver them as-is without stripping the crypto param. This would
* also make sense for software based decryption (which is not
* implemented in ath10k).
*
* If there's no error then the frame is decrypted. At least that is
* the case for frames that come in via fragmented rx indication.
*/
if
(
!
is_decrypted
)
return
;
skb
->
ip_summed
=
ath10k_htt_rx_get_csum_state
(
skb
);
/* The payload is decrypted so strip crypto params. Start from tail
* since hdr is used to compute some stuff.
*/
/* First frame in an A-MSDU chain has more decapped data. */
if
(
skb
==
first
)
{
len
=
round_up
(
ieee80211_hdrlen
(
hdr
->
frame_control
),
4
);
len
+=
round_up
(
ath10k_htt_rx_crypto_param_len
(
ar
,
enctype
),
4
);
decap_hdr
+=
len
;
}
hdr
=
(
void
*
)
msdu
->
data
;
/* Tail */
skb_trim
(
msdu
,
msdu
->
len
-
ath10k_htt_rx_crypto_tail_len
(
ar
,
enctype
));
/* MMIC */
if
(
!
ieee80211_has_morefrags
(
hdr
->
frame_control
)
&&
enctype
==
HTT_RX_MPDU_ENCRYPT_TKIP_WPA
)
skb_trim
(
msdu
,
msdu
->
len
-
8
);
/* Head */
hdr_len
=
ieee80211_hdrlen
(
hdr
->
frame_control
);
crypto_len
=
ath10k_htt_rx_crypto_param_len
(
ar
,
enctype
);
memmove
((
void
*
)
msdu
->
data
+
crypto_len
,
(
void
*
)
msdu
->
data
,
hdr_len
);
skb_pull
(
msdu
,
crypto_len
);
}
static
void
ath10k_htt_rx_h_undecap_nwifi
(
struct
ath10k
*
ar
,
struct
sk_buff
*
msdu
,
struct
ieee80211_rx_status
*
status
,
const
u8
first_hdr
[
64
])
{
struct
ieee80211_hdr
*
hdr
;
size_t
hdr_len
;
u8
da
[
ETH_ALEN
];
u8
sa
[
ETH_ALEN
];
/* Delivered decapped frame:
* [nwifi 802.11 header] <-- replaced with 802.11 hdr
* [rfc1042/llc]
*
* Note: The nwifi header doesn't have QoS Control and is
* (always?) a 3addr frame.
*
* Note2: There's no A-MSDU subframe header. Even if it's part
* of an A-MSDU.
*/
switch
(
fmt
)
{
case
RX_MSDU_DECAP_RAW
:
/* remove trailing FCS */
skb_trim
(
skb
,
skb
->
len
-
FCS_LEN
);
break
;
case
RX_MSDU_DECAP_NATIVE_WIFI
:
/* pull decapped header and copy SA & DA */
hdr
=
(
struct
ieee80211_hdr
*
)
skb
->
data
;
hdr
=
(
struct
ieee80211_hdr
*
)
msdu
->
data
;
hdr_len
=
ath10k_htt_rx_nwifi_hdrlen
(
hdr
);
ether_addr_copy
(
da
,
ieee80211_get_DA
(
hdr
));
ether_addr_copy
(
sa
,
ieee80211_get_SA
(
hdr
));
skb_pull
(
skb
,
hdr_len
);
skb_pull
(
msdu
,
hdr_len
);
/* push original 802.11 header */
hdr
=
(
struct
ieee80211_hdr
*
)
hdr_buf
;
hdr
=
(
struct
ieee80211_hdr
*
)
first_hdr
;
hdr_len
=
ieee80211_hdrlen
(
hdr
->
frame_control
);
memcpy
(
skb_push
(
skb
,
hdr_len
),
hdr
,
hdr_len
);
/* original A-MSDU header has the bit set but we're
* not including A-MSDU subframe header */
hdr
=
(
struct
ieee80211_hdr
*
)
skb
->
data
;
qos
=
ieee80211_get_qos_ctl
(
hdr
);
qos
[
0
]
&=
~
IEEE80211_QOS_CTL_A_MSDU_PRESENT
;
memcpy
(
skb_push
(
msdu
,
hdr_len
),
hdr
,
hdr_len
);
/* original 802.11 header has a different DA and in
* case of 4addr it may also have different SA
*/
hdr
=
(
struct
ieee80211_hdr
*
)
msdu
->
data
;
ether_addr_copy
(
ieee80211_get_DA
(
hdr
),
da
);
ether_addr_copy
(
ieee80211_get_SA
(
hdr
),
sa
);
break
;
case
RX_MSDU_DECAP_ETHERNET2_DIX
:
/* strip ethernet header and insert decapped 802.11
* header, amsdu subframe header and rfc1042 header */
}
len
=
0
;
len
+=
sizeof
(
struct
rfc1042_hdr
);
len
+=
sizeof
(
struct
amsdu_subframe_hdr
);
static
void
*
ath10k_htt_rx_h_find_rfc1042
(
struct
ath10k
*
ar
,
struct
sk_buff
*
msdu
,
enum
htt_rx_mpdu_encrypt_type
enctype
)
{
struct
ieee80211_hdr
*
hdr
;
struct
htt_rx_desc
*
rxd
;
size_t
hdr_len
,
crypto_len
;
void
*
rfc1042
;
bool
is_first
,
is_last
,
is_amsdu
;
skb_pull
(
skb
,
sizeof
(
struct
ethhdr
));
memcpy
(
skb_push
(
skb
,
len
),
decap_hdr
,
len
);
memcpy
(
skb_push
(
skb
,
hdr_len
),
hdr
,
hdr_len
);
break
;
case
RX_MSDU_DECAP_8023_SNAP_LLC
:
/* insert decapped 802.11 header making a singly
* A-MSDU */
memcpy
(
skb_push
(
skb
,
hdr_len
),
hdr
,
hdr_len
);
break
;
}
rxd
=
(
void
*
)
msdu
->
data
-
sizeof
(
*
rxd
);
hdr
=
(
void
*
)
rxd
->
rx_hdr_status
;
skb_in
=
skb
;
ath10k_htt_rx_h_protected
(
htt
,
rx_status
,
skb_in
,
enctype
,
fmt
,
false
);
skb
=
skb
->
next
;
skb_in
->
next
=
NULL
;
is_first
=
!!
(
rxd
->
msdu_end
.
info0
&
__cpu_to_le32
(
RX_MSDU_END_INFO0_FIRST_MSDU
));
is_last
=
!!
(
rxd
->
msdu_end
.
info0
&
__cpu_to_le32
(
RX_MSDU_END_INFO0_LAST_MSDU
))
;
is_amsdu
=
!
(
is_first
&&
is_last
)
;
if
(
skb
)
rx_status
->
flag
|=
RX_FLAG_AMSDU_MORE
;
else
rx_status
->
flag
&=
~
RX_FLAG_AMSDU_MORE
;
rfc1042
=
hdr
;
if
(
is_first
)
{
hdr_len
=
ieee80211_hdrlen
(
hdr
->
frame_control
);
crypto_len
=
ath10k_htt_rx_crypto_param_len
(
ar
,
enctype
);
ath10k_process_rx
(
htt
->
ar
,
rx_status
,
skb_in
);
rfc1042
+=
round_up
(
hdr_len
,
4
)
+
round_up
(
crypto_len
,
4
);
}
/* FIXME: It might be nice to re-assemble the A-MSDU when there's a
* monitor interface active for sniffing purposes. */
if
(
is_amsdu
)
rfc1042
+=
sizeof
(
struct
amsdu_subframe_hdr
);
return
rfc1042
;
}
static
void
ath10k_htt_rx_msdu
(
struct
ath10k_htt
*
htt
,
struct
ieee80211_rx_status
*
rx_status
,
struct
sk_buff
*
skb
)
static
void
ath10k_htt_rx_h_undecap_eth
(
struct
ath10k
*
ar
,
struct
sk_buff
*
msdu
,
struct
ieee80211_rx_status
*
status
,
const
u8
first_hdr
[
64
],
enum
htt_rx_mpdu_encrypt_type
enctype
)
{
struct
ath10k
*
ar
=
htt
->
ar
;
struct
htt_rx_desc
*
rxd
;
struct
ieee80211_hdr
*
hdr
;
enum
rx_msdu_decap_format
fmt
;
enum
htt_rx_mpdu_encrypt_type
enctype
;
int
hdr_len
;
struct
ethhdr
*
eth
;
size_t
hdr_len
;
void
*
rfc1042
;
u8
da
[
ETH_ALEN
];
u8
sa
[
ETH_ALEN
];
/* This shouldn't happen. If it does than it may be a FW bug. */
if
(
skb
->
next
)
{
ath10k_warn
(
ar
,
"htt rx received chained non A-MSDU frame
\n
"
);
ath10k_htt_rx_free_msdu_chain
(
skb
->
next
);
skb
->
next
=
NULL
;
}
/* Delivered decapped frame:
* [eth header] <-- replaced with 802.11 hdr & rfc1042/llc
* [payload]
*/
rxd
=
(
void
*
)
skb
->
data
-
sizeof
(
*
rxd
);
fmt
=
MS
(
__le32_to_cpu
(
rxd
->
msdu_start
.
info1
),
RX_MSDU_START_INFO1_DECAP_FORMAT
);
enctype
=
MS
(
__le32_to_cpu
(
rxd
->
mpdu_start
.
info0
),
RX_MPDU_START_INFO0_ENCRYPT_TYPE
);
hdr
=
(
struct
ieee80211_hdr
*
)
rxd
->
rx_hdr_status
;
rfc1042
=
ath10k_htt_rx_h_find_rfc1042
(
ar
,
msdu
,
enctype
);
if
(
WARN_ON_ONCE
(
!
rfc1042
))
return
;
/* pull decapped header and copy SA & DA */
eth
=
(
struct
ethhdr
*
)
msdu
->
data
;
ether_addr_copy
(
da
,
eth
->
h_dest
);
ether_addr_copy
(
sa
,
eth
->
h_source
);
skb_pull
(
msdu
,
sizeof
(
struct
ethhdr
));
/* push rfc1042/llc/snap */
memcpy
(
skb_push
(
msdu
,
sizeof
(
struct
rfc1042_hdr
)),
rfc1042
,
sizeof
(
struct
rfc1042_hdr
));
/* push original 802.11 header */
hdr
=
(
struct
ieee80211_hdr
*
)
first_hdr
;
hdr_len
=
ieee80211_hdrlen
(
hdr
->
frame_control
);
memcpy
(
skb_push
(
msdu
,
hdr_len
),
hdr
,
hdr_len
);
/* original 802.11 header has a different DA and in
* case of 4addr it may also have different SA
*/
hdr
=
(
struct
ieee80211_hdr
*
)
msdu
->
data
;
ether_addr_copy
(
ieee80211_get_DA
(
hdr
),
da
);
ether_addr_copy
(
ieee80211_get_SA
(
hdr
),
sa
);
}
static
void
ath10k_htt_rx_h_undecap_snap
(
struct
ath10k
*
ar
,
struct
sk_buff
*
msdu
,
struct
ieee80211_rx_status
*
status
,
const
u8
first_hdr
[
64
])
{
struct
ieee80211_hdr
*
hdr
;
size_t
hdr_len
;
/* Delivered decapped frame:
* [amsdu header] <-- replaced with 802.11 hdr
* [rfc1042/llc]
* [payload]
*/
skb_pull
(
msdu
,
sizeof
(
struct
amsdu_subframe_hdr
));
hdr
=
(
struct
ieee80211_hdr
*
)
first_hdr
;
hdr_len
=
ieee80211_hdrlen
(
hdr
->
frame_control
);
memcpy
(
skb_push
(
msdu
,
hdr_len
),
hdr
,
hdr_len
);
}
static
void
ath10k_htt_rx_h_undecap
(
struct
ath10k
*
ar
,
struct
sk_buff
*
msdu
,
struct
ieee80211_rx_status
*
status
,
u8
first_hdr
[
64
],
enum
htt_rx_mpdu_encrypt_type
enctype
,
bool
is_decrypted
)
{
struct
htt_rx_desc
*
rxd
;
enum
rx_msdu_decap_format
decap
;
struct
ieee80211_hdr
*
hdr
;
/* First msdu's decapped header:
* [802.11 header] <-- padded to 4 bytes long
* [crypto param] <-- padded to 4 bytes long
* [amsdu header] <-- only if A-MSDU
* [rfc1042/llc]
*
* Other (2nd, 3rd, ..) msdu's decapped header:
* [amsdu header] <-- only if A-MSDU
* [rfc1042/llc]
*/
skb
->
ip_summed
=
ath10k_htt_rx_get_csum_state
(
skb
);
rxd
=
(
void
*
)
msdu
->
data
-
sizeof
(
*
rxd
);
hdr
=
(
void
*
)
rxd
->
rx_hdr_status
;
decap
=
MS
(
__le32_to_cpu
(
rxd
->
msdu_start
.
info1
),
RX_MSDU_START_INFO1_DECAP_FORMAT
);
switch
(
fmt
)
{
switch
(
decap
)
{
case
RX_MSDU_DECAP_RAW
:
/* remove trailing FCS */
skb_trim
(
skb
,
skb
->
len
-
FCS_LEN
);
ath10k_htt_rx_h_undecap_raw
(
ar
,
msdu
,
status
,
enctype
,
is_decrypted
);
break
;
case
RX_MSDU_DECAP_NATIVE_WIFI
:
/* Pull decapped header */
hdr
=
(
struct
ieee80211_hdr
*
)
skb
->
data
;
hdr_len
=
ath10k_htt_rx_nwifi_hdrlen
(
hdr
);
skb_pull
(
skb
,
hdr_len
);
/* Push original header */
hdr
=
(
struct
ieee80211_hdr
*
)
rxd
->
rx_hdr_status
;
hdr_len
=
ieee80211_hdrlen
(
hdr
->
frame_control
);
memcpy
(
skb_push
(
skb
,
hdr_len
),
hdr
,
hdr_len
);
ath10k_htt_rx_h_undecap_nwifi
(
ar
,
msdu
,
status
,
first_hdr
);
break
;
case
RX_MSDU_DECAP_ETHERNET2_DIX
:
/* strip ethernet header and insert decapped 802.11 header and
* rfc1042 header */
rfc1042
=
hdr
;
rfc1042
+=
roundup
(
hdr_len
,
4
);
rfc1042
+=
roundup
(
ath10k_htt_rx_crypto_param_len
(
ar
,
enctype
),
4
);
skb_pull
(
skb
,
sizeof
(
struct
ethhdr
));
memcpy
(
skb_push
(
skb
,
sizeof
(
struct
rfc1042_hdr
)),
rfc1042
,
sizeof
(
struct
rfc1042_hdr
));
memcpy
(
skb_push
(
skb
,
hdr_len
),
hdr
,
hdr_len
);
ath10k_htt_rx_h_undecap_eth
(
ar
,
msdu
,
status
,
first_hdr
,
enctype
);
break
;
case
RX_MSDU_DECAP_8023_SNAP_LLC
:
/* remove A-MSDU subframe header and insert
* decapped 802.11 header. rfc1042 header is already there */
skb_pull
(
skb
,
sizeof
(
struct
amsdu_subframe_hdr
));
memcpy
(
skb_push
(
skb
,
hdr_len
),
hdr
,
hdr_len
);
ath10k_htt_rx_h_undecap_snap
(
ar
,
msdu
,
status
,
first_hdr
);
break
;
}
ath10k_htt_rx_h_protected
(
htt
,
rx_status
,
skb
,
enctype
,
fmt
,
false
);
ath10k_process_rx
(
htt
->
ar
,
rx_status
,
skb
);
}
static
int
ath10k_htt_rx_get_csum_state
(
struct
sk_buff
*
skb
)
...
...
@@ -1127,10 +1103,128 @@ static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb)
return
CHECKSUM_UNNECESSARY
;
}
static
int
ath10k_unchain_msdu
(
struct
sk_buff
*
msdu_head
)
static
void
ath10k_htt_rx_h_csum_offload
(
struct
sk_buff
*
msdu
)
{
struct
sk_buff
*
next
=
msdu_head
->
next
;
struct
sk_buff
*
to_free
=
next
;
msdu
->
ip_summed
=
ath10k_htt_rx_get_csum_state
(
msdu
);
}
static
void
ath10k_htt_rx_h_mpdu
(
struct
ath10k
*
ar
,
struct
sk_buff_head
*
amsdu
,
struct
ieee80211_rx_status
*
status
)
{
struct
sk_buff
*
first
;
struct
sk_buff
*
last
;
struct
sk_buff
*
msdu
;
struct
htt_rx_desc
*
rxd
;
struct
ieee80211_hdr
*
hdr
;
enum
htt_rx_mpdu_encrypt_type
enctype
;
u8
first_hdr
[
64
];
u8
*
qos
;
size_t
hdr_len
;
bool
has_fcs_err
;
bool
has_crypto_err
;
bool
has_tkip_err
;
bool
has_peer_idx_invalid
;
bool
is_decrypted
;
u32
attention
;
if
(
skb_queue_empty
(
amsdu
))
return
;
first
=
skb_peek
(
amsdu
);
rxd
=
(
void
*
)
first
->
data
-
sizeof
(
*
rxd
);
enctype
=
MS
(
__le32_to_cpu
(
rxd
->
mpdu_start
.
info0
),
RX_MPDU_START_INFO0_ENCRYPT_TYPE
);
/* First MSDU's Rx descriptor in an A-MSDU contains full 802.11
* decapped header. It'll be used for undecapping of each MSDU.
*/
hdr
=
(
void
*
)
rxd
->
rx_hdr_status
;
hdr_len
=
ieee80211_hdrlen
(
hdr
->
frame_control
);
memcpy
(
first_hdr
,
hdr
,
hdr_len
);
/* Each A-MSDU subframe will use the original header as the base and be
* reported as a separate MSDU so strip the A-MSDU bit from QoS Ctl.
*/
hdr
=
(
void
*
)
first_hdr
;
qos
=
ieee80211_get_qos_ctl
(
hdr
);
qos
[
0
]
&=
~
IEEE80211_QOS_CTL_A_MSDU_PRESENT
;
/* Some attention flags are valid only in the last MSDU. */
last
=
skb_peek_tail
(
amsdu
);
rxd
=
(
void
*
)
last
->
data
-
sizeof
(
*
rxd
);
attention
=
__le32_to_cpu
(
rxd
->
attention
.
flags
);
has_fcs_err
=
!!
(
attention
&
RX_ATTENTION_FLAGS_FCS_ERR
);
has_crypto_err
=
!!
(
attention
&
RX_ATTENTION_FLAGS_DECRYPT_ERR
);
has_tkip_err
=
!!
(
attention
&
RX_ATTENTION_FLAGS_TKIP_MIC_ERR
);
has_peer_idx_invalid
=
!!
(
attention
&
RX_ATTENTION_FLAGS_PEER_IDX_INVALID
);
/* Note: If hardware captures an encrypted frame that it can't decrypt,
* e.g. due to fcs error, missing peer or invalid key data it will
* report the frame as raw.
*/
is_decrypted
=
(
enctype
!=
HTT_RX_MPDU_ENCRYPT_NONE
&&
!
has_fcs_err
&&
!
has_crypto_err
&&
!
has_peer_idx_invalid
);
/* Clear per-MPDU flags while leaving per-PPDU flags intact. */
status
->
flag
&=
~
(
RX_FLAG_FAILED_FCS_CRC
|
RX_FLAG_MMIC_ERROR
|
RX_FLAG_DECRYPTED
|
RX_FLAG_IV_STRIPPED
|
RX_FLAG_MMIC_STRIPPED
);
if
(
has_fcs_err
)
status
->
flag
|=
RX_FLAG_FAILED_FCS_CRC
;
if
(
has_tkip_err
)
status
->
flag
|=
RX_FLAG_MMIC_ERROR
;
if
(
is_decrypted
)
status
->
flag
|=
RX_FLAG_DECRYPTED
|
RX_FLAG_IV_STRIPPED
|
RX_FLAG_MMIC_STRIPPED
;
skb_queue_walk
(
amsdu
,
msdu
)
{
ath10k_htt_rx_h_csum_offload
(
msdu
);
ath10k_htt_rx_h_undecap
(
ar
,
msdu
,
status
,
first_hdr
,
enctype
,
is_decrypted
);
/* Undecapping involves copying the original 802.11 header back
* to sk_buff. If frame is protected and hardware has decrypted
* it then remove the protected bit.
*/
if
(
!
is_decrypted
)
continue
;
hdr
=
(
void
*
)
msdu
->
data
;
hdr
->
frame_control
&=
~
__cpu_to_le16
(
IEEE80211_FCTL_PROTECTED
);
}
}
static
void
ath10k_htt_rx_h_deliver
(
struct
ath10k
*
ar
,
struct
sk_buff_head
*
amsdu
,
struct
ieee80211_rx_status
*
status
)
{
struct
sk_buff
*
msdu
;
while
((
msdu
=
__skb_dequeue
(
amsdu
)))
{
/* Setup per-MSDU flags */
if
(
skb_queue_empty
(
amsdu
))
status
->
flag
&=
~
RX_FLAG_AMSDU_MORE
;
else
status
->
flag
|=
RX_FLAG_AMSDU_MORE
;
ath10k_process_rx
(
ar
,
status
,
msdu
);
}
}
static
int
ath10k_unchain_msdu
(
struct
sk_buff_head
*
amsdu
)
{
struct
sk_buff
*
skb
,
*
first
;
int
space
;
int
total_len
=
0
;
...
...
@@ -1141,99 +1235,142 @@ static int ath10k_unchain_msdu(struct sk_buff *msdu_head)
* skb?
*/
msdu_head
->
next
=
NULL
;
first
=
__skb_dequeue
(
amsdu
)
;
/* Allocate total length all at once. */
while
(
next
)
{
total_len
+=
next
->
len
;
next
=
next
->
next
;
}
skb_queue_walk
(
amsdu
,
skb
)
total_len
+=
skb
->
len
;
space
=
total_len
-
skb_tailroom
(
msdu_head
);
space
=
total_len
-
skb_tailroom
(
first
);
if
((
space
>
0
)
&&
(
pskb_expand_head
(
msdu_head
,
0
,
space
,
GFP_ATOMIC
)
<
0
))
{
(
pskb_expand_head
(
first
,
0
,
space
,
GFP_ATOMIC
)
<
0
))
{
/* TODO: bump some rx-oom error stat */
/* put it back together so we can free the
* whole list at once.
*/
msdu_head
->
next
=
to_free
;
__skb_queue_head
(
amsdu
,
first
)
;
return
-
1
;
}
/* Walk list again, copying contents into
* msdu_head
*/
next
=
to_free
;
while
(
next
)
{
skb_copy_from_linear_data
(
next
,
skb_put
(
msdu_head
,
next
->
len
),
next
->
len
);
next
=
next
->
next
;
while
((
skb
=
__skb_dequeue
(
amsdu
)))
{
skb_copy_from_linear_data
(
skb
,
skb_put
(
first
,
skb
->
len
),
skb
->
len
);
dev_kfree_skb_any
(
skb
);
}
/* If here, we have consolidated skb. Free the
* fragments and pass the main skb on up the
* stack.
*/
ath10k_htt_rx_free_msdu_chain
(
to_free
);
__skb_queue_head
(
amsdu
,
first
);
return
0
;
}
static
bool
ath10k_htt_rx_amsdu_allowed
(
struct
ath10k_htt
*
htt
,
struct
sk_buff
*
head
,
bool
channel_set
,
u32
attention
)
static
void
ath10k_htt_rx_h_unchain
(
struct
ath10k
*
ar
,
struct
sk_buff_head
*
amsdu
,
bool
chained
)
{
struct
ath10k
*
ar
=
htt
->
ar
;
struct
sk_buff
*
first
;
struct
htt_rx_desc
*
rxd
;
enum
rx_msdu_decap_format
decap
;
if
(
head
->
len
==
0
)
{
ath10k_dbg
(
ar
,
ATH10K_DBG_HTT
,
"htt rx dropping due to zero-len
\n
"
);
return
false
;
}
first
=
skb_peek
(
amsdu
);
rxd
=
(
void
*
)
first
->
data
-
sizeof
(
*
rxd
);
decap
=
MS
(
__le32_to_cpu
(
rxd
->
msdu_start
.
info1
),
RX_MSDU_START_INFO1_DECAP_FORMAT
);
if
(
attention
&
RX_ATTENTION_FLAGS_DECRYPT_ERR
)
{
ath10k_dbg
(
ar
,
ATH10K_DBG_HTT
,
"htt rx dropping due to decrypt-err
\n
"
);
return
false
;
if
(
!
chained
)
return
;
/* FIXME: Current unchaining logic can only handle simple case of raw
* msdu chaining. If decapping is other than raw the chaining may be
* more complex and this isn't handled by the current code. Don't even
* try re-constructing such frames - it'll be pretty much garbage.
*/
if
(
decap
!=
RX_MSDU_DECAP_RAW
||
skb_queue_len
(
amsdu
)
!=
1
+
rxd
->
frag_info
.
ring2_more_count
)
{
__skb_queue_purge
(
amsdu
);
return
;
}
if
(
!
channel_set
)
{
ath10k_warn
(
ar
,
"no channel configured; ignoring frame!
\n
"
);
ath10k_unchain_msdu
(
amsdu
);
}
static
bool
ath10k_htt_rx_amsdu_allowed
(
struct
ath10k
*
ar
,
struct
sk_buff_head
*
amsdu
,
struct
ieee80211_rx_status
*
rx_status
)
{
struct
sk_buff
*
msdu
;
struct
htt_rx_desc
*
rxd
;
bool
is_mgmt
;
bool
has_fcs_err
;
msdu
=
skb_peek
(
amsdu
);
rxd
=
(
void
*
)
msdu
->
data
-
sizeof
(
*
rxd
);
/* FIXME: It might be a good idea to do some fuzzy-testing to drop
* invalid/dangerous frames.
*/
if
(
!
rx_status
->
freq
)
{
ath10k_warn
(
ar
,
"no channel configured; ignoring frame(s)!
\n
"
);
return
false
;
}
/* Skip mgmt frames while we handle this in WMI */
if
(
attention
&
RX_ATTENTION_FLAGS_MGMT_TYPE
)
{
is_mgmt
=
!!
(
rxd
->
attention
.
flags
&
__cpu_to_le32
(
RX_ATTENTION_FLAGS_MGMT_TYPE
));
has_fcs_err
=
!!
(
rxd
->
attention
.
flags
&
__cpu_to_le32
(
RX_ATTENTION_FLAGS_FCS_ERR
));
/* Management frames are handled via WMI events. The pros of such
* approach is that channel is explicitly provided in WMI events
* whereas HTT doesn't provide channel information for Rxed frames.
*
* However some firmware revisions don't report corrupted frames via
* WMI so don't drop them.
*/
if
(
is_mgmt
&&
!
has_fcs_err
)
{
ath10k_dbg
(
ar
,
ATH10K_DBG_HTT
,
"htt rx mgmt ctrl
\n
"
);
return
false
;
}
if
(
test_bit
(
ATH10K_CAC_RUNNING
,
&
htt
->
ar
->
dev_flags
))
{
ath10k_dbg
(
ar
,
ATH10K_DBG_HTT
,
"htt rx CAC running
\n
"
);
if
(
test_bit
(
ATH10K_CAC_RUNNING
,
&
ar
->
dev_flags
))
{
ath10k_dbg
(
ar
,
ATH10K_DBG_HTT
,
"htt rx cac running
\n
"
);
return
false
;
}
return
true
;
}
static
void
ath10k_htt_rx_h_filter
(
struct
ath10k
*
ar
,
struct
sk_buff_head
*
amsdu
,
struct
ieee80211_rx_status
*
rx_status
)
{
if
(
skb_queue_empty
(
amsdu
))
return
;
if
(
ath10k_htt_rx_amsdu_allowed
(
ar
,
amsdu
,
rx_status
))
return
;
__skb_queue_purge
(
amsdu
);
}
static
void
ath10k_htt_rx_handler
(
struct
ath10k_htt
*
htt
,
struct
htt_rx_indication
*
rx
)
{
struct
ath10k
*
ar
=
htt
->
ar
;
struct
ieee80211_rx_status
*
rx_status
=
&
htt
->
rx_status
;
struct
htt_rx_indication_mpdu_range
*
mpdu_ranges
;
struct
ieee80211_hdr
*
hdr
;
struct
sk_buff_head
amsdu
;
int
num_mpdu_ranges
;
u32
attention
;
int
fw_desc_len
;
u8
*
fw_desc
;
bool
channel_set
;
int
i
,
j
;
int
ret
;
int
i
,
ret
,
mpdu_count
=
0
;
lockdep_assert_held
(
&
htt
->
rx_ring
.
lock
);
if
(
htt
->
rx_confused
)
return
;
fw_desc_len
=
__le16_to_cpu
(
rx
->
prefix
.
fw_rx_desc_bytes
);
fw_desc
=
(
u8
*
)
&
rx
->
fw_desc
;
...
...
@@ -1241,85 +1378,33 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES
);
mpdu_ranges
=
htt_rx_ind_get_mpdu_ranges
(
rx
);
/* Fill this once, while this is per-ppdu */
if
(
rx
->
ppdu
.
info0
&
HTT_RX_INDICATION_INFO0_START_VALID
)
{
memset
(
rx_status
,
0
,
sizeof
(
*
rx_status
));
rx_status
->
signal
=
ATH10K_DEFAULT_NOISE_FLOOR
+
rx
->
ppdu
.
combined_rssi
;
}
if
(
rx
->
ppdu
.
info0
&
HTT_RX_INDICATION_INFO0_END_VALID
)
{
/* TSF available only in 32-bit */
rx_status
->
mactime
=
__le32_to_cpu
(
rx
->
ppdu
.
tsf
)
&
0xffffffff
;
rx_status
->
flag
|=
RX_FLAG_MACTIME_END
;
}
channel_set
=
ath10k_htt_rx_h_channel
(
htt
->
ar
,
rx_status
);
if
(
channel_set
)
{
ath10k_htt_rx_h_rates
(
htt
->
ar
,
rx_status
->
band
,
rx
->
ppdu
.
info0
,
__le32_to_cpu
(
rx
->
ppdu
.
info1
),
__le32_to_cpu
(
rx
->
ppdu
.
info2
),
rx_status
);
}
ath10k_dbg_dump
(
ar
,
ATH10K_DBG_HTT_DUMP
,
NULL
,
"htt rx ind: "
,
rx
,
sizeof
(
*
rx
)
+
(
sizeof
(
struct
htt_rx_indication_mpdu_range
)
*
num_mpdu_ranges
));
for
(
i
=
0
;
i
<
num_mpdu_ranges
;
i
++
)
{
for
(
j
=
0
;
j
<
mpdu_ranges
[
i
].
mpdu_count
;
j
++
)
{
struct
sk_buff
*
msdu_head
,
*
msdu_tail
;
attention
=
0
;
msdu_head
=
NULL
;
msdu_tail
=
NULL
;
ret
=
ath10k_htt_rx_amsdu_pop
(
htt
,
&
fw_desc
,
&
fw_desc_len
,
&
msdu_head
,
&
msdu_tail
,
&
attention
);
for
(
i
=
0
;
i
<
num_mpdu_ranges
;
i
++
)
mpdu_count
+=
mpdu_ranges
[
i
].
mpdu_count
;
while
(
mpdu_count
--
)
{
__skb_queue_head_init
(
&
amsdu
);
ret
=
ath10k_htt_rx_amsdu_pop
(
htt
,
&
fw_desc
,
&
fw_desc_len
,
&
amsdu
);
if
(
ret
<
0
)
{
ath10k_warn
(
ar
,
"failed to pop amsdu from htt rx ring %d
\n
"
,
ret
);
ath10k_htt_rx_free_msdu_chain
(
msdu_head
);
continue
;
}
if
(
!
ath10k_htt_rx_amsdu_allowed
(
htt
,
msdu_head
,
channel_set
,
attention
))
{
ath10k_htt_rx_free_msdu_chain
(
msdu_head
);
continue
;
}
if
(
ret
>
0
&&
ath10k_unchain_msdu
(
msdu_head
)
<
0
)
{
ath10k_htt_rx_free_msdu_chain
(
msdu_head
);
continue
;
ath10k_warn
(
ar
,
"rx ring became corrupted: %d
\n
"
,
ret
);
__skb_queue_purge
(
&
amsdu
);
/* FIXME: It's probably a good idea to reboot the
* device instead of leaving it inoperable.
*/
htt
->
rx_confused
=
true
;
break
;
}
if
(
attention
&
RX_ATTENTION_FLAGS_FCS_ERR
)
rx_status
->
flag
|=
RX_FLAG_FAILED_FCS_CRC
;
else
rx_status
->
flag
&=
~
RX_FLAG_FAILED_FCS_CRC
;
if
(
attention
&
RX_ATTENTION_FLAGS_TKIP_MIC_ERR
)
rx_status
->
flag
|=
RX_FLAG_MMIC_ERROR
;
else
rx_status
->
flag
&=
~
RX_FLAG_MMIC_ERROR
;
hdr
=
ath10k_htt_rx_skb_get_hdr
(
msdu_head
);
if
(
ath10k_htt_rx_hdr_is_amsdu
(
hdr
))
ath10k_htt_rx_amsdu
(
htt
,
rx_status
,
msdu_head
);
else
ath10k_htt_rx_msdu
(
htt
,
rx_status
,
msdu_head
);
}
ath10k_htt_rx_h_ppdu
(
ar
,
&
amsdu
,
rx_status
);
ath10k_htt_rx_h_unchain
(
ar
,
&
amsdu
,
ret
>
0
);
ath10k_htt_rx_h_filter
(
ar
,
&
amsdu
,
rx_status
);
ath10k_htt_rx_h_mpdu
(
ar
,
&
amsdu
,
rx_status
);
ath10k_htt_rx_h_deliver
(
ar
,
&
amsdu
,
rx_status
);
}
tasklet_schedule
(
&
htt
->
rx_replenish_task
);
...
...
@@ -1329,30 +1414,20 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
struct
htt_rx_fragment_indication
*
frag
)
{
struct
ath10k
*
ar
=
htt
->
ar
;
struct
sk_buff
*
msdu_head
,
*
msdu_tail
;
enum
htt_rx_mpdu_encrypt_type
enctype
;
struct
htt_rx_desc
*
rxd
;
enum
rx_msdu_decap_format
fmt
;
struct
ieee80211_rx_status
*
rx_status
=
&
htt
->
rx_status
;
struct
ieee80211_hdr
*
hdr
;
struct
sk_buff_head
amsdu
;
int
ret
;
bool
tkip_mic_err
;
bool
decrypt_err
;
u8
*
fw_desc
;
int
fw_desc_len
,
hdrlen
,
paramlen
;
int
trim
;
u32
attention
=
0
;
int
fw_desc_len
;
fw_desc_len
=
__le16_to_cpu
(
frag
->
fw_rx_desc_bytes
);
fw_desc
=
(
u8
*
)
frag
->
fw_msdu_rx_desc
;
msdu_head
=
NULL
;
msdu_tail
=
NULL
;
__skb_queue_head_init
(
&
amsdu
);
spin_lock_bh
(
&
htt
->
rx_ring
.
lock
);
ret
=
ath10k_htt_rx_amsdu_pop
(
htt
,
&
fw_desc
,
&
fw_desc_len
,
&
msdu_head
,
&
msdu_tail
,
&
attention
);
&
amsdu
);
spin_unlock_bh
(
&
htt
->
rx_ring
.
lock
);
tasklet_schedule
(
&
htt
->
rx_replenish_task
);
...
...
@@ -1362,77 +1437,21 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
if
(
ret
)
{
ath10k_warn
(
ar
,
"failed to pop amsdu from httr rx ring for fragmented rx %d
\n
"
,
ret
);
ath10k_htt_rx_free_msdu_chain
(
msdu_head
);
__skb_queue_purge
(
&
amsdu
);
return
;
}
/* FIXME: implement signal strength */
rx_status
->
flag
|=
RX_FLAG_NO_SIGNAL_VAL
;
hdr
=
(
struct
ieee80211_hdr
*
)
msdu_head
->
data
;
rxd
=
(
void
*
)
msdu_head
->
data
-
sizeof
(
*
rxd
);
tkip_mic_err
=
!!
(
attention
&
RX_ATTENTION_FLAGS_TKIP_MIC_ERR
);
decrypt_err
=
!!
(
attention
&
RX_ATTENTION_FLAGS_DECRYPT_ERR
);
fmt
=
MS
(
__le32_to_cpu
(
rxd
->
msdu_start
.
info1
),
RX_MSDU_START_INFO1_DECAP_FORMAT
);
if
(
fmt
!=
RX_MSDU_DECAP_RAW
)
{
ath10k_warn
(
ar
,
"we dont support non-raw fragmented rx yet
\n
"
);
dev_kfree_skb_any
(
msdu_head
);
goto
end
;
}
enctype
=
MS
(
__le32_to_cpu
(
rxd
->
mpdu_start
.
info0
),
RX_MPDU_START_INFO0_ENCRYPT_TYPE
);
ath10k_htt_rx_h_protected
(
htt
,
rx_status
,
msdu_head
,
enctype
,
fmt
,
true
);
msdu_head
->
ip_summed
=
ath10k_htt_rx_get_csum_state
(
msdu_head
);
if
(
tkip_mic_err
)
ath10k_warn
(
ar
,
"tkip mic error
\n
"
);
if
(
decrypt_err
)
{
ath10k_warn
(
ar
,
"decryption err in fragmented rx
\n
"
);
dev_kfree_skb_any
(
msdu_head
);
goto
end
;
}
if
(
enctype
!=
HTT_RX_MPDU_ENCRYPT_NONE
)
{
hdrlen
=
ieee80211_hdrlen
(
hdr
->
frame_control
);
paramlen
=
ath10k_htt_rx_crypto_param_len
(
ar
,
enctype
);
/* It is more efficient to move the header than the payload */
memmove
((
void
*
)
msdu_head
->
data
+
paramlen
,
(
void
*
)
msdu_head
->
data
,
hdrlen
);
skb_pull
(
msdu_head
,
paramlen
);
hdr
=
(
struct
ieee80211_hdr
*
)
msdu_head
->
data
;
}
/* remove trailing FCS */
trim
=
4
;
/* remove crypto trailer */
trim
+=
ath10k_htt_rx_crypto_tail_len
(
ar
,
enctype
);
/* last fragment of TKIP frags has MIC */
if
(
!
ieee80211_has_morefrags
(
hdr
->
frame_control
)
&&
enctype
==
HTT_RX_MPDU_ENCRYPT_TKIP_WPA
)
trim
+=
MICHAEL_MIC_LEN
;
if
(
trim
>
msdu_head
->
len
)
{
ath10k_warn
(
ar
,
"htt rx fragment: trailer longer than the frame itself? drop
\n
"
);
dev_kfree_skb_any
(
msdu_head
);
goto
end
;
if
(
skb_queue_len
(
&
amsdu
)
!=
1
)
{
ath10k_warn
(
ar
,
"failed to pop frag amsdu: too many msdus
\n
"
);
__skb_queue_purge
(
&
amsdu
);
return
;
}
skb_trim
(
msdu_head
,
msdu_head
->
len
-
trim
);
ath10k_dbg_dump
(
ar
,
ATH10K_DBG_HTT_DUMP
,
NULL
,
"htt rx frag mpdu: "
,
msdu_head
->
data
,
msdu_head
->
len
);
ath10k_process_rx
(
htt
->
ar
,
rx_status
,
msdu_head
);
ath10k_htt_rx_h_ppdu
(
ar
,
&
amsdu
,
rx_status
);
ath10k_htt_rx_h_filter
(
ar
,
&
amsdu
,
rx_status
);
ath10k_htt_rx_h_mpdu
(
ar
,
&
amsdu
,
rx_status
);
ath10k_htt_rx_h_deliver
(
ar
,
&
amsdu
,
rx_status
);
end:
if
(
fw_desc_len
>
0
)
{
ath10k_dbg
(
ar
,
ATH10K_DBG_HTT
,
"expecting more fragmented rx in one indication %d
\n
"
,
...
...
drivers/net/wireless/ath/ath10k/htt_tx.c
浏览文件 @
cbe1bc23
...
...
@@ -554,13 +554,14 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
skb_cb
->
htt
.
txbuf
->
cmd_tx
.
len
=
__cpu_to_le16
(
msdu
->
len
);
skb_cb
->
htt
.
txbuf
->
cmd_tx
.
id
=
__cpu_to_le16
(
msdu_id
);
skb_cb
->
htt
.
txbuf
->
cmd_tx
.
frags_paddr
=
__cpu_to_le32
(
frags_paddr
);
skb_cb
->
htt
.
txbuf
->
cmd_tx
.
peerid
=
__cpu_to_le32
(
HTT_INVALID_PEERID
);
skb_cb
->
htt
.
txbuf
->
cmd_tx
.
peerid
=
__cpu_to_le16
(
HTT_INVALID_PEERID
);
skb_cb
->
htt
.
txbuf
->
cmd_tx
.
freq
=
__cpu_to_le16
(
skb_cb
->
htt
.
freq
);
trace_ath10k_htt_tx
(
ar
,
msdu_id
,
msdu
->
len
,
vdev_id
,
tid
);
ath10k_dbg
(
ar
,
ATH10K_DBG_HTT
,
"htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu
\n
"
,
"htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu
freq %hu
\n
"
,
flags0
,
flags1
,
msdu
->
len
,
msdu_id
,
frags_paddr
,
(
u32
)
skb_cb
->
paddr
,
vdev_id
,
tid
);
(
u32
)
skb_cb
->
paddr
,
vdev_id
,
tid
,
skb_cb
->
htt
.
freq
);
ath10k_dbg_dump
(
ar
,
ATH10K_DBG_HTT_DUMP
,
NULL
,
"htt tx msdu: "
,
msdu
->
data
,
msdu
->
len
);
trace_ath10k_tx_hdr
(
ar
,
msdu
->
data
,
msdu
->
len
);
...
...
drivers/net/wireless/ath/ath10k/hw.h
浏览文件 @
cbe1bc23
...
...
@@ -97,11 +97,13 @@ struct ath10k_pktlog_hdr {
#define TARGET_DMA_BURST_SIZE 0
#define TARGET_MAC_AGGR_DELIM 0
#define TARGET_AST_SKID_LIMIT 16
#define TARGET_NUM_PEERS 16
#define TARGET_NUM_STATIONS 16
#define TARGET_NUM_PEERS ((TARGET_NUM_STATIONS) + \
(TARGET_NUM_VDEVS))
#define TARGET_NUM_OFFLOAD_PEERS 0
#define TARGET_NUM_OFFLOAD_REORDER_BUFS 0
#define TARGET_NUM_PEER_KEYS 2
#define TARGET_NUM_TIDS
(2 * ((TARGET_NUM_PEERS) + (TARGET_NUM_VDEVS))
)
#define TARGET_NUM_TIDS
((TARGET_NUM_PEERS) * 2
)
#define TARGET_TX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
#define TARGET_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
#define TARGET_RX_TIMEOUT_LO_PRI 100
...
...
@@ -132,12 +134,15 @@ struct ath10k_pktlog_hdr {
#define TARGET_10X_DMA_BURST_SIZE 0
#define TARGET_10X_MAC_AGGR_DELIM 0
#define TARGET_10X_AST_SKID_LIMIT 16
#define TARGET_10X_NUM_PEERS (128 + (TARGET_10X_NUM_VDEVS))
#define TARGET_10X_NUM_PEERS_MAX 128
#define TARGET_10X_NUM_STATIONS 128
#define TARGET_10X_NUM_PEERS ((TARGET_10X_NUM_STATIONS) + \
(TARGET_10X_NUM_VDEVS))
#define TARGET_10X_NUM_OFFLOAD_PEERS 0
#define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS 0
#define TARGET_10X_NUM_PEER_KEYS 2
#define TARGET_10X_NUM_TIDS 256
#define TARGET_10X_NUM_TIDS_MAX 256
#define TARGET_10X_NUM_TIDS min((TARGET_10X_NUM_TIDS_MAX), \
(TARGET_10X_NUM_PEERS) * 2)
#define TARGET_10X_TX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
#define TARGET_10X_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
#define TARGET_10X_RX_TIMEOUT_LO_PRI 100
...
...
drivers/net/wireless/ath/ath10k/mac.c
浏览文件 @
cbe1bc23
...
...
@@ -136,7 +136,9 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,
if
(
ret
)
return
ret
;
spin_lock_bh
(
&
ar
->
data_lock
);
peer
->
keys
[
i
]
=
arvif
->
wep_keys
[
i
];
spin_unlock_bh
(
&
ar
->
data_lock
);
}
return
0
;
...
...
@@ -173,12 +175,39 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif,
ath10k_warn
(
ar
,
"failed to remove peer wep key %d: %d
\n
"
,
i
,
ret
);
spin_lock_bh
(
&
ar
->
data_lock
);
peer
->
keys
[
i
]
=
NULL
;
spin_unlock_bh
(
&
ar
->
data_lock
);
}
return
first_errno
;
}
bool
ath10k_mac_is_peer_wep_key_set
(
struct
ath10k
*
ar
,
const
u8
*
addr
,
u8
keyidx
)
{
struct
ath10k_peer
*
peer
;
int
i
;
lockdep_assert_held
(
&
ar
->
data_lock
);
/* We don't know which vdev this peer belongs to,
* since WMI doesn't give us that information.
*
* FIXME: multi-bss needs to be handled.
*/
peer
=
ath10k_peer_find
(
ar
,
0
,
addr
);
if
(
!
peer
)
return
false
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
peer
->
keys
);
i
++
)
{
if
(
peer
->
keys
[
i
]
&&
peer
->
keys
[
i
]
->
keyidx
==
keyidx
)
return
true
;
}
return
false
;
}
static
int
ath10k_clear_vdev_key
(
struct
ath10k_vif
*
arvif
,
struct
ieee80211_key_conf
*
key
)
{
...
...
@@ -326,6 +355,9 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
lockdep_assert_held
(
&
ar
->
conf_mutex
);
if
(
ar
->
num_peers
>=
ar
->
max_num_peers
)
return
-
ENOBUFS
;
ret
=
ath10k_wmi_peer_create
(
ar
,
vdev_id
,
addr
);
if
(
ret
)
{
ath10k_warn
(
ar
,
"failed to create wmi peer %pM on vdev %i: %i
\n
"
,
...
...
@@ -339,9 +371,8 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
addr
,
vdev_id
,
ret
);
return
ret
;
}
spin_lock_bh
(
&
ar
->
data_lock
);
ar
->
num_peers
++
;
spin_unlock_bh
(
&
ar
->
data_lock
);
return
0
;
}
...
...
@@ -396,10 +427,6 @@ static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value)
struct
ath10k
*
ar
=
arvif
->
ar
;
u32
vdev_param
;
if
(
value
!=
0xFFFFFFFF
)
value
=
min_t
(
u32
,
arvif
->
ar
->
hw
->
wiphy
->
rts_threshold
,
ATH10K_RTS_MAX
);
vdev_param
=
ar
->
wmi
.
vdev_param
->
rts_threshold
;
return
ath10k_wmi_vdev_set_param
(
ar
,
arvif
->
vdev_id
,
vdev_param
,
value
);
}
...
...
@@ -432,9 +459,7 @@ static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr)
if
(
ret
)
return
ret
;
spin_lock_bh
(
&
ar
->
data_lock
);
ar
->
num_peers
--
;
spin_unlock_bh
(
&
ar
->
data_lock
);
return
0
;
}
...
...
@@ -471,8 +496,10 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)
list_del
(
&
peer
->
list
);
kfree
(
peer
);
}
ar
->
num_peers
=
0
;
spin_unlock_bh
(
&
ar
->
data_lock
);
ar
->
num_peers
=
0
;
ar
->
num_stations
=
0
;
}
/************************/
...
...
@@ -1997,6 +2024,18 @@ static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar,
}
}
static
bool
ath10k_mac_need_offchan_tx_work
(
struct
ath10k
*
ar
)
{
/* FIXME: Not really sure since when the behaviour changed. At some
* point new firmware stopped requiring creation of peer entries for
* offchannel tx (and actually creating them causes issues with wmi-htc
* tx credit replenishment and reliability). Assuming it's at least 3.4
* because that's when the `freq` was introduced to TX_FRM HTT command.
*/
return
!
(
ar
->
htt
.
target_version_major
>=
3
&&
ar
->
htt
.
target_version_minor
>=
4
);
}
static
void
ath10k_tx_htt
(
struct
ath10k
*
ar
,
struct
sk_buff
*
skb
)
{
struct
ieee80211_hdr
*
hdr
=
(
struct
ieee80211_hdr
*
)
skb
->
data
;
...
...
@@ -2172,10 +2211,10 @@ void __ath10k_scan_finish(struct ath10k *ar)
case
ATH10K_SCAN_IDLE
:
break
;
case
ATH10K_SCAN_RUNNING
:
case
ATH10K_SCAN_ABORTING
:
if
(
ar
->
scan
.
is_roc
)
ieee80211_remain_on_channel_expired
(
ar
->
hw
);
else
case
ATH10K_SCAN_ABORTING
:
if
(
!
ar
->
scan
.
is_roc
)
ieee80211_scan_completed
(
ar
->
hw
,
(
ar
->
scan
.
state
==
ATH10K_SCAN_ABORTING
));
...
...
@@ -2341,10 +2380,14 @@ static void ath10k_tx(struct ieee80211_hw *hw,
if
(
info
->
flags
&
IEEE80211_TX_CTL_TX_OFFCHAN
)
{
spin_lock_bh
(
&
ar
->
data_lock
);
ATH10K_SKB_CB
(
skb
)
->
htt
.
is_offchan
=
true
;
ATH10K_SKB_CB
(
skb
)
->
htt
.
freq
=
ar
->
scan
.
roc_freq
;
ATH10K_SKB_CB
(
skb
)
->
vdev_id
=
ar
->
scan
.
vdev_id
;
spin_unlock_bh
(
&
ar
->
data_lock
);
if
(
ath10k_mac_need_offchan_tx_work
(
ar
))
{
ATH10K_SKB_CB
(
skb
)
->
htt
.
freq
=
0
;
ATH10K_SKB_CB
(
skb
)
->
htt
.
is_offchan
=
true
;
ath10k_dbg
(
ar
,
ATH10K_DBG_MAC
,
"queued offchannel skb %p
\n
"
,
skb
);
...
...
@@ -2352,6 +2395,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
ieee80211_queue_work
(
hw
,
&
ar
->
offchan_tx_work
);
return
;
}
}
ath10k_tx_htt
(
ar
,
skb
);
}
...
...
@@ -2414,12 +2458,28 @@ static int ath10k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
return
0
;
}
static
void
ath10k_check_chain_mask
(
struct
ath10k
*
ar
,
u32
cm
,
const
char
*
dbg
)
{
/* It is not clear that allowing gaps in chainmask
* is helpful. Probably it will not do what user
* is hoping for, so warn in that case.
*/
if
(
cm
==
15
||
cm
==
7
||
cm
==
3
||
cm
==
1
||
cm
==
0
)
return
;
ath10k_warn
(
ar
,
"mac %s antenna chainmask may be invalid: 0x%x. Suggested values: 15, 7, 3, 1 or 0.
\n
"
,
dbg
,
cm
);
}
static
int
__ath10k_set_antenna
(
struct
ath10k
*
ar
,
u32
tx_ant
,
u32
rx_ant
)
{
int
ret
;
lockdep_assert_held
(
&
ar
->
conf_mutex
);
ath10k_check_chain_mask
(
ar
,
tx_ant
,
"tx"
);
ath10k_check_chain_mask
(
ar
,
rx_ant
,
"rx"
);
ar
->
cfg_tx_chainmask
=
tx_ant
;
ar
->
cfg_rx_chainmask
=
rx_ant
;
...
...
@@ -2782,6 +2842,17 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
return
ret
;
}
static
u32
get_nss_from_chainmask
(
u16
chain_mask
)
{
if
((
chain_mask
&
0x15
)
==
0x15
)
return
4
;
else
if
((
chain_mask
&
0x7
)
==
0x7
)
return
3
;
else
if
((
chain_mask
&
0x3
)
==
0x3
)
return
2
;
return
1
;
}
/*
* TODO:
* Figure out how to handle WMI_VDEV_SUBTYPE_P2P_DEVICE,
...
...
@@ -2914,6 +2985,20 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
goto
err_vdev_delete
;
}
if
(
ar
->
cfg_tx_chainmask
)
{
u16
nss
=
get_nss_from_chainmask
(
ar
->
cfg_tx_chainmask
);
vdev_param
=
ar
->
wmi
.
vdev_param
->
nss
;
ret
=
ath10k_wmi_vdev_set_param
(
ar
,
arvif
->
vdev_id
,
vdev_param
,
nss
);
if
(
ret
)
{
ath10k_warn
(
ar
,
"failed to set vdev %i chainmask 0x%x, nss %i: %d
\n
"
,
arvif
->
vdev_id
,
ar
->
cfg_tx_chainmask
,
nss
,
ret
);
goto
err_vdev_delete
;
}
}
if
(
arvif
->
vdev_type
==
WMI_VDEV_TYPE_AP
)
{
ret
=
ath10k_peer_create
(
ar
,
arvif
->
vdev_id
,
vif
->
addr
);
if
(
ret
)
{
...
...
@@ -3014,10 +3099,10 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
struct
ath10k_vif
*
arvif
=
ath10k_vif_to_arvif
(
vif
);
int
ret
;
mutex_lock
(
&
ar
->
conf_mutex
);
cancel_work_sync
(
&
arvif
->
wep_key_work
);
mutex_lock
(
&
ar
->
conf_mutex
);
spin_lock_bh
(
&
ar
->
data_lock
);
ath10k_mac_vif_beacon_cleanup
(
arvif
);
spin_unlock_bh
(
&
ar
->
data_lock
);
...
...
@@ -3511,6 +3596,37 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
mutex_unlock
(
&
ar
->
conf_mutex
);
}
static
int
ath10k_mac_inc_num_stations
(
struct
ath10k_vif
*
arvif
)
{
struct
ath10k
*
ar
=
arvif
->
ar
;
lockdep_assert_held
(
&
ar
->
conf_mutex
);
if
(
arvif
->
vdev_type
!=
WMI_VDEV_TYPE_AP
&&
arvif
->
vdev_type
!=
WMI_VDEV_TYPE_IBSS
)
return
0
;
if
(
ar
->
num_stations
>=
ar
->
max_num_stations
)
return
-
ENOBUFS
;
ar
->
num_stations
++
;
return
0
;
}
static
void
ath10k_mac_dec_num_stations
(
struct
ath10k_vif
*
arvif
)
{
struct
ath10k
*
ar
=
arvif
->
ar
;
lockdep_assert_held
(
&
ar
->
conf_mutex
);
if
(
arvif
->
vdev_type
!=
WMI_VDEV_TYPE_AP
&&
arvif
->
vdev_type
!=
WMI_VDEV_TYPE_IBSS
)
return
;
ar
->
num_stations
--
;
}
static
int
ath10k_sta_state
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_sta
*
sta
,
...
...
@@ -3520,7 +3636,6 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
struct
ath10k
*
ar
=
hw
->
priv
;
struct
ath10k_vif
*
arvif
=
ath10k_vif_to_arvif
(
vif
);
struct
ath10k_sta
*
arsta
=
(
struct
ath10k_sta
*
)
sta
->
drv_priv
;
int
max_num_peers
;
int
ret
=
0
;
if
(
old_state
==
IEEE80211_STA_NOTEXIST
&&
...
...
@@ -3542,26 +3657,26 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
/*
* New station addition.
*/
if
(
test_bit
(
ATH10K_FW_FEATURE_WMI_10X
,
ar
->
fw_features
))
max_num_peers
=
TARGET_10X_NUM_PEERS_MAX
-
1
;
else
max_num_peers
=
TARGET_NUM_PEERS
;
ath10k_dbg
(
ar
,
ATH10K_DBG_MAC
,
"mac vdev %d peer create %pM (new sta) sta %d / %d peer %d / %d
\n
"
,
arvif
->
vdev_id
,
sta
->
addr
,
ar
->
num_stations
+
1
,
ar
->
max_num_stations
,
ar
->
num_peers
+
1
,
ar
->
max_num_peers
);
if
(
ar
->
num_peers
>=
max_num_peers
)
{
ath10k_warn
(
ar
,
"number of peers exceeded: peers number %d (max peers %d)
\n
"
,
ar
->
num_peers
,
max_num_peers
);
ret
=
-
ENOBUFS
;
ret
=
ath10k_mac_inc_num_stations
(
arvif
);
if
(
ret
)
{
ath10k_warn
(
ar
,
"refusing to associate station: too many connected already (%d)
\n
"
,
ar
->
max_num_stations
)
;
goto
exit
;
}
ath10k_dbg
(
ar
,
ATH10K_DBG_MAC
,
"mac vdev %d peer create %pM (new sta) num_peers %d
\n
"
,
arvif
->
vdev_id
,
sta
->
addr
,
ar
->
num_peers
);
ret
=
ath10k_peer_create
(
ar
,
arvif
->
vdev_id
,
sta
->
addr
);
if
(
ret
)
if
(
ret
)
{
ath10k_warn
(
ar
,
"failed to add peer %pM for vdev %d when adding a new sta: %i
\n
"
,
sta
->
addr
,
arvif
->
vdev_id
,
ret
);
ath10k_mac_dec_num_stations
(
arvif
);
goto
exit
;
}
if
(
vif
->
type
==
NL80211_IFTYPE_STATION
)
{
WARN_ON
(
arvif
->
is_started
);
...
...
@@ -3572,6 +3687,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
arvif
->
vdev_id
,
ret
);
WARN_ON
(
ath10k_peer_delete
(
ar
,
arvif
->
vdev_id
,
sta
->
addr
));
ath10k_mac_dec_num_stations
(
arvif
);
goto
exit
;
}
...
...
@@ -3602,6 +3718,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
ath10k_warn
(
ar
,
"failed to delete peer %pM for vdev %d: %i
\n
"
,
sta
->
addr
,
arvif
->
vdev_id
,
ret
);
ath10k_mac_dec_num_stations
(
arvif
);
}
else
if
(
old_state
==
IEEE80211_STA_AUTH
&&
new_state
==
IEEE80211_STA_ASSOC
&&
(
vif
->
type
==
NL80211_IFTYPE_AP
||
...
...
@@ -3790,6 +3907,8 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
if
(
ret
)
goto
exit
;
duration
=
max
(
duration
,
WMI_SCAN_CHAN_MIN_TIME_MSEC
);
memset
(
&
arg
,
0
,
sizeof
(
arg
));
ath10k_wmi_start_scan_init
(
ar
,
&
arg
);
arg
.
vdev_id
=
arvif
->
vdev_id
;
...
...
@@ -4106,6 +4225,10 @@ ath10k_default_bitrate_mask(struct ath10k *ar,
u32
legacy
=
0x00ff
;
u8
ht
=
0xff
,
i
;
u16
vht
=
0x3ff
;
u16
nrf
=
ar
->
num_rf_chains
;
if
(
ar
->
cfg_tx_chainmask
)
nrf
=
get_nss_from_chainmask
(
ar
->
cfg_tx_chainmask
);
switch
(
band
)
{
case
IEEE80211_BAND_2GHZ
:
...
...
@@ -4121,11 +4244,11 @@ ath10k_default_bitrate_mask(struct ath10k *ar,
if
(
mask
->
control
[
band
].
legacy
!=
legacy
)
return
false
;
for
(
i
=
0
;
i
<
ar
->
num_rf_chains
;
i
++
)
for
(
i
=
0
;
i
<
nrf
;
i
++
)
if
(
mask
->
control
[
band
].
ht_mcs
[
i
]
!=
ht
)
return
false
;
for
(
i
=
0
;
i
<
ar
->
num_rf_chains
;
i
++
)
for
(
i
=
0
;
i
<
nrf
;
i
++
)
if
(
mask
->
control
[
band
].
vht_mcs
[
i
]
!=
vht
)
return
false
;
...
...
@@ -4376,6 +4499,9 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw,
u8
fixed_nss
=
ar
->
num_rf_chains
;
u8
force_sgi
;
if
(
ar
->
cfg_tx_chainmask
)
fixed_nss
=
get_nss_from_chainmask
(
ar
->
cfg_tx_chainmask
);
force_sgi
=
mask
->
control
[
band
].
gi
;
if
(
force_sgi
==
NL80211_TXRATE_FORCE_LGI
)
return
-
EINVAL
;
...
...
@@ -4905,10 +5031,6 @@ int ath10k_mac_register(struct ath10k *ar)
IEEE80211_HW_AP_LINK_PS
|
IEEE80211_HW_SPECTRUM_MGMT
;
/* MSDU can have HTT TX fragment pushed in front. The additional 4
* bytes is used for padding/alignment if necessary. */
ar
->
hw
->
extra_tx_headroom
+=
sizeof
(
struct
htt_data_tx_desc_frag
)
*
2
+
4
;
ar
->
hw
->
wiphy
->
features
|=
NL80211_FEATURE_STATIC_SMPS
;
if
(
ar
->
ht_cap_info
&
WMI_HT_CAP_DYNAMIC_SMPS
)
...
...
drivers/net/wireless/ath/ath10k/mac.h
浏览文件 @
cbe1bc23
...
...
@@ -21,6 +21,8 @@
#include <net/mac80211.h>
#include "core.h"
#define WEP_KEYID_SHIFT 6
struct
ath10k_generic_iter
{
struct
ath10k
*
ar
;
int
ret
;
...
...
@@ -41,6 +43,8 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work);
void
ath10k_halt
(
struct
ath10k
*
ar
);
void
ath10k_mac_vif_beacon_free
(
struct
ath10k_vif
*
arvif
);
void
ath10k_drain_tx
(
struct
ath10k
*
ar
);
bool
ath10k_mac_is_peer_wep_key_set
(
struct
ath10k
*
ar
,
const
u8
*
addr
,
u8
keyidx
);
static
inline
struct
ath10k_vif
*
ath10k_vif_to_arvif
(
struct
ieee80211_vif
*
vif
)
{
...
...
drivers/net/wireless/ath/ath10k/pci.c
浏览文件 @
cbe1bc23
...
...
@@ -823,20 +823,24 @@ static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state)
struct
ath10k
*
ar
=
ce_state
->
ar
;
struct
ath10k_pci
*
ar_pci
=
ath10k_pci_priv
(
ar
);
struct
ath10k_hif_cb
*
cb
=
&
ar_pci
->
msg_callbacks_current
;
void
*
transfer_context
;
struct
sk_buff_head
list
;
struct
sk_buff
*
skb
;
u32
ce_data
;
unsigned
int
nbytes
;
unsigned
int
transfer_id
;
while
(
ath10k_ce_completed_send_next
(
ce_state
,
&
transfer_context
,
&
ce_data
,
&
nbytes
,
&
transfer_id
)
==
0
)
{
__skb_queue_head_init
(
&
list
);
while
(
ath10k_ce_completed_send_next
(
ce_state
,
(
void
**
)
&
skb
,
&
ce_data
,
&
nbytes
,
&
transfer_id
)
==
0
)
{
/* no need to call tx completion for NULL pointers */
if
(
transfer_context
==
NULL
)
if
(
skb
==
NULL
)
continue
;
cb
->
tx_completion
(
ar
,
transfer_context
,
transfer_id
);
__skb_queue_tail
(
&
list
,
skb
);
}
while
((
skb
=
__skb_dequeue
(
&
list
)))
cb
->
tx_completion
(
ar
,
skb
);
}
/* Called by lower (CE) layer when data is received from the Target. */
...
...
@@ -847,12 +851,14 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
struct
ath10k_pci_pipe
*
pipe_info
=
&
ar_pci
->
pipe_info
[
ce_state
->
id
];
struct
ath10k_hif_cb
*
cb
=
&
ar_pci
->
msg_callbacks_current
;
struct
sk_buff
*
skb
;
struct
sk_buff_head
list
;
void
*
transfer_context
;
u32
ce_data
;
unsigned
int
nbytes
,
max_nbytes
;
unsigned
int
transfer_id
;
unsigned
int
flags
;
__skb_queue_head_init
(
&
list
);
while
(
ath10k_ce_completed_recv_next
(
ce_state
,
&
transfer_context
,
&
ce_data
,
&
nbytes
,
&
transfer_id
,
&
flags
)
==
0
)
{
...
...
@@ -869,13 +875,16 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
}
skb_put
(
skb
,
nbytes
);
__skb_queue_tail
(
&
list
,
skb
);
}
while
((
skb
=
__skb_dequeue
(
&
list
)))
{
ath10k_dbg
(
ar
,
ATH10K_DBG_PCI
,
"pci rx ce pipe %d len %d
\n
"
,
ce_state
->
id
,
skb
->
len
);
ath10k_dbg_dump
(
ar
,
ATH10K_DBG_PCI_DUMP
,
NULL
,
"pci rx: "
,
skb
->
data
,
skb
->
len
);
cb
->
rx_completion
(
ar
,
skb
,
pipe_info
->
pipe_num
);
cb
->
rx_completion
(
ar
,
skb
);
}
ath10k_pci_rx_post_pipe
(
pipe_info
);
...
...
@@ -1263,7 +1272,7 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe)
id
=
MS
(
__le16_to_cpu
(
ce_desc
[
i
].
flags
),
CE_DESC_FLAGS_META_DATA
);
ar_pci
->
msg_callbacks_current
.
tx_completion
(
ar
,
skb
,
id
);
ar_pci
->
msg_callbacks_current
.
tx_completion
(
ar
,
skb
);
}
}
...
...
@@ -1988,6 +1997,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
static
const
struct
ath10k_hif_ops
ath10k_pci_hif_ops
=
{
.
tx_sg
=
ath10k_pci_hif_tx_sg
,
.
diag_read
=
ath10k_pci_hif_diag_read
,
.
diag_write
=
ath10k_pci_diag_write_mem
,
.
exchange_bmi_msg
=
ath10k_pci_hif_exchange_bmi_msg
,
.
start
=
ath10k_pci_hif_start
,
.
stop
=
ath10k_pci_hif_stop
,
...
...
@@ -1998,6 +2008,8 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
.
get_free_queue_number
=
ath10k_pci_hif_get_free_queue_number
,
.
power_up
=
ath10k_pci_hif_power_up
,
.
power_down
=
ath10k_pci_hif_power_down
,
.
read32
=
ath10k_pci_read32
,
.
write32
=
ath10k_pci_write32
,
#ifdef CONFIG_PM
.
suspend
=
ath10k_pci_hif_suspend
,
.
resume
=
ath10k_pci_hif_resume
,
...
...
drivers/net/wireless/ath/ath10k/trace.h
浏览文件 @
cbe1bc23
...
...
@@ -21,9 +21,11 @@
#include "core.h"
#if !defined(_TRACE_H_)
static
inline
u32
ath10k_frm_hdr_len
(
void
*
buf
)
static
inline
u32
ath10k_frm_hdr_len
(
const
void
*
buf
)
{
return
ieee80211_hdrlen
(((
struct
ieee80211_hdr
*
)
buf
)
->
frame_control
);
const
struct
ieee80211_hdr
*
hdr
=
buf
;
return
ieee80211_hdrlen
(
hdr
->
frame_control
);
}
#endif
...
...
@@ -145,7 +147,8 @@ TRACE_EVENT(ath10k_log_dbg_dump,
);
TRACE_EVENT
(
ath10k_wmi_cmd
,
TP_PROTO
(
struct
ath10k
*
ar
,
int
id
,
void
*
buf
,
size_t
buf_len
,
int
ret
),
TP_PROTO
(
struct
ath10k
*
ar
,
int
id
,
const
void
*
buf
,
size_t
buf_len
,
int
ret
),
TP_ARGS
(
ar
,
id
,
buf
,
buf_len
,
ret
),
...
...
@@ -178,7 +181,7 @@ TRACE_EVENT(ath10k_wmi_cmd,
);
TRACE_EVENT
(
ath10k_wmi_event
,
TP_PROTO
(
struct
ath10k
*
ar
,
int
id
,
void
*
buf
,
size_t
buf_len
),
TP_PROTO
(
struct
ath10k
*
ar
,
int
id
,
const
void
*
buf
,
size_t
buf_len
),
TP_ARGS
(
ar
,
id
,
buf
,
buf_len
),
...
...
@@ -208,7 +211,7 @@ TRACE_EVENT(ath10k_wmi_event,
);
TRACE_EVENT
(
ath10k_htt_stats
,
TP_PROTO
(
struct
ath10k
*
ar
,
void
*
buf
,
size_t
buf_len
),
TP_PROTO
(
struct
ath10k
*
ar
,
const
void
*
buf
,
size_t
buf_len
),
TP_ARGS
(
ar
,
buf
,
buf_len
),
...
...
@@ -235,7 +238,7 @@ TRACE_EVENT(ath10k_htt_stats,
);
TRACE_EVENT
(
ath10k_wmi_dbglog
,
TP_PROTO
(
struct
ath10k
*
ar
,
void
*
buf
,
size_t
buf_len
),
TP_PROTO
(
struct
ath10k
*
ar
,
const
void
*
buf
,
size_t
buf_len
),
TP_ARGS
(
ar
,
buf
,
buf_len
),
...
...
@@ -262,7 +265,7 @@ TRACE_EVENT(ath10k_wmi_dbglog,
);
TRACE_EVENT
(
ath10k_htt_pktlog
,
TP_PROTO
(
struct
ath10k
*
ar
,
void
*
buf
,
u16
buf_len
),
TP_PROTO
(
struct
ath10k
*
ar
,
const
void
*
buf
,
u16
buf_len
),
TP_ARGS
(
ar
,
buf
,
buf_len
),
...
...
@@ -349,7 +352,7 @@ TRACE_EVENT(ath10k_txrx_tx_unref,
);
DECLARE_EVENT_CLASS
(
ath10k_hdr_event
,
TP_PROTO
(
struct
ath10k
*
ar
,
void
*
data
,
size_t
len
),
TP_PROTO
(
struct
ath10k
*
ar
,
const
void
*
data
,
size_t
len
),
TP_ARGS
(
ar
,
data
,
len
),
...
...
@@ -376,7 +379,7 @@ DECLARE_EVENT_CLASS(ath10k_hdr_event,
);
DECLARE_EVENT_CLASS
(
ath10k_payload_event
,
TP_PROTO
(
struct
ath10k
*
ar
,
void
*
data
,
size_t
len
),
TP_PROTO
(
struct
ath10k
*
ar
,
const
void
*
data
,
size_t
len
),
TP_ARGS
(
ar
,
data
,
len
),
...
...
@@ -404,27 +407,27 @@ DECLARE_EVENT_CLASS(ath10k_payload_event,
);
DEFINE_EVENT
(
ath10k_hdr_event
,
ath10k_tx_hdr
,
TP_PROTO
(
struct
ath10k
*
ar
,
void
*
data
,
size_t
len
),
TP_PROTO
(
struct
ath10k
*
ar
,
const
void
*
data
,
size_t
len
),
TP_ARGS
(
ar
,
data
,
len
)
);
DEFINE_EVENT
(
ath10k_payload_event
,
ath10k_tx_payload
,
TP_PROTO
(
struct
ath10k
*
ar
,
void
*
data
,
size_t
len
),
TP_PROTO
(
struct
ath10k
*
ar
,
const
void
*
data
,
size_t
len
),
TP_ARGS
(
ar
,
data
,
len
)
);
DEFINE_EVENT
(
ath10k_hdr_event
,
ath10k_rx_hdr
,
TP_PROTO
(
struct
ath10k
*
ar
,
void
*
data
,
size_t
len
),
TP_PROTO
(
struct
ath10k
*
ar
,
const
void
*
data
,
size_t
len
),
TP_ARGS
(
ar
,
data
,
len
)
);
DEFINE_EVENT
(
ath10k_payload_event
,
ath10k_rx_payload
,
TP_PROTO
(
struct
ath10k
*
ar
,
void
*
data
,
size_t
len
),
TP_PROTO
(
struct
ath10k
*
ar
,
const
void
*
data
,
size_t
len
),
TP_ARGS
(
ar
,
data
,
len
)
);
TRACE_EVENT
(
ath10k_htt_rx_desc
,
TP_PROTO
(
struct
ath10k
*
ar
,
void
*
data
,
size_t
len
),
TP_PROTO
(
struct
ath10k
*
ar
,
const
void
*
data
,
size_t
len
),
TP_ARGS
(
ar
,
data
,
len
),
...
...
drivers/net/wireless/ath/ath10k/wmi.c
浏览文件 @
cbe1bc23
...
...
@@ -1113,6 +1113,40 @@ static inline u8 get_rate_idx(u32 rate, enum ieee80211_band band)
return
rate_idx
;
}
/* If keys are configured, HW decrypts all frames
* with protected bit set. Mark such frames as decrypted.
*/
static
void
ath10k_wmi_handle_wep_reauth
(
struct
ath10k
*
ar
,
struct
sk_buff
*
skb
,
struct
ieee80211_rx_status
*
status
)
{
struct
ieee80211_hdr
*
hdr
=
(
struct
ieee80211_hdr
*
)
skb
->
data
;
unsigned
int
hdrlen
;
bool
peer_key
;
u8
*
addr
,
keyidx
;
if
(
!
ieee80211_is_auth
(
hdr
->
frame_control
)
||
!
ieee80211_has_protected
(
hdr
->
frame_control
))
return
;
hdrlen
=
ieee80211_hdrlen
(
hdr
->
frame_control
);
if
(
skb
->
len
<
(
hdrlen
+
IEEE80211_WEP_IV_LEN
))
return
;
keyidx
=
skb
->
data
[
hdrlen
+
(
IEEE80211_WEP_IV_LEN
-
1
)]
>>
WEP_KEYID_SHIFT
;
addr
=
ieee80211_get_SA
(
hdr
);
spin_lock_bh
(
&
ar
->
data_lock
);
peer_key
=
ath10k_mac_is_peer_wep_key_set
(
ar
,
addr
,
keyidx
);
spin_unlock_bh
(
&
ar
->
data_lock
);
if
(
peer_key
)
{
ath10k_dbg
(
ar
,
ATH10K_DBG_MAC
,
"mac wep key present for peer %pM
\n
"
,
addr
);
status
->
flag
|=
RX_FLAG_DECRYPTED
;
}
}
static
int
ath10k_wmi_event_mgmt_rx
(
struct
ath10k
*
ar
,
struct
sk_buff
*
skb
)
{
struct
wmi_mgmt_rx_event_v1
*
ev_v1
;
...
...
@@ -1166,8 +1200,11 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
return
0
;
}
if
(
rx_status
&
WMI_RX_STATUS_ERR_CRC
)
status
->
flag
|=
RX_FLAG_FAILED_FCS_CRC
;
if
(
rx_status
&
WMI_RX_STATUS_ERR_CRC
)
{
dev_kfree_skb
(
skb
);
return
0
;
}
if
(
rx_status
&
WMI_RX_STATUS_ERR_MIC
)
status
->
flag
|=
RX_FLAG_MMIC_ERROR
;
...
...
@@ -1200,6 +1237,8 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
hdr
=
(
struct
ieee80211_hdr
*
)
skb
->
data
;
fc
=
le16_to_cpu
(
hdr
->
frame_control
);
ath10k_wmi_handle_wep_reauth
(
ar
,
skb
,
status
);
/* FW delivers WEP Shared Auth frame with Protected Bit set and
* encrypted payload. However in case of PMF it delivers decrypted
* frames with Protected Bit set. */
...
...
@@ -2261,7 +2300,7 @@ static void ath10k_wmi_event_debug_print(struct ath10k *ar,
/* the last byte is always reserved for the null character */
buf
[
i
]
=
'\0'
;
ath10k_dbg
(
ar
,
ATH10K_DBG_WMI
,
"wmi event debug
print '%s'
\n
"
,
buf
);
ath10k_dbg
(
ar
,
ATH10K_DBG_WMI
_PRINT
,
"wmi
print '%s'
\n
"
,
buf
);
}
static
void
ath10k_wmi_event_pdev_qvit
(
struct
ath10k
*
ar
,
struct
sk_buff
*
skb
)
...
...
@@ -2418,6 +2457,7 @@ static int ath10k_wmi_main_pull_svc_rdy_ev(struct sk_buff *skb,
arg
->
eeprom_rd
=
ev
->
hal_reg_capabilities
.
eeprom_rd
;
arg
->
num_mem_reqs
=
ev
->
num_mem_reqs
;
arg
->
service_map
=
ev
->
wmi_service_bitmap
;
arg
->
service_map_len
=
sizeof
(
ev
->
wmi_service_bitmap
);
n
=
min_t
(
size_t
,
__le32_to_cpu
(
arg
->
num_mem_reqs
),
ARRAY_SIZE
(
arg
->
mem_reqs
));
...
...
@@ -2452,6 +2492,7 @@ static int ath10k_wmi_10x_pull_svc_rdy_ev(struct sk_buff *skb,
arg
->
eeprom_rd
=
ev
->
hal_reg_capabilities
.
eeprom_rd
;
arg
->
num_mem_reqs
=
ev
->
num_mem_reqs
;
arg
->
service_map
=
ev
->
wmi_service_bitmap
;
arg
->
service_map_len
=
sizeof
(
ev
->
wmi_service_bitmap
);
n
=
min_t
(
size_t
,
__le32_to_cpu
(
arg
->
num_mem_reqs
),
ARRAY_SIZE
(
arg
->
mem_reqs
));
...
...
@@ -2470,15 +2511,18 @@ static void ath10k_wmi_event_service_ready(struct ath10k *ar,
{
struct
wmi_svc_rdy_ev_arg
arg
=
{};
u32
num_units
,
req_id
,
unit_size
,
num_mem_reqs
,
num_unit_info
,
i
;
DECLARE_BITMAP
(
svc_bmap
,
WMI_SERVICE_MAX
)
=
{};
int
ret
;
memset
(
&
ar
->
wmi
.
svc_map
,
0
,
sizeof
(
ar
->
wmi
.
svc_map
));
if
(
test_bit
(
ATH10K_FW_FEATURE_WMI_10X
,
ar
->
fw_features
))
{
ret
=
ath10k_wmi_10x_pull_svc_rdy_ev
(
skb
,
&
arg
);
wmi_10x_svc_map
(
arg
.
service_map
,
svc_bmap
);
wmi_10x_svc_map
(
arg
.
service_map
,
ar
->
wmi
.
svc_map
,
arg
.
service_map_len
);
}
else
{
ret
=
ath10k_wmi_main_pull_svc_rdy_ev
(
skb
,
&
arg
);
wmi_main_svc_map
(
arg
.
service_map
,
svc_bmap
);
wmi_main_svc_map
(
arg
.
service_map
,
ar
->
wmi
.
svc_map
,
arg
.
service_map_len
);
}
if
(
ret
)
{
...
...
@@ -2500,9 +2544,8 @@ static void ath10k_wmi_event_service_ready(struct ath10k *ar,
ar
->
num_rf_chains
=
__le32_to_cpu
(
arg
.
num_rf_chains
);
ar
->
ath_common
.
regulatory
.
current_rd
=
__le32_to_cpu
(
arg
.
eeprom_rd
);
ath10k_debug_read_service_map
(
ar
,
svc_bmap
,
sizeof
(
svc_bmap
));
ath10k_dbg_dump
(
ar
,
ATH10K_DBG_WMI
,
NULL
,
"wmi svc: "
,
arg
.
service_map
,
sizeof
(
arg
.
service_map
)
);
arg
.
service_map
,
arg
.
service_map_len
);
/* only manually set fw features when not using FW IE format */
if
(
ar
->
fw_api
==
1
&&
ar
->
fw_version_build
>
636
)
...
...
@@ -3142,7 +3185,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
u32
len
,
val
;
config
.
num_vdevs
=
__cpu_to_le32
(
TARGET_NUM_VDEVS
);
config
.
num_peers
=
__cpu_to_le32
(
TARGET_NUM_PEERS
+
TARGET_NUM_VDEVS
);
config
.
num_peers
=
__cpu_to_le32
(
TARGET_NUM_PEERS
);
config
.
num_offload_peers
=
__cpu_to_le32
(
TARGET_NUM_OFFLOAD_PEERS
);
config
.
num_offload_reorder_bufs
=
...
...
drivers/net/wireless/ath/ath10k/wmi.h
浏览文件 @
cbe1bc23
...
...
@@ -222,128 +222,131 @@ static inline char *wmi_service_name(int service_id)
#undef SVCSTR
}
#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id) \
(__le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \
#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \
((svc_id) < (len) && \
__le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \
BIT((svc_id)%(sizeof(u32))))
#define SVCMAP(x, y) \
#define SVCMAP(x, y
, len
) \
do { \
if (WMI_SERVICE_IS_ENABLED((in), (x))) \
if (WMI_SERVICE_IS_ENABLED((in), (x)
, (len)
)) \
__set_bit(y, out); \
} while (0)
static
inline
void
wmi_10x_svc_map
(
const
__le32
*
in
,
unsigned
long
*
out
)
static
inline
void
wmi_10x_svc_map
(
const
__le32
*
in
,
unsigned
long
*
out
,
size_t
len
)
{
SVCMAP
(
WMI_10X_SERVICE_BEACON_OFFLOAD
,
WMI_SERVICE_BEACON_OFFLOAD
);
WMI_SERVICE_BEACON_OFFLOAD
,
len
);
SVCMAP
(
WMI_10X_SERVICE_SCAN_OFFLOAD
,
WMI_SERVICE_SCAN_OFFLOAD
);
WMI_SERVICE_SCAN_OFFLOAD
,
len
);
SVCMAP
(
WMI_10X_SERVICE_ROAM_OFFLOAD
,
WMI_SERVICE_ROAM_OFFLOAD
);
WMI_SERVICE_ROAM_OFFLOAD
,
len
);
SVCMAP
(
WMI_10X_SERVICE_BCN_MISS_OFFLOAD
,
WMI_SERVICE_BCN_MISS_OFFLOAD
);
WMI_SERVICE_BCN_MISS_OFFLOAD
,
len
);
SVCMAP
(
WMI_10X_SERVICE_STA_PWRSAVE
,
WMI_SERVICE_STA_PWRSAVE
);
WMI_SERVICE_STA_PWRSAVE
,
len
);
SVCMAP
(
WMI_10X_SERVICE_STA_ADVANCED_PWRSAVE
,
WMI_SERVICE_STA_ADVANCED_PWRSAVE
);
WMI_SERVICE_STA_ADVANCED_PWRSAVE
,
len
);
SVCMAP
(
WMI_10X_SERVICE_AP_UAPSD
,
WMI_SERVICE_AP_UAPSD
);
WMI_SERVICE_AP_UAPSD
,
len
);
SVCMAP
(
WMI_10X_SERVICE_AP_DFS
,
WMI_SERVICE_AP_DFS
);
WMI_SERVICE_AP_DFS
,
len
);
SVCMAP
(
WMI_10X_SERVICE_11AC
,
WMI_SERVICE_11AC
);
WMI_SERVICE_11AC
,
len
);
SVCMAP
(
WMI_10X_SERVICE_BLOCKACK
,
WMI_SERVICE_BLOCKACK
);
WMI_SERVICE_BLOCKACK
,
len
);
SVCMAP
(
WMI_10X_SERVICE_PHYERR
,
WMI_SERVICE_PHYERR
);
WMI_SERVICE_PHYERR
,
len
);
SVCMAP
(
WMI_10X_SERVICE_BCN_FILTER
,
WMI_SERVICE_BCN_FILTER
);
WMI_SERVICE_BCN_FILTER
,
len
);
SVCMAP
(
WMI_10X_SERVICE_RTT
,
WMI_SERVICE_RTT
);
WMI_SERVICE_RTT
,
len
);
SVCMAP
(
WMI_10X_SERVICE_RATECTRL
,
WMI_SERVICE_RATECTRL
);
WMI_SERVICE_RATECTRL
,
len
);
SVCMAP
(
WMI_10X_SERVICE_WOW
,
WMI_SERVICE_WOW
);
WMI_SERVICE_WOW
,
len
);
SVCMAP
(
WMI_10X_SERVICE_RATECTRL_CACHE
,
WMI_SERVICE_RATECTRL_CACHE
);
WMI_SERVICE_RATECTRL_CACHE
,
len
);
SVCMAP
(
WMI_10X_SERVICE_IRAM_TIDS
,
WMI_SERVICE_IRAM_TIDS
);
WMI_SERVICE_IRAM_TIDS
,
len
);
SVCMAP
(
WMI_10X_SERVICE_BURST
,
WMI_SERVICE_BURST
);
WMI_SERVICE_BURST
,
len
);
SVCMAP
(
WMI_10X_SERVICE_SMART_ANTENNA_SW_SUPPORT
,
WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT
);
WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT
,
len
);
SVCMAP
(
WMI_10X_SERVICE_FORCE_FW_HANG
,
WMI_SERVICE_FORCE_FW_HANG
);
WMI_SERVICE_FORCE_FW_HANG
,
len
);
SVCMAP
(
WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT
,
WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT
);
WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT
,
len
);
}
static
inline
void
wmi_main_svc_map
(
const
__le32
*
in
,
unsigned
long
*
out
)
static
inline
void
wmi_main_svc_map
(
const
__le32
*
in
,
unsigned
long
*
out
,
size_t
len
)
{
SVCMAP
(
WMI_MAIN_SERVICE_BEACON_OFFLOAD
,
WMI_SERVICE_BEACON_OFFLOAD
);
WMI_SERVICE_BEACON_OFFLOAD
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_SCAN_OFFLOAD
,
WMI_SERVICE_SCAN_OFFLOAD
);
WMI_SERVICE_SCAN_OFFLOAD
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_ROAM_OFFLOAD
,
WMI_SERVICE_ROAM_OFFLOAD
);
WMI_SERVICE_ROAM_OFFLOAD
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_BCN_MISS_OFFLOAD
,
WMI_SERVICE_BCN_MISS_OFFLOAD
);
WMI_SERVICE_BCN_MISS_OFFLOAD
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_STA_PWRSAVE
,
WMI_SERVICE_STA_PWRSAVE
);
WMI_SERVICE_STA_PWRSAVE
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_STA_ADVANCED_PWRSAVE
,
WMI_SERVICE_STA_ADVANCED_PWRSAVE
);
WMI_SERVICE_STA_ADVANCED_PWRSAVE
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_AP_UAPSD
,
WMI_SERVICE_AP_UAPSD
);
WMI_SERVICE_AP_UAPSD
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_AP_DFS
,
WMI_SERVICE_AP_DFS
);
WMI_SERVICE_AP_DFS
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_11AC
,
WMI_SERVICE_11AC
);
WMI_SERVICE_11AC
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_BLOCKACK
,
WMI_SERVICE_BLOCKACK
);
WMI_SERVICE_BLOCKACK
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_PHYERR
,
WMI_SERVICE_PHYERR
);
WMI_SERVICE_PHYERR
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_BCN_FILTER
,
WMI_SERVICE_BCN_FILTER
);
WMI_SERVICE_BCN_FILTER
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_RTT
,
WMI_SERVICE_RTT
);
WMI_SERVICE_RTT
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_RATECTRL
,
WMI_SERVICE_RATECTRL
);
WMI_SERVICE_RATECTRL
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_WOW
,
WMI_SERVICE_WOW
);
WMI_SERVICE_WOW
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_RATECTRL_CACHE
,
WMI_SERVICE_RATECTRL_CACHE
);
WMI_SERVICE_RATECTRL_CACHE
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_IRAM_TIDS
,
WMI_SERVICE_IRAM_TIDS
);
WMI_SERVICE_IRAM_TIDS
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_ARPNS_OFFLOAD
,
WMI_SERVICE_ARPNS_OFFLOAD
);
WMI_SERVICE_ARPNS_OFFLOAD
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_NLO
,
WMI_SERVICE_NLO
);
WMI_SERVICE_NLO
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_GTK_OFFLOAD
,
WMI_SERVICE_GTK_OFFLOAD
);
WMI_SERVICE_GTK_OFFLOAD
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_SCAN_SCH
,
WMI_SERVICE_SCAN_SCH
);
WMI_SERVICE_SCAN_SCH
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_CSA_OFFLOAD
,
WMI_SERVICE_CSA_OFFLOAD
);
WMI_SERVICE_CSA_OFFLOAD
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_CHATTER
,
WMI_SERVICE_CHATTER
);
WMI_SERVICE_CHATTER
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_COEX_FREQAVOID
,
WMI_SERVICE_COEX_FREQAVOID
);
WMI_SERVICE_COEX_FREQAVOID
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_PACKET_POWER_SAVE
,
WMI_SERVICE_PACKET_POWER_SAVE
);
WMI_SERVICE_PACKET_POWER_SAVE
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_FORCE_FW_HANG
,
WMI_SERVICE_FORCE_FW_HANG
);
WMI_SERVICE_FORCE_FW_HANG
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_GPIO
,
WMI_SERVICE_GPIO
);
WMI_SERVICE_GPIO
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_STA_DTIM_PS_MODULATED_DTIM
,
WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM
);
WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG
,
WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG
);
WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_STA_UAPSD_VAR_AUTO_TRIG
,
WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG
);
WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_STA_KEEP_ALIVE
,
WMI_SERVICE_STA_KEEP_ALIVE
);
WMI_SERVICE_STA_KEEP_ALIVE
,
len
);
SVCMAP
(
WMI_MAIN_SERVICE_TX_ENCAP
,
WMI_SERVICE_TX_ENCAP
);
WMI_SERVICE_TX_ENCAP
,
len
);
}
#undef SVCMAP
...
...
@@ -1952,6 +1955,11 @@ struct wmi_ssid_list {
#define WLAN_SCAN_PARAMS_MAX_BSSID 4
#define WLAN_SCAN_PARAMS_MAX_IE_LEN 256
/* Values lower than this may be refused by some firmware revisions with a scan
* completion with a timedout reason.
*/
#define WMI_SCAN_CHAN_MIN_TIME_MSEC 40
/* Scan priority numbers must be sequential, starting with 0 */
enum
wmi_scan_priority
{
WMI_SCAN_PRIORITY_VERY_LOW
=
0
,
...
...
@@ -4547,7 +4555,6 @@ struct wmi_dbglog_cfg_cmd {
__le32
config_valid
;
}
__packed
;
#define ATH10K_RTS_MAX 2347
#define ATH10K_FRAGMT_THRESHOLD_MIN 540
#define ATH10K_FRAGMT_THRESHOLD_MAX 2346
...
...
@@ -4572,6 +4579,7 @@ struct wmi_svc_rdy_ev_arg {
__le32
eeprom_rd
;
__le32
num_mem_reqs
;
const
__le32
*
service_map
;
size_t
service_map_len
;
const
struct
wlan_host_mem_req
*
mem_reqs
[
WMI_MAX_MEM_REQS
];
};
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录