Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
cbe1bc23
Commit
cbe1bc23
authored
Dec 01, 2014
by
John W. Linville
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-linville' of
git://github.com/kvalo/ath
parents
992066c8
fe2407a8
Changes
16
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
1257 additions
and
749 deletions
+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
No files found.
drivers/net/wireless/ath/ath10k/core.c
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
];
};
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment