Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
42774986
K
Kernel
项目概览
openeuler
/
Kernel
1 年多 前同步成功
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
42774986
编写于
2月 23, 2011
作者:
J
John W. Linville
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'for-linville' of
git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx
上级
9077f218
b622d992
变更
11
隐藏空白更改
内联
并排
Showing
11 changed file
with
478 addition
and
77 deletion
+478
-77
drivers/net/wireless/wl12xx/acx.c
drivers/net/wireless/wl12xx/acx.c
+26
-2
drivers/net/wireless/wl12xx/acx.h
drivers/net/wireless/wl12xx/acx.h
+9
-0
drivers/net/wireless/wl12xx/init.c
drivers/net/wireless/wl12xx/init.c
+1
-1
drivers/net/wireless/wl12xx/main.c
drivers/net/wireless/wl12xx/main.c
+118
-29
drivers/net/wireless/wl12xx/ps.c
drivers/net/wireless/wl12xx/ps.c
+78
-0
drivers/net/wireless/wl12xx/ps.h
drivers/net/wireless/wl12xx/ps.h
+2
-0
drivers/net/wireless/wl12xx/rx.c
drivers/net/wireless/wl12xx/rx.c
+3
-3
drivers/net/wireless/wl12xx/rx.h
drivers/net/wireless/wl12xx/rx.h
+0
-4
drivers/net/wireless/wl12xx/tx.c
drivers/net/wireless/wl12xx/tx.c
+201
-36
drivers/net/wireless/wl12xx/tx.h
drivers/net/wireless/wl12xx/tx.h
+3
-2
drivers/net/wireless/wl12xx/wl12xx.h
drivers/net/wireless/wl12xx/wl12xx.h
+37
-0
未找到文件。
drivers/net/wireless/wl12xx/acx.c
浏览文件 @
42774986
...
...
@@ -1328,10 +1328,9 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
/* get data from A-MPDU parameters field */
acx
->
ampdu_max_length
=
ht_cap
->
ampdu_factor
;
acx
->
ampdu_min_spacing
=
ht_cap
->
ampdu_density
;
memcpy
(
acx
->
mac_address
,
mac_address
,
ETH_ALEN
);
}
memcpy
(
acx
->
mac_address
,
mac_address
,
ETH_ALEN
);
acx
->
ht_capabilites
=
cpu_to_le32
(
ht_capabilites
);
ret
=
wl1271_cmd_configure
(
wl
,
ACX_PEER_HT_CAP
,
acx
,
sizeof
(
*
acx
));
...
...
@@ -1542,3 +1541,28 @@ int wl1271_acx_config_ps(struct wl1271 *wl)
kfree
(
config_ps
);
return
ret
;
}
int
wl1271_acx_set_inconnection_sta
(
struct
wl1271
*
wl
,
u8
*
addr
)
{
struct
wl1271_acx_inconnection_sta
*
acx
=
NULL
;
int
ret
;
wl1271_debug
(
DEBUG_ACX
,
"acx set inconnaction sta %pM"
,
addr
);
acx
=
kzalloc
(
sizeof
(
*
acx
),
GFP_KERNEL
);
if
(
!
acx
)
return
-
ENOMEM
;
memcpy
(
acx
->
addr
,
addr
,
ETH_ALEN
);
ret
=
wl1271_cmd_configure
(
wl
,
ACX_UPDATE_INCONNECTION_STA_LIST
,
acx
,
sizeof
(
*
acx
));
if
(
ret
<
0
)
{
wl1271_warning
(
"acx set inconnaction sta failed: %d"
,
ret
);
goto
out
;
}
out:
kfree
(
acx
);
return
ret
;
}
drivers/net/wireless/wl12xx/acx.h
浏览文件 @
42774986
...
...
@@ -1155,6 +1155,13 @@ struct wl1271_acx_config_ps {
__le32
null_data_rate
;
}
__packed
;
struct
wl1271_acx_inconnection_sta
{
struct
acx_header
header
;
u8
addr
[
ETH_ALEN
];
u8
padding1
[
2
];
}
__packed
;
enum
{
ACX_WAKE_UP_CONDITIONS
=
0x0002
,
ACX_MEM_CFG
=
0x0003
,
...
...
@@ -1215,6 +1222,7 @@ enum {
ACX_GEN_FW_CMD
=
0x0070
,
ACX_HOST_IF_CFG_BITMAP
=
0x0071
,
ACX_MAX_TX_FAILURE
=
0x0072
,
ACX_UPDATE_INCONNECTION_STA_LIST
=
0x0073
,
DOT11_RX_MSDU_LIFE_TIME
=
0x1004
,
DOT11_CUR_TX_PWR
=
0x100D
,
DOT11_RX_DOT11_MODE
=
0x1012
,
...
...
@@ -1290,5 +1298,6 @@ int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
int
wl1271_acx_tsf_info
(
struct
wl1271
*
wl
,
u64
*
mactime
);
int
wl1271_acx_max_tx_retry
(
struct
wl1271
*
wl
);
int
wl1271_acx_config_ps
(
struct
wl1271
*
wl
);
int
wl1271_acx_set_inconnection_sta
(
struct
wl1271
*
wl
,
u8
*
addr
);
#endif
/* __WL1271_ACX_H__ */
drivers/net/wireless/wl12xx/init.c
浏览文件 @
42774986
...
...
@@ -483,7 +483,7 @@ static void wl1271_check_ba_support(struct wl1271 *wl)
static
int
wl1271_set_ba_policies
(
struct
wl1271
*
wl
)
{
u8
tid_index
;
u8
ret
=
0
;
int
ret
=
0
;
/* Reset the BA RX indicators */
wl
->
ba_rx_bitmap
=
0
;
...
...
drivers/net/wireless/wl12xx/main.c
浏览文件 @
42774986
...
...
@@ -482,6 +482,10 @@ static int wl1271_plt_init(struct wl1271 *wl)
if
(
ret
<
0
)
goto
out_free_memmap
;
ret
=
wl1271_acx_sta_mem_cfg
(
wl
);
if
(
ret
<
0
)
goto
out_free_memmap
;
/* Default fragmentation threshold */
ret
=
wl1271_acx_frag_threshold
(
wl
,
wl
->
conf
.
tx
.
frag_threshold
);
if
(
ret
<
0
)
...
...
@@ -533,6 +537,57 @@ static int wl1271_plt_init(struct wl1271 *wl)
return
ret
;
}
static
void
wl1271_irq_ps_regulate_link
(
struct
wl1271
*
wl
,
u8
hlid
,
u8
tx_blks
)
{
bool
fw_ps
;
/* only regulate station links */
if
(
hlid
<
WL1271_AP_STA_HLID_START
)
return
;
fw_ps
=
test_bit
(
hlid
,
(
unsigned
long
*
)
&
wl
->
ap_fw_ps_map
);
/*
* Wake up from high level PS if the STA is asleep with too little
* blocks in FW or if the STA is awake.
*/
if
(
!
fw_ps
||
tx_blks
<
WL1271_PS_STA_MAX_BLOCKS
)
wl1271_ps_link_end
(
wl
,
hlid
);
/* Start high-level PS if the STA is asleep with enough blocks in FW */
else
if
(
fw_ps
&&
tx_blks
>=
WL1271_PS_STA_MAX_BLOCKS
)
wl1271_ps_link_start
(
wl
,
hlid
,
true
);
}
static
void
wl1271_irq_update_links_status
(
struct
wl1271
*
wl
,
struct
wl1271_fw_ap_status
*
status
)
{
u32
cur_fw_ps_map
;
u8
hlid
;
cur_fw_ps_map
=
le32_to_cpu
(
status
->
link_ps_bitmap
);
if
(
wl
->
ap_fw_ps_map
!=
cur_fw_ps_map
)
{
wl1271_debug
(
DEBUG_PSM
,
"link ps prev 0x%x cur 0x%x changed 0x%x"
,
wl
->
ap_fw_ps_map
,
cur_fw_ps_map
,
wl
->
ap_fw_ps_map
^
cur_fw_ps_map
);
wl
->
ap_fw_ps_map
=
cur_fw_ps_map
;
}
for
(
hlid
=
WL1271_AP_STA_HLID_START
;
hlid
<
AP_MAX_LINKS
;
hlid
++
)
{
u8
cnt
=
status
->
tx_lnk_free_blks
[
hlid
]
-
wl
->
links
[
hlid
].
prev_freed_blks
;
wl
->
links
[
hlid
].
prev_freed_blks
=
status
->
tx_lnk_free_blks
[
hlid
];
wl
->
links
[
hlid
].
allocated_blks
-=
cnt
;
wl1271_irq_ps_regulate_link
(
wl
,
hlid
,
wl
->
links
[
hlid
].
allocated_blks
);
}
}
static
void
wl1271_fw_status
(
struct
wl1271
*
wl
,
struct
wl1271_fw_full_status
*
full_status
)
{
...
...
@@ -570,6 +625,10 @@ static void wl1271_fw_status(struct wl1271 *wl,
if
(
total
)
clear_bit
(
WL1271_FLAG_FW_TX_BUSY
,
&
wl
->
flags
);
/* for AP update num of allocated TX blocks per link and ps status */
if
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
)
wl1271_irq_update_links_status
(
wl
,
&
full_status
->
ap
);
/* update the host-chipset time offset */
getnstimeofday
(
&
ts
);
wl
->
time_offset
=
(
timespec_to_ns
(
&
ts
)
>>
10
)
-
...
...
@@ -980,14 +1039,32 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
struct
wl1271
*
wl
=
hw
->
priv
;
unsigned
long
flags
;
int
q
;
u8
hlid
=
0
;
spin_lock_irqsave
(
&
wl
->
wl_lock
,
flags
);
wl
->
tx_queue_count
++
;
/*
* The workqueue is slow to process the tx_queue and we need stop
* the queue here, otherwise the queue will get too long.
*/
if
(
wl
->
tx_queue_count
>=
WL1271_TX_QUEUE_HIGH_WATERMARK
)
{
wl1271_debug
(
DEBUG_TX
,
"op_tx: stopping queues"
);
ieee80211_stop_queues
(
wl
->
hw
);
set_bit
(
WL1271_FLAG_TX_QUEUE_STOPPED
,
&
wl
->
flags
);
}
spin_unlock_irqrestore
(
&
wl
->
wl_lock
,
flags
);
/* queue the packet */
q
=
wl1271_tx_get_queue
(
skb_get_queue_mapping
(
skb
));
skb_queue_tail
(
&
wl
->
tx_queue
[
q
],
skb
);
if
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
)
{
hlid
=
wl1271_tx_get_hlid
(
skb
);
wl1271_debug
(
DEBUG_TX
,
"queue skb hlid %d q %d"
,
hlid
,
q
);
skb_queue_tail
(
&
wl
->
links
[
hlid
].
tx_queue
[
q
],
skb
);
}
else
{
skb_queue_tail
(
&
wl
->
tx_queue
[
q
],
skb
);
}
/*
* The chip specific setup must run before the first TX packet -
...
...
@@ -997,19 +1074,6 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
if
(
!
test_bit
(
WL1271_FLAG_FW_TX_BUSY
,
&
wl
->
flags
))
ieee80211_queue_work
(
wl
->
hw
,
&
wl
->
tx_work
);
/*
* The workqueue is slow to process the tx_queue and we need stop
* the queue here, otherwise the queue will get too long.
*/
if
(
wl
->
tx_queue_count
>=
WL1271_TX_QUEUE_HIGH_WATERMARK
)
{
wl1271_debug
(
DEBUG_TX
,
"op_tx: stopping queues"
);
spin_lock_irqsave
(
&
wl
->
wl_lock
,
flags
);
ieee80211_stop_queues
(
wl
->
hw
);
set_bit
(
WL1271_FLAG_TX_QUEUE_STOPPED
,
&
wl
->
flags
);
spin_unlock_irqrestore
(
&
wl
->
wl_lock
,
flags
);
}
return
NETDEV_TX_OK
;
}
...
...
@@ -1221,6 +1285,8 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl)
wl
->
filters
=
0
;
wl1271_free_ap_keys
(
wl
);
memset
(
wl
->
ap_hlid_map
,
0
,
sizeof
(
wl
->
ap_hlid_map
));
wl
->
ap_fw_ps_map
=
0
;
wl
->
ap_ps_map
=
0
;
for
(
i
=
0
;
i
<
NUM_TX_QUEUES
;
i
++
)
wl
->
tx_blocks_freed
[
i
]
=
0
;
...
...
@@ -2218,6 +2284,8 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
u32
sta_rate_set
=
0
;
int
ret
;
struct
ieee80211_sta
*
sta
;
bool
sta_exists
=
false
;
struct
ieee80211_sta_ht_cap
sta_ht_cap
;
if
(
is_ibss
)
{
ret
=
wl1271_bss_beacon_info_changed
(
wl
,
vif
,
bss_conf
,
...
...
@@ -2289,16 +2357,20 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
if
(
sta
->
ht_cap
.
ht_supported
)
sta_rate_set
|=
(
sta
->
ht_cap
.
mcs
.
rx_mask
[
0
]
<<
HW_HT_RATES_OFFSET
);
sta_ht_cap
=
sta
->
ht_cap
;
sta_exists
=
true
;
}
rcu_read_unlock
();
if
(
sta_exists
)
{
/* handle new association with HT and HT information change */
if
((
changed
&
BSS_CHANGED_HT
)
&&
(
bss_conf
->
channel_type
!=
NL80211_CHAN_NO_HT
))
{
ret
=
wl1271_acx_set_ht_capabilities
(
wl
,
&
sta
->
ht_cap
,
ret
=
wl1271_acx_set_ht_capabilities
(
wl
,
&
sta
_
ht_cap
,
true
);
if
(
ret
<
0
)
{
wl1271_warning
(
"Set ht cap true failed %d"
,
ret
);
rcu_read_unlock
();
goto
out
;
}
ret
=
wl1271_acx_set_ht_information
(
wl
,
...
...
@@ -2306,23 +2378,20 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
if
(
ret
<
0
)
{
wl1271_warning
(
"Set ht information failed %d"
,
ret
);
rcu_read_unlock
();
goto
out
;
}
}
/* handle new association without HT and disassociation */
else
if
(
changed
&
BSS_CHANGED_ASSOC
)
{
ret
=
wl1271_acx_set_ht_capabilities
(
wl
,
&
sta
->
ht_cap
,
ret
=
wl1271_acx_set_ht_capabilities
(
wl
,
&
sta
_
ht_cap
,
false
);
if
(
ret
<
0
)
{
wl1271_warning
(
"Set ht cap false failed %d"
,
ret
);
rcu_read_unlock
();
goto
out
;
}
}
}
rcu_read_unlock
();
if
((
changed
&
BSS_CHANGED_ASSOC
))
{
if
(
bss_conf
->
assoc
)
{
...
...
@@ -2612,7 +2681,7 @@ static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
return
0
;
}
static
int
wl1271_allocate_
hlid
(
struct
wl1271
*
wl
,
static
int
wl1271_allocate_
sta
(
struct
wl1271
*
wl
,
struct
ieee80211_sta
*
sta
,
u8
*
hlid
)
{
...
...
@@ -2626,18 +2695,25 @@ static int wl1271_allocate_hlid(struct wl1271 *wl,
}
wl_sta
=
(
struct
wl1271_station
*
)
sta
->
drv_priv
;
__set_bit
(
id
,
wl
->
ap_hlid_map
);
wl_sta
->
hlid
=
WL1271_AP_STA_HLID_START
+
id
;
*
hlid
=
wl_sta
->
hlid
;
memcpy
(
wl
->
links
[
wl_sta
->
hlid
].
addr
,
sta
->
addr
,
ETH_ALEN
);
return
0
;
}
static
void
wl1271_free_
hlid
(
struct
wl1271
*
wl
,
u8
hlid
)
static
void
wl1271_free_
sta
(
struct
wl1271
*
wl
,
u8
hlid
)
{
int
id
=
hlid
-
WL1271_AP_STA_HLID_START
;
if
(
WARN_ON
(
!
test_bit
(
id
,
wl
->
ap_hlid_map
)))
return
;
__clear_bit
(
id
,
wl
->
ap_hlid_map
);
memset
(
wl
->
links
[
hlid
].
addr
,
0
,
ETH_ALEN
);
wl1271_tx_reset_link_queues
(
wl
,
hlid
);
__clear_bit
(
hlid
,
&
wl
->
ap_ps_map
);
__clear_bit
(
hlid
,
(
unsigned
long
*
)
&
wl
->
ap_fw_ps_map
);
}
static
int
wl1271_op_sta_add
(
struct
ieee80211_hw
*
hw
,
...
...
@@ -2658,13 +2734,13 @@ static int wl1271_op_sta_add(struct ieee80211_hw *hw,
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 add sta %d"
,
(
int
)
sta
->
aid
);
ret
=
wl1271_allocate_
hlid
(
wl
,
sta
,
&
hlid
);
ret
=
wl1271_allocate_
sta
(
wl
,
sta
,
&
hlid
);
if
(
ret
<
0
)
goto
out
;
ret
=
wl1271_ps_elp_wakeup
(
wl
,
false
);
if
(
ret
<
0
)
goto
out
;
goto
out
_free_sta
;
ret
=
wl1271_cmd_add_sta
(
wl
,
sta
,
hlid
);
if
(
ret
<
0
)
...
...
@@ -2673,6 +2749,10 @@ static int wl1271_op_sta_add(struct ieee80211_hw *hw,
out_sleep:
wl1271_ps_elp_sleep
(
wl
);
out_free_sta:
if
(
ret
<
0
)
wl1271_free_sta
(
wl
,
hlid
);
out:
mutex_unlock
(
&
wl
->
mutex
);
return
ret
;
...
...
@@ -2709,7 +2789,7 @@ static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
if
(
ret
<
0
)
goto
out_sleep
;
wl1271_free_
hlid
(
wl
,
wl_sta
->
hlid
);
wl1271_free_
sta
(
wl
,
wl_sta
->
hlid
);
out_sleep:
wl1271_ps_elp_sleep
(
wl
);
...
...
@@ -3212,7 +3292,9 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
IEEE80211_HW_SUPPORTS_UAPSD
|
IEEE80211_HW_HAS_RATE_CONTROL
|
IEEE80211_HW_CONNECTION_MONITOR
|
IEEE80211_HW_SUPPORTS_CQM_RSSI
;
IEEE80211_HW_SUPPORTS_CQM_RSSI
|
IEEE80211_HW_REPORTS_TX_ACK_STATUS
|
IEEE80211_HW_AP_LINK_PS
;
wl
->
hw
->
wiphy
->
cipher_suites
=
cipher_suites
;
wl
->
hw
->
wiphy
->
n_cipher_suites
=
ARRAY_SIZE
(
cipher_suites
);
...
...
@@ -3264,7 +3346,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
struct
ieee80211_hw
*
hw
;
struct
platform_device
*
plat_dev
=
NULL
;
struct
wl1271
*
wl
;
int
i
,
ret
;
int
i
,
j
,
ret
;
unsigned
int
order
;
hw
=
ieee80211_alloc_hw
(
sizeof
(
*
wl
),
&
wl1271_ops
);
...
...
@@ -3292,6 +3374,10 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
for
(
i
=
0
;
i
<
NUM_TX_QUEUES
;
i
++
)
skb_queue_head_init
(
&
wl
->
tx_queue
[
i
]);
for
(
i
=
0
;
i
<
NUM_TX_QUEUES
;
i
++
)
for
(
j
=
0
;
j
<
AP_MAX_LINKS
;
j
++
)
skb_queue_head_init
(
&
wl
->
links
[
j
].
tx_queue
[
i
]);
INIT_DELAYED_WORK
(
&
wl
->
elp_work
,
wl1271_elp_work
);
INIT_DELAYED_WORK
(
&
wl
->
pspoll_work
,
wl1271_pspoll_work
);
INIT_WORK
(
&
wl
->
irq_work
,
wl1271_irq_work
);
...
...
@@ -3317,6 +3403,9 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl
->
bss_type
=
MAX_BSS_TYPE
;
wl
->
set_bss_type
=
MAX_BSS_TYPE
;
wl
->
fw_bss_type
=
MAX_BSS_TYPE
;
wl
->
last_tx_hlid
=
0
;
wl
->
ap_ps_map
=
0
;
wl
->
ap_fw_ps_map
=
0
;
memset
(
wl
->
tx_frames_map
,
0
,
sizeof
(
wl
->
tx_frames_map
));
for
(
i
=
0
;
i
<
ACX_TX_DESCRIPTORS
;
i
++
)
...
...
@@ -3412,5 +3501,5 @@ module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
MODULE_PARM_DESC
(
debug_level
,
"wl12xx debugging level"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_AUTHOR
(
"Luciano Coelho <
luciano.coelho@nokia
.com>"
);
MODULE_AUTHOR
(
"Luciano Coelho <
coelho@ti
.com>"
);
MODULE_AUTHOR
(
"Juuso Oikarinen <juuso.oikarinen@nokia.com>"
);
drivers/net/wireless/wl12xx/ps.c
浏览文件 @
42774986
...
...
@@ -24,6 +24,7 @@
#include "reg.h"
#include "ps.h"
#include "io.h"
#include "tx.h"
#define WL1271_WAKEUP_TIMEOUT 500
...
...
@@ -173,4 +174,81 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
return
ret
;
}
static
void
wl1271_ps_filter_frames
(
struct
wl1271
*
wl
,
u8
hlid
)
{
int
i
,
filtered
=
0
;
struct
sk_buff
*
skb
;
struct
ieee80211_tx_info
*
info
;
unsigned
long
flags
;
/* filter all frames currently the low level queus for this hlid */
for
(
i
=
0
;
i
<
NUM_TX_QUEUES
;
i
++
)
{
while
((
skb
=
skb_dequeue
(
&
wl
->
links
[
hlid
].
tx_queue
[
i
])))
{
info
=
IEEE80211_SKB_CB
(
skb
);
info
->
flags
|=
IEEE80211_TX_STAT_TX_FILTERED
;
info
->
status
.
rates
[
0
].
idx
=
-
1
;
ieee80211_tx_status
(
wl
->
hw
,
skb
);
filtered
++
;
}
}
spin_lock_irqsave
(
&
wl
->
wl_lock
,
flags
);
wl
->
tx_queue_count
-=
filtered
;
spin_unlock_irqrestore
(
&
wl
->
wl_lock
,
flags
);
wl1271_handle_tx_low_watermark
(
wl
);
}
void
wl1271_ps_link_start
(
struct
wl1271
*
wl
,
u8
hlid
,
bool
clean_queues
)
{
struct
ieee80211_sta
*
sta
;
if
(
test_bit
(
hlid
,
&
wl
->
ap_ps_map
))
return
;
wl1271_debug
(
DEBUG_PSM
,
"start mac80211 PSM on hlid %d blks %d "
"clean_queues %d"
,
hlid
,
wl
->
links
[
hlid
].
allocated_blks
,
clean_queues
);
rcu_read_lock
();
sta
=
ieee80211_find_sta
(
wl
->
vif
,
wl
->
links
[
hlid
].
addr
);
if
(
!
sta
)
{
wl1271_error
(
"could not find sta %pM for starting ps"
,
wl
->
links
[
hlid
].
addr
);
rcu_read_unlock
();
return
;
}
ieee80211_sta_ps_transition_ni
(
sta
,
true
);
rcu_read_unlock
();
/* do we want to filter all frames from this link's queues? */
if
(
clean_queues
)
wl1271_ps_filter_frames
(
wl
,
hlid
);
__set_bit
(
hlid
,
&
wl
->
ap_ps_map
);
}
void
wl1271_ps_link_end
(
struct
wl1271
*
wl
,
u8
hlid
)
{
struct
ieee80211_sta
*
sta
;
if
(
!
test_bit
(
hlid
,
&
wl
->
ap_ps_map
))
return
;
wl1271_debug
(
DEBUG_PSM
,
"end mac80211 PSM on hlid %d"
,
hlid
);
__clear_bit
(
hlid
,
&
wl
->
ap_ps_map
);
rcu_read_lock
();
sta
=
ieee80211_find_sta
(
wl
->
vif
,
wl
->
links
[
hlid
].
addr
);
if
(
!
sta
)
{
wl1271_error
(
"could not find sta %pM for ending ps"
,
wl
->
links
[
hlid
].
addr
);
goto
end
;
}
ieee80211_sta_ps_transition_ni
(
sta
,
false
);
end:
rcu_read_unlock
();
}
drivers/net/wireless/wl12xx/ps.h
浏览文件 @
42774986
...
...
@@ -32,5 +32,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
void
wl1271_ps_elp_sleep
(
struct
wl1271
*
wl
);
int
wl1271_ps_elp_wakeup
(
struct
wl1271
*
wl
,
bool
chip_awake
);
void
wl1271_elp_work
(
struct
work_struct
*
work
);
void
wl1271_ps_link_start
(
struct
wl1271
*
wl
,
u8
hlid
,
bool
clean_queues
);
void
wl1271_ps_link_end
(
struct
wl1271
*
wl
,
u8
hlid
);
#endif
/* __WL1271_PS_H__ */
drivers/net/wireless/wl12xx/rx.c
浏览文件 @
42774986
...
...
@@ -92,7 +92,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
{
struct
wl1271_rx_descriptor
*
desc
;
struct
sk_buff
*
skb
;
u16
*
fc
;
struct
ieee80211_hdr
*
hdr
;
u8
*
buf
;
u8
beacon
=
0
;
...
...
@@ -118,8 +118,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
/* now we pull the descriptor out of the buffer */
skb_pull
(
skb
,
sizeof
(
*
desc
));
fc
=
(
u16
*
)
skb
->
data
;
if
(
(
*
fc
&
IEEE80211_FCTL_STYPE
)
==
IEEE80211_STYPE_BEACON
)
hdr
=
(
struct
ieee80211_hdr
*
)
skb
->
data
;
if
(
ieee80211_is_beacon
(
hdr
->
frame_control
)
)
beacon
=
1
;
wl1271_rx_status
(
wl
,
desc
,
IEEE80211_SKB_RXCB
(
skb
),
beacon
);
...
...
drivers/net/wireless/wl12xx/rx.h
浏览文件 @
42774986
...
...
@@ -30,10 +30,6 @@
#define WL1271_RX_MAX_RSSI -30
#define WL1271_RX_MIN_RSSI -95
#define WL1271_RX_ALIGN_TO 4
#define WL1271_RX_ALIGN(len) (((len) + WL1271_RX_ALIGN_TO - 1) & \
~(WL1271_RX_ALIGN_TO - 1))
#define SHORT_PREAMBLE_BIT BIT(0)
#define OFDM_RATE_BIT BIT(6)
#define PBCC_RATE_BIT BIT(7)
...
...
drivers/net/wireless/wl12xx/tx.c
浏览文件 @
42774986
...
...
@@ -70,8 +70,65 @@ static void wl1271_free_tx_id(struct wl1271 *wl, int id)
}
}
static
void
wl1271_tx_ap_update_inconnection_sta
(
struct
wl1271
*
wl
,
struct
sk_buff
*
skb
)
{
struct
ieee80211_hdr
*
hdr
;
/*
* add the station to the known list before transmitting the
* authentication response. this way it won't get de-authed by FW
* when transmitting too soon.
*/
hdr
=
(
struct
ieee80211_hdr
*
)(
skb
->
data
+
sizeof
(
struct
wl1271_tx_hw_descr
));
if
(
ieee80211_is_auth
(
hdr
->
frame_control
))
wl1271_acx_set_inconnection_sta
(
wl
,
hdr
->
addr1
);
}
static
void
wl1271_tx_regulate_link
(
struct
wl1271
*
wl
,
u8
hlid
)
{
bool
fw_ps
;
u8
tx_blks
;
/* only regulate station links */
if
(
hlid
<
WL1271_AP_STA_HLID_START
)
return
;
fw_ps
=
test_bit
(
hlid
,
(
unsigned
long
*
)
&
wl
->
ap_fw_ps_map
);
tx_blks
=
wl
->
links
[
hlid
].
allocated_blks
;
/*
* if in FW PS and there is enough data in FW we can put the link
* into high-level PS and clean out its TX queues.
*/
if
(
fw_ps
&&
tx_blks
>=
WL1271_PS_STA_MAX_BLOCKS
)
wl1271_ps_link_start
(
wl
,
hlid
,
true
);
}
u8
wl1271_tx_get_hlid
(
struct
sk_buff
*
skb
)
{
struct
ieee80211_tx_info
*
control
=
IEEE80211_SKB_CB
(
skb
);
if
(
control
->
control
.
sta
)
{
struct
wl1271_station
*
wl_sta
;
wl_sta
=
(
struct
wl1271_station
*
)
control
->
control
.
sta
->
drv_priv
;
return
wl_sta
->
hlid
;
}
else
{
struct
ieee80211_hdr
*
hdr
;
hdr
=
(
struct
ieee80211_hdr
*
)
skb
->
data
;
if
(
ieee80211_is_mgmt
(
hdr
->
frame_control
))
return
WL1271_AP_GLOBAL_HLID
;
else
return
WL1271_AP_BROADCAST_HLID
;
}
}
static
int
wl1271_tx_allocate
(
struct
wl1271
*
wl
,
struct
sk_buff
*
skb
,
u32
extra
,
u32
buf_offset
)
u32
buf_offset
,
u8
hlid
)
{
struct
wl1271_tx_hw_descr
*
desc
;
u32
total_len
=
skb
->
len
+
sizeof
(
struct
wl1271_tx_hw_descr
)
+
extra
;
...
...
@@ -100,6 +157,9 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
wl
->
tx_blocks_available
-=
total_blocks
;
if
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
)
wl
->
links
[
hlid
].
allocated_blks
+=
total_blocks
;
ret
=
0
;
wl1271_debug
(
DEBUG_TX
,
...
...
@@ -113,7 +173,8 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
}
static
void
wl1271_tx_fill_hdr
(
struct
wl1271
*
wl
,
struct
sk_buff
*
skb
,
u32
extra
,
struct
ieee80211_tx_info
*
control
)
u32
extra
,
struct
ieee80211_tx_info
*
control
,
u8
hlid
)
{
struct
timespec
ts
;
struct
wl1271_tx_hw_descr
*
desc
;
...
...
@@ -149,7 +210,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
desc
->
tid
=
ac
;
if
(
wl
->
bss_type
!=
BSS_TYPE_AP_BSS
)
{
desc
->
aid
=
TX_HW_DEFAULT_AID
;
desc
->
aid
=
hlid
;
/* if the packets are destined for AP (have a STA entry)
send them with AP rate policies, otherwise use default
...
...
@@ -159,25 +220,17 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
else
rate_idx
=
ACX_TX_BASIC_RATE
;
}
else
{
if
(
control
->
control
.
sta
)
{
struct
wl1271_station
*
wl_sta
;
wl_sta
=
(
struct
wl1271_station
*
)
control
->
control
.
sta
->
drv_priv
;
desc
->
hlid
=
wl_sta
->
hlid
;
desc
->
hlid
=
hlid
;
switch
(
hlid
)
{
case
WL1271_AP_GLOBAL_HLID
:
rate_idx
=
ACX_TX_AP_MODE_MGMT_RATE
;
break
;
case
WL1271_AP_BROADCAST_HLID
:
rate_idx
=
ACX_TX_AP_MODE_BCST_RATE
;
break
;
default:
rate_idx
=
ac
;
}
else
{
struct
ieee80211_hdr
*
hdr
;
hdr
=
(
struct
ieee80211_hdr
*
)
(
skb
->
data
+
sizeof
(
*
desc
));
if
(
ieee80211_is_mgmt
(
hdr
->
frame_control
))
{
desc
->
hlid
=
WL1271_AP_GLOBAL_HLID
;
rate_idx
=
ACX_TX_AP_MODE_MGMT_RATE
;
}
else
{
desc
->
hlid
=
WL1271_AP_BROADCAST_HLID
;
rate_idx
=
ACX_TX_AP_MODE_BCST_RATE
;
}
break
;
}
}
...
...
@@ -185,7 +238,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
desc
->
reserved
=
0
;
/* align the length (and store in terms of words) */
pad
=
WL1271_TX_ALIGN
(
skb
->
len
);
pad
=
ALIGN
(
skb
->
len
,
WL1271_TX_ALIGN_TO
);
desc
->
length
=
cpu_to_le16
(
pad
>>
2
);
/* calculate number of padding bytes */
...
...
@@ -208,6 +261,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
u32
extra
=
0
;
int
ret
=
0
;
u32
total_len
;
u8
hlid
;
if
(
!
skb
)
return
-
EINVAL
;
...
...
@@ -234,18 +288,28 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
}
}
ret
=
wl1271_tx_allocate
(
wl
,
skb
,
extra
,
buf_offset
);
if
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
)
hlid
=
wl1271_tx_get_hlid
(
skb
);
else
hlid
=
TX_HW_DEFAULT_AID
;
ret
=
wl1271_tx_allocate
(
wl
,
skb
,
extra
,
buf_offset
,
hlid
);
if
(
ret
<
0
)
return
ret
;
wl1271_tx_fill_hdr
(
wl
,
skb
,
extra
,
info
);
if
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
)
{
wl1271_tx_ap_update_inconnection_sta
(
wl
,
skb
);
wl1271_tx_regulate_link
(
wl
,
hlid
);
}
wl1271_tx_fill_hdr
(
wl
,
skb
,
extra
,
info
,
hlid
);
/*
* The length of each packet is stored in terms of words. Thus, we must
* pad the skb data to make sure its length is aligned.
* The number of padding bytes is computed and set in wl1271_tx_fill_hdr
*/
total_len
=
WL1271_TX_ALIGN
(
skb
->
len
);
total_len
=
ALIGN
(
skb
->
len
,
WL1271_TX_ALIGN_TO
);
memcpy
(
wl
->
aggr_buf
+
buf_offset
,
skb
->
data
,
skb
->
len
);
memset
(
wl
->
aggr_buf
+
buf_offset
+
skb
->
len
,
0
,
total_len
-
skb
->
len
);
...
...
@@ -279,7 +343,7 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
return
enabled_rates
;
}
static
void
handle_tx_low_watermark
(
struct
wl1271
*
wl
)
void
wl1271_
handle_tx_low_watermark
(
struct
wl1271
*
wl
)
{
unsigned
long
flags
;
...
...
@@ -293,7 +357,7 @@ static void handle_tx_low_watermark(struct wl1271 *wl)
}
}
static
struct
sk_buff
*
wl1271_skb_dequeue
(
struct
wl1271
*
wl
)
static
struct
sk_buff
*
wl1271_s
ta_s
kb_dequeue
(
struct
wl1271
*
wl
)
{
struct
sk_buff
*
skb
=
NULL
;
unsigned
long
flags
;
...
...
@@ -319,12 +383,69 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
return
skb
;
}
static
struct
sk_buff
*
wl1271_ap_skb_dequeue
(
struct
wl1271
*
wl
)
{
struct
sk_buff
*
skb
=
NULL
;
unsigned
long
flags
;
int
i
,
h
,
start_hlid
;
/* start from the link after the last one */
start_hlid
=
(
wl
->
last_tx_hlid
+
1
)
%
AP_MAX_LINKS
;
/* dequeue according to AC, round robin on each link */
for
(
i
=
0
;
i
<
AP_MAX_LINKS
;
i
++
)
{
h
=
(
start_hlid
+
i
)
%
AP_MAX_LINKS
;
skb
=
skb_dequeue
(
&
wl
->
links
[
h
].
tx_queue
[
CONF_TX_AC_VO
]);
if
(
skb
)
goto
out
;
skb
=
skb_dequeue
(
&
wl
->
links
[
h
].
tx_queue
[
CONF_TX_AC_VI
]);
if
(
skb
)
goto
out
;
skb
=
skb_dequeue
(
&
wl
->
links
[
h
].
tx_queue
[
CONF_TX_AC_BE
]);
if
(
skb
)
goto
out
;
skb
=
skb_dequeue
(
&
wl
->
links
[
h
].
tx_queue
[
CONF_TX_AC_BK
]);
if
(
skb
)
goto
out
;
}
out:
if
(
skb
)
{
wl
->
last_tx_hlid
=
h
;
spin_lock_irqsave
(
&
wl
->
wl_lock
,
flags
);
wl
->
tx_queue_count
--
;
spin_unlock_irqrestore
(
&
wl
->
wl_lock
,
flags
);
}
else
{
wl
->
last_tx_hlid
=
0
;
}
return
skb
;
}
static
struct
sk_buff
*
wl1271_skb_dequeue
(
struct
wl1271
*
wl
)
{
if
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
)
return
wl1271_ap_skb_dequeue
(
wl
);
return
wl1271_sta_skb_dequeue
(
wl
);
}
static
void
wl1271_skb_queue_head
(
struct
wl1271
*
wl
,
struct
sk_buff
*
skb
)
{
unsigned
long
flags
;
int
q
=
wl1271_tx_get_queue
(
skb_get_queue_mapping
(
skb
));
skb_queue_head
(
&
wl
->
tx_queue
[
q
],
skb
);
if
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
)
{
u8
hlid
=
wl1271_tx_get_hlid
(
skb
);
skb_queue_head
(
&
wl
->
links
[
hlid
].
tx_queue
[
q
],
skb
);
/* make sure we dequeue the same packet next time */
wl
->
last_tx_hlid
=
(
hlid
+
AP_MAX_LINKS
-
1
)
%
AP_MAX_LINKS
;
}
else
{
skb_queue_head
(
&
wl
->
tx_queue
[
q
],
skb
);
}
spin_lock_irqsave
(
&
wl
->
wl_lock
,
flags
);
wl
->
tx_queue_count
++
;
spin_unlock_irqrestore
(
&
wl
->
wl_lock
,
flags
);
...
...
@@ -387,7 +508,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
if
(
sent_packets
)
{
/* interrupt the firmware with the new packets */
wl1271_write32
(
wl
,
WL1271_HOST_WR_ACCESS
,
wl
->
tx_packets_count
);
handle_tx_low_watermark
(
wl
);
wl1271_
handle_tx_low_watermark
(
wl
);
}
out:
...
...
@@ -504,32 +625,76 @@ void wl1271_tx_complete(struct wl1271 *wl)
}
}
void
wl1271_tx_reset_link_queues
(
struct
wl1271
*
wl
,
u8
hlid
)
{
struct
sk_buff
*
skb
;
int
i
,
total
=
0
;
unsigned
long
flags
;
struct
ieee80211_tx_info
*
info
;
for
(
i
=
0
;
i
<
NUM_TX_QUEUES
;
i
++
)
{
while
((
skb
=
skb_dequeue
(
&
wl
->
links
[
hlid
].
tx_queue
[
i
])))
{
wl1271_debug
(
DEBUG_TX
,
"link freeing skb 0x%p"
,
skb
);
info
=
IEEE80211_SKB_CB
(
skb
);
info
->
status
.
rates
[
0
].
idx
=
-
1
;
info
->
status
.
rates
[
0
].
count
=
0
;
ieee80211_tx_status
(
wl
->
hw
,
skb
);
total
++
;
}
}
spin_lock_irqsave
(
&
wl
->
wl_lock
,
flags
);
wl
->
tx_queue_count
-=
total
;
spin_unlock_irqrestore
(
&
wl
->
wl_lock
,
flags
);
wl1271_handle_tx_low_watermark
(
wl
);
}
/* caller must hold wl->mutex */
void
wl1271_tx_reset
(
struct
wl1271
*
wl
)
{
int
i
;
struct
sk_buff
*
skb
;
struct
ieee80211_tx_info
*
info
;
/* TX failure */
for
(
i
=
0
;
i
<
NUM_TX_QUEUES
;
i
++
)
{
while
((
skb
=
skb_dequeue
(
&
wl
->
tx_queue
[
i
])))
{
wl1271_debug
(
DEBUG_TX
,
"freeing skb 0x%p"
,
skb
);
ieee80211_tx_status
(
wl
->
hw
,
skb
);
if
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
)
{
for
(
i
=
0
;
i
<
AP_MAX_LINKS
;
i
++
)
{
wl1271_tx_reset_link_queues
(
wl
,
i
);
wl
->
links
[
i
].
allocated_blks
=
0
;
wl
->
links
[
i
].
prev_freed_blks
=
0
;
}
wl
->
last_tx_hlid
=
0
;
}
else
{
for
(
i
=
0
;
i
<
NUM_TX_QUEUES
;
i
++
)
{
while
((
skb
=
skb_dequeue
(
&
wl
->
tx_queue
[
i
])))
{
wl1271_debug
(
DEBUG_TX
,
"freeing skb 0x%p"
,
skb
);
info
=
IEEE80211_SKB_CB
(
skb
);
info
->
status
.
rates
[
0
].
idx
=
-
1
;
info
->
status
.
rates
[
0
].
count
=
0
;
ieee80211_tx_status
(
wl
->
hw
,
skb
);
}
}
}
wl
->
tx_queue_count
=
0
;
/*
* Make sure the driver is at a consistent state, in case this
* function is called from a context other than interface removal.
*/
handle_tx_low_watermark
(
wl
);
wl1271_
handle_tx_low_watermark
(
wl
);
for
(
i
=
0
;
i
<
ACX_TX_DESCRIPTORS
;
i
++
)
if
(
wl
->
tx_frames
[
i
]
!=
NULL
)
{
skb
=
wl
->
tx_frames
[
i
];
wl1271_free_tx_id
(
wl
,
i
);
wl1271_debug
(
DEBUG_TX
,
"freeing skb 0x%p"
,
skb
);
info
=
IEEE80211_SKB_CB
(
skb
);
info
->
status
.
rates
[
0
].
idx
=
-
1
;
info
->
status
.
rates
[
0
].
count
=
0
;
ieee80211_tx_status
(
wl
->
hw
,
skb
);
}
}
...
...
@@ -544,8 +709,8 @@ void wl1271_tx_flush(struct wl1271 *wl)
while
(
!
time_after
(
jiffies
,
timeout
))
{
mutex_lock
(
&
wl
->
mutex
);
wl1271_debug
(
DEBUG_TX
,
"flushing tx buffer: %d"
,
wl
->
tx_frames_cnt
);
wl1271_debug
(
DEBUG_TX
,
"flushing tx buffer: %d
%d
"
,
wl
->
tx_frames_cnt
,
wl
->
tx_queue_count
);
if
((
wl
->
tx_frames_cnt
==
0
)
&&
(
wl
->
tx_queue_count
==
0
))
{
mutex_unlock
(
&
wl
->
mutex
);
return
;
...
...
drivers/net/wireless/wl12xx/tx.h
浏览文件 @
42774986
...
...
@@ -53,8 +53,6 @@
#define TX_HW_RESULT_QUEUE_LEN_MASK 0xf
#define WL1271_TX_ALIGN_TO 4
#define WL1271_TX_ALIGN(len) (((len) + WL1271_TX_ALIGN_TO - 1) & \
~(WL1271_TX_ALIGN_TO - 1))
#define WL1271_TKIP_IV_SPACE 4
struct
wl1271_tx_hw_descr
{
...
...
@@ -152,5 +150,8 @@ void wl1271_tx_flush(struct wl1271 *wl);
u8
wl1271_rate_to_idx
(
int
rate
,
enum
ieee80211_band
band
);
u32
wl1271_tx_enabled_rates_get
(
struct
wl1271
*
wl
,
u32
rate_set
);
u32
wl1271_tx_min_rate_get
(
struct
wl1271
*
wl
);
u8
wl1271_tx_get_hlid
(
struct
sk_buff
*
skb
);
void
wl1271_tx_reset_link_queues
(
struct
wl1271
*
wl
,
u8
hlid
);
void
wl1271_handle_tx_low_watermark
(
struct
wl1271
*
wl
);
#endif
drivers/net/wireless/wl12xx/wl12xx.h
浏览文件 @
42774986
...
...
@@ -153,6 +153,17 @@ extern u32 wl12xx_debug_level;
#define WL1271_AP_BROADCAST_HLID 1
#define WL1271_AP_STA_HLID_START 2
/*
* When in AP-mode, we allow (at least) this number of mem-blocks
* to be transmitted to FW for a STA in PS-mode. Only when packets are
* present in the FW buffers it will wake the sleeping STA. We want to put
* enough packets for the driver to transmit all of its buffered data before
* the STA goes to sleep again. But we don't want to take too much mem-blocks
* as it might hurt the throughput of active STAs.
* The number of blocks (18) is enough for 2 large packets.
*/
#define WL1271_PS_STA_MAX_BLOCKS (2 * 9)
#define WL1271_AP_BSS_INDEX 0
#define WL1271_AP_DEF_INACTIV_SEC 300
#define WL1271_AP_DEF_BEACON_EXP 20
...
...
@@ -319,6 +330,17 @@ enum wl12xx_flags {
WL1271_FLAG_AP_STARTED
};
struct
wl1271_link
{
/* AP-mode - TX queue per AC in link */
struct
sk_buff_head
tx_queue
[
NUM_TX_QUEUES
];
/* accounting for allocated / available TX blocks in FW */
u8
allocated_blks
;
u8
prev_freed_blks
;
u8
addr
[
ETH_ALEN
];
};
struct
wl1271
{
struct
platform_device
*
plat_dev
;
struct
ieee80211_hw
*
hw
;
...
...
@@ -498,6 +520,21 @@ struct wl1271 {
/* RX BA constraint value */
bool
ba_support
;
u8
ba_rx_bitmap
;
/*
* AP-mode - links indexed by HLID. The global and broadcast links
* are always active.
*/
struct
wl1271_link
links
[
AP_MAX_LINKS
];
/* the hlid of the link where the last transmitted skb came from */
int
last_tx_hlid
;
/* AP-mode - a bitmap of links currently in PS mode according to FW */
u32
ap_fw_ps_map
;
/* AP-mode - a bitmap of links currently in PS mode in mac80211 */
unsigned
long
ap_ps_map
;
};
struct
wl1271_station
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录