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
Kirill Smelkov
linux
Commits
e441a5ea
Commit
e441a5ea
authored
Jul 08, 2011
by
John W. Linville
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-linville' of
git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx
parents
5f0dd296
f1a46384
Changes
17
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
414 additions
and
144 deletions
+414
-144
drivers/net/wireless/wl12xx/acx.c
drivers/net/wireless/wl12xx/acx.c
+6
-6
drivers/net/wireless/wl12xx/acx.h
drivers/net/wireless/wl12xx/acx.h
+2
-2
drivers/net/wireless/wl12xx/boot.c
drivers/net/wireless/wl12xx/boot.c
+3
-1
drivers/net/wireless/wl12xx/cmd.c
drivers/net/wireless/wl12xx/cmd.c
+1
-5
drivers/net/wireless/wl12xx/conf.h
drivers/net/wireless/wl12xx/conf.h
+9
-1
drivers/net/wireless/wl12xx/debugfs.c
drivers/net/wireless/wl12xx/debugfs.c
+11
-4
drivers/net/wireless/wl12xx/event.c
drivers/net/wireless/wl12xx/event.c
+42
-0
drivers/net/wireless/wl12xx/event.h
drivers/net/wireless/wl12xx/event.h
+11
-1
drivers/net/wireless/wl12xx/init.c
drivers/net/wireless/wl12xx/init.c
+6
-1
drivers/net/wireless/wl12xx/main.c
drivers/net/wireless/wl12xx/main.c
+143
-59
drivers/net/wireless/wl12xx/ps.c
drivers/net/wireless/wl12xx/ps.c
+6
-3
drivers/net/wireless/wl12xx/scan.c
drivers/net/wireless/wl12xx/scan.c
+27
-0
drivers/net/wireless/wl12xx/scan.h
drivers/net/wireless/wl12xx/scan.h
+1
-0
drivers/net/wireless/wl12xx/sdio.c
drivers/net/wireless/wl12xx/sdio.c
+6
-6
drivers/net/wireless/wl12xx/tx.c
drivers/net/wireless/wl12xx/tx.c
+97
-46
drivers/net/wireless/wl12xx/tx.h
drivers/net/wireless/wl12xx/tx.h
+27
-1
drivers/net/wireless/wl12xx/wl12xx.h
drivers/net/wireless/wl12xx/wl12xx.h
+16
-8
No files found.
drivers/net/wireless/wl12xx/acx.c
View file @
e441a5ea
...
...
@@ -90,7 +90,7 @@ int wl1271_acx_tx_power(struct wl1271 *wl, int power)
struct
acx_current_tx_power
*
acx
;
int
ret
;
wl1271_debug
(
DEBUG_ACX
,
"acx dot11_cur_tx_pwr
"
);
wl1271_debug
(
DEBUG_ACX
,
"acx dot11_cur_tx_pwr
%d"
,
power
);
if
(
power
<
0
||
power
>
25
)
return
-
EINVAL
;
...
...
@@ -1624,22 +1624,22 @@ int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable)
return
ret
;
}
int
wl1271_acx_max_tx_retry
(
struct
wl1271
*
wl
)
int
wl1271_acx_
ap_
max_tx_retry
(
struct
wl1271
*
wl
)
{
struct
wl1271_acx_max_tx_retry
*
acx
=
NULL
;
struct
wl1271_acx_
ap_
max_tx_retry
*
acx
=
NULL
;
int
ret
;
wl1271_debug
(
DEBUG_ACX
,
"acx max tx retry"
);
wl1271_debug
(
DEBUG_ACX
,
"acx
ap
max tx retry"
);
acx
=
kzalloc
(
sizeof
(
*
acx
),
GFP_KERNEL
);
if
(
!
acx
)
return
-
ENOMEM
;
acx
->
max_tx_retry
=
cpu_to_le16
(
wl
->
conf
.
tx
.
ap_
max_tx_retries
);
acx
->
max_tx_retry
=
cpu_to_le16
(
wl
->
conf
.
tx
.
max_tx_retries
);
ret
=
wl1271_cmd_configure
(
wl
,
ACX_MAX_TX_FAILURE
,
acx
,
sizeof
(
*
acx
));
if
(
ret
<
0
)
{
wl1271_warning
(
"acx max tx retry failed: %d"
,
ret
);
wl1271_warning
(
"acx
ap
max tx retry failed: %d"
,
ret
);
goto
out
;
}
...
...
drivers/net/wireless/wl12xx/acx.h
View file @
e441a5ea
...
...
@@ -1168,7 +1168,7 @@ struct wl1271_acx_ps_rx_streaming {
u8
timeout
;
}
__packed
;
struct
wl1271_acx_max_tx_retry
{
struct
wl1271_acx_
ap_
max_tx_retry
{
struct
acx_header
header
;
/*
...
...
@@ -1400,7 +1400,7 @@ int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
bool
enable
);
int
wl1271_acx_tsf_info
(
struct
wl1271
*
wl
,
u64
*
mactime
);
int
wl1271_acx_ps_rx_streaming
(
struct
wl1271
*
wl
,
bool
enable
);
int
wl1271_acx_max_tx_retry
(
struct
wl1271
*
wl
);
int
wl1271_acx_
ap_
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
);
int
wl1271_acx_set_ap_beacon_filter
(
struct
wl1271
*
wl
,
bool
enable
);
...
...
drivers/net/wireless/wl12xx/boot.c
View file @
e441a5ea
...
...
@@ -513,7 +513,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
PERIODIC_SCAN_COMPLETE_EVENT_ID
;
if
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
)
wl
->
event_mask
|=
STA_REMOVE_COMPLETE_EVENT_ID
;
wl
->
event_mask
|=
STA_REMOVE_COMPLETE_EVENT_ID
|
INACTIVE_STA_EVENT_ID
|
MAX_TX_RETRY_EVENT_ID
;
else
wl
->
event_mask
|=
DUMMY_PACKET_EVENT_ID
|
BA_SESSION_RX_CONSTRAINT_EVENT_ID
;
...
...
drivers/net/wireless/wl12xx/cmd.c
View file @
e441a5ea
...
...
@@ -400,10 +400,6 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
join
->
ctrl
|=
wl
->
session_counter
<<
WL1271_JOIN_CMD_TX_SESSION_OFFSET
;
/* reset TX security counters */
wl
->
tx_security_last_seq
=
0
;
wl
->
tx_security_seq
=
0
;
wl1271_debug
(
DEBUG_CMD
,
"cmd join: basic_rate_set=0x%x, rate_set=0x%x"
,
join
->
basic_rate_set
,
join
->
supported_rate_set
);
...
...
@@ -1084,7 +1080,7 @@ int wl1271_cmd_start_bss(struct wl1271 *wl)
memcpy
(
cmd
->
bssid
,
bss_conf
->
bssid
,
ETH_ALEN
);
cmd
->
aging_period
=
cpu_to_le16
(
WL1271_AP_DEF_INACTIV_SEC
);
cmd
->
aging_period
=
cpu_to_le16
(
wl
->
conf
.
tx
.
ap_aging_period
);
cmd
->
bss_index
=
WL1271_AP_BSS_INDEX
;
cmd
->
global_hlid
=
WL1271_AP_GLOBAL_HLID
;
cmd
->
broadcast_hlid
=
WL1271_AP_BROADCAST_HLID
;
...
...
drivers/net/wireless/wl12xx/conf.h
View file @
e441a5ea
...
...
@@ -713,8 +713,16 @@ struct conf_tx_settings {
/*
* AP-mode - allow this number of TX retries to a station before an
* event is triggered from FW.
* In AP-mode the hlids of unreachable stations are given in the
* "sta_tx_retry_exceeded" member in the event mailbox.
*/
u16
ap_max_tx_retries
;
u8
max_tx_retries
;
/*
* AP-mode - after this number of seconds a connected station is
* considered inactive.
*/
u16
ap_aging_period
;
/*
* Configuration for TID parameters.
...
...
drivers/net/wireless/wl12xx/debugfs.c
View file @
e441a5ea
...
...
@@ -30,6 +30,7 @@
#include "acx.h"
#include "ps.h"
#include "io.h"
#include "tx.h"
/* ms */
#define WL1271_DEBUGFS_STATS_LIFETIME 1000
...
...
@@ -233,7 +234,7 @@ static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf,
char
buf
[
20
];
int
res
;
queue_len
=
wl
->
tx_queue_count
;
queue_len
=
wl
1271_tx_total_queue_count
(
wl
)
;
res
=
scnprintf
(
buf
,
sizeof
(
buf
),
"%u
\n
"
,
queue_len
);
return
simple_read_from_buffer
(
userbuf
,
count
,
ppos
,
buf
,
res
);
...
...
@@ -338,10 +339,16 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
#define DRIVER_STATE_PRINT_HEX(x) DRIVER_STATE_PRINT(x, "0x%x")
DRIVER_STATE_PRINT_INT
(
tx_blocks_available
);
DRIVER_STATE_PRINT_INT
(
tx_allocated_blocks
);
DRIVER_STATE_PRINT_INT
(
tx_allocated_blocks
[
0
]);
DRIVER_STATE_PRINT_INT
(
tx_allocated_blocks
[
1
]);
DRIVER_STATE_PRINT_INT
(
tx_allocated_blocks
[
2
]);
DRIVER_STATE_PRINT_INT
(
tx_allocated_blocks
[
3
]);
DRIVER_STATE_PRINT_INT
(
tx_frames_cnt
);
DRIVER_STATE_PRINT_LHEX
(
tx_frames_map
[
0
]);
DRIVER_STATE_PRINT_INT
(
tx_queue_count
);
DRIVER_STATE_PRINT_INT
(
tx_queue_count
[
0
]);
DRIVER_STATE_PRINT_INT
(
tx_queue_count
[
1
]);
DRIVER_STATE_PRINT_INT
(
tx_queue_count
[
2
]);
DRIVER_STATE_PRINT_INT
(
tx_queue_count
[
3
]);
DRIVER_STATE_PRINT_INT
(
tx_packets_count
);
DRIVER_STATE_PRINT_INT
(
tx_results_count
);
DRIVER_STATE_PRINT_LHEX
(
flags
);
...
...
@@ -349,7 +356,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
DRIVER_STATE_PRINT_INT
(
tx_blocks_freed
[
1
]);
DRIVER_STATE_PRINT_INT
(
tx_blocks_freed
[
2
]);
DRIVER_STATE_PRINT_INT
(
tx_blocks_freed
[
3
]);
DRIVER_STATE_PRINT_INT
(
tx_security_last_seq
);
DRIVER_STATE_PRINT_INT
(
tx_security_last_seq
_lsb
);
DRIVER_STATE_PRINT_INT
(
rx_counter
);
DRIVER_STATE_PRINT_INT
(
session_counter
);
DRIVER_STATE_PRINT_INT
(
state
);
...
...
drivers/net/wireless/wl12xx/event.c
View file @
e441a5ea
...
...
@@ -214,6 +214,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
u32
vector
;
bool
beacon_loss
=
false
;
bool
is_ap
=
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
);
bool
disconnect_sta
=
false
;
unsigned
long
sta_bitmap
=
0
;
wl1271_event_mbox_dump
(
mbox
);
...
...
@@ -295,6 +297,46 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
wl1271_tx_dummy_packet
(
wl
);
}
/*
* "TX retries exceeded" has a different meaning according to mode.
* In AP mode the offending station is disconnected.
*/
if
((
vector
&
MAX_TX_RETRY_EVENT_ID
)
&&
is_ap
)
{
wl1271_debug
(
DEBUG_EVENT
,
"MAX_TX_RETRY_EVENT_ID"
);
sta_bitmap
|=
le16_to_cpu
(
mbox
->
sta_tx_retry_exceeded
);
disconnect_sta
=
true
;
}
if
((
vector
&
INACTIVE_STA_EVENT_ID
)
&&
is_ap
)
{
wl1271_debug
(
DEBUG_EVENT
,
"INACTIVE_STA_EVENT_ID"
);
sta_bitmap
|=
le16_to_cpu
(
mbox
->
sta_aging_status
);
disconnect_sta
=
true
;
}
if
(
is_ap
&&
disconnect_sta
)
{
u32
num_packets
=
wl
->
conf
.
tx
.
max_tx_retries
;
struct
ieee80211_sta
*
sta
;
const
u8
*
addr
;
int
h
;
for
(
h
=
find_first_bit
(
&
sta_bitmap
,
AP_MAX_LINKS
);
h
<
AP_MAX_LINKS
;
h
=
find_next_bit
(
&
sta_bitmap
,
AP_MAX_LINKS
,
h
+
1
))
{
if
(
!
wl1271_is_active_sta
(
wl
,
h
))
continue
;
addr
=
wl
->
links
[
h
].
addr
;
rcu_read_lock
();
sta
=
ieee80211_find_sta
(
wl
->
vif
,
addr
);
if
(
sta
)
{
wl1271_debug
(
DEBUG_EVENT
,
"remove sta %d"
,
h
);
ieee80211_report_low_ack
(
sta
,
num_packets
);
}
rcu_read_unlock
();
}
}
if
(
wl
->
vif
&&
beacon_loss
)
ieee80211_connection_loss
(
wl
->
vif
);
...
...
drivers/net/wireless/wl12xx/event.h
View file @
e441a5ea
...
...
@@ -58,13 +58,16 @@ enum {
CHANNEL_SWITCH_COMPLETE_EVENT_ID
=
BIT
(
17
),
BSS_LOSE_EVENT_ID
=
BIT
(
18
),
REGAINED_BSS_EVENT_ID
=
BIT
(
19
),
ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID
=
BIT
(
20
),
MAX_TX_RETRY_EVENT_ID
=
BIT
(
20
),
/* STA: dummy paket for dynamic mem blocks */
DUMMY_PACKET_EVENT_ID
=
BIT
(
21
),
/* AP: STA remove complete */
STA_REMOVE_COMPLETE_EVENT_ID
=
BIT
(
21
),
SOFT_GEMINI_SENSE_EVENT_ID
=
BIT
(
22
),
/* STA: SG prediction */
SOFT_GEMINI_PREDICTION_EVENT_ID
=
BIT
(
23
),
/* AP: Inactive STA */
INACTIVE_STA_EVENT_ID
=
BIT
(
23
),
SOFT_GEMINI_AVALANCHE_EVENT_ID
=
BIT
(
24
),
PLT_RX_CALIBRATION_COMPLETE_EVENT_ID
=
BIT
(
25
),
DBG_EVENT_ID
=
BIT
(
26
),
...
...
@@ -119,7 +122,11 @@ struct event_mailbox {
/* AP FW only */
u8
hlid_removed
;
/* a bitmap of hlids for stations that have been inactive too long */
__le16
sta_aging_status
;
/* a bitmap of hlids for stations which didn't respond to TX */
__le16
sta_tx_retry_exceeded
;
/*
...
...
@@ -143,4 +150,7 @@ void wl1271_event_mbox_config(struct wl1271 *wl);
int
wl1271_event_handle
(
struct
wl1271
*
wl
,
u8
mbox
);
void
wl1271_pspoll_work
(
struct
work_struct
*
work
);
/* Functions from main.c */
bool
wl1271_is_active_sta
(
struct
wl1271
*
wl
,
u8
hlid
);
#endif
drivers/net/wireless/wl12xx/init.c
View file @
e441a5ea
...
...
@@ -447,7 +447,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl)
if
(
ret
<
0
)
return
ret
;
ret
=
wl1271_acx_max_tx_retry
(
wl
);
ret
=
wl1271_acx_
ap_
max_tx_retry
(
wl
);
if
(
ret
<
0
)
return
ret
;
...
...
@@ -455,6 +455,11 @@ static int wl1271_ap_hw_init(struct wl1271 *wl)
if
(
ret
<
0
)
return
ret
;
/* initialize Tx power */
ret
=
wl1271_acx_tx_power
(
wl
,
wl
->
power_level
);
if
(
ret
<
0
)
return
ret
;
return
0
;
}
...
...
drivers/net/wireless/wl12xx/main.c
View file @
e441a5ea
This diff is collapsed.
Click to expand it.
drivers/net/wireless/wl12xx/ps.c
View file @
e441a5ea
...
...
@@ -193,24 +193,27 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
static
void
wl1271_ps_filter_frames
(
struct
wl1271
*
wl
,
u8
hlid
)
{
int
i
,
filtered
=
0
;
int
i
;
struct
sk_buff
*
skb
;
struct
ieee80211_tx_info
*
info
;
unsigned
long
flags
;
int
filtered
[
NUM_TX_QUEUES
];
/* filter all frames currently the low level queus for this hlid */
for
(
i
=
0
;
i
<
NUM_TX_QUEUES
;
i
++
)
{
filtered
[
i
]
=
0
;
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_ni
(
wl
->
hw
,
skb
);
filtered
++
;
filtered
[
i
]
++
;
}
}
spin_lock_irqsave
(
&
wl
->
wl_lock
,
flags
);
wl
->
tx_queue_count
-=
filtered
;
for
(
i
=
0
;
i
<
NUM_TX_QUEUES
;
i
++
)
wl
->
tx_queue_count
[
i
]
-=
filtered
[
i
];
spin_unlock_irqrestore
(
&
wl
->
wl_lock
,
flags
);
wl1271_handle_tx_low_watermark
(
wl
);
...
...
drivers/net/wireless/wl12xx/scan.c
View file @
e441a5ea
...
...
@@ -321,6 +321,33 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
return
0
;
}
int
wl1271_scan_stop
(
struct
wl1271
*
wl
)
{
struct
wl1271_cmd_header
*
cmd
=
NULL
;
int
ret
=
0
;
if
(
WARN_ON
(
wl
->
scan
.
state
==
WL1271_SCAN_STATE_IDLE
))
return
-
EINVAL
;
wl1271_debug
(
DEBUG_CMD
,
"cmd scan stop"
);
cmd
=
kzalloc
(
sizeof
(
*
cmd
),
GFP_KERNEL
);
if
(
!
cmd
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
ret
=
wl1271_cmd_send
(
wl
,
CMD_STOP_SCAN
,
cmd
,
sizeof
(
*
cmd
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"cmd stop_scan failed"
);
goto
out
;
}
out:
kfree
(
cmd
);
return
ret
;
}
static
int
wl1271_scan_get_sched_scan_channels
(
struct
wl1271
*
wl
,
struct
cfg80211_sched_scan_request
*
req
,
...
...
drivers/net/wireless/wl12xx/scan.h
View file @
e441a5ea
...
...
@@ -28,6 +28,7 @@
int
wl1271_scan
(
struct
wl1271
*
wl
,
const
u8
*
ssid
,
size_t
ssid_len
,
struct
cfg80211_scan_request
*
req
);
int
wl1271_scan_stop
(
struct
wl1271
*
wl
);
int
wl1271_scan_build_probe_req
(
struct
wl1271
*
wl
,
const
u8
*
ssid
,
size_t
ssid_len
,
const
u8
*
ie
,
size_t
ie_len
,
u8
band
);
...
...
drivers/net/wireless/wl12xx/sdio.c
View file @
e441a5ea
...
...
@@ -166,12 +166,12 @@ static int wl1271_sdio_power_on(struct wl1271 *wl)
ret
=
pm_runtime_get_sync
(
&
func
->
dev
);
if
(
ret
)
goto
out
;
}
/* Runtime PM might be disabled, so power up the card manually */
}
else
{
/* Runtime PM is disabled: power up the card manually */
ret
=
mmc_power_restore_host
(
func
->
card
->
host
);
if
(
ret
<
0
)
goto
out
;
}
sdio_claim_host
(
func
);
sdio_enable_func
(
func
);
...
...
@@ -188,7 +188,7 @@ static int wl1271_sdio_power_off(struct wl1271 *wl)
sdio_disable_func
(
func
);
sdio_release_host
(
func
);
/*
Runtime PM might be disabled, so power off the card manually
*/
/*
Power off the card manually, even if runtime PM is enabled.
*/
ret
=
mmc_power_save_host
(
func
->
card
->
host
);
if
(
ret
<
0
)
return
ret
;
...
...
drivers/net/wireless/wl12xx/tx.c
View file @
e441a5ea
...
...
@@ -168,7 +168,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
u32
total_len
=
skb
->
len
+
sizeof
(
struct
wl1271_tx_hw_descr
)
+
extra
;
u32
len
;
u32
total_blocks
;
int
id
,
ret
=
-
EBUSY
;
int
id
,
ret
=
-
EBUSY
,
ac
;
u32
spare_blocks
;
if
(
unlikely
(
wl
->
quirks
&
WL12XX_QUIRK_USE_2_SPARE_BLOCKS
))
...
...
@@ -206,7 +206,9 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
desc
->
id
=
id
;
wl
->
tx_blocks_available
-=
total_blocks
;
wl
->
tx_allocated_blocks
+=
total_blocks
;
ac
=
wl1271_tx_get_queue
(
skb_get_queue_mapping
(
skb
));
wl
->
tx_allocated_blocks
[
ac
]
+=
total_blocks
;
if
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
)
wl
->
links
[
hlid
].
allocated_blks
+=
total_blocks
;
...
...
@@ -383,6 +385,8 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
if
(
ret
<
0
)
return
ret
;
wl1271_tx_fill_hdr
(
wl
,
skb
,
extra
,
info
,
hlid
);
if
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
)
{
wl1271_tx_ap_update_inconnection_sta
(
wl
,
skb
);
wl1271_tx_regulate_link
(
wl
,
hlid
);
...
...
@@ -390,8 +394,6 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
wl1271_tx_update_filters
(
wl
,
skb
);
}
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
...
...
@@ -442,37 +444,62 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
void
wl1271_handle_tx_low_watermark
(
struct
wl1271
*
wl
)
{
unsigned
long
flags
;
int
i
;
if
(
test_bit
(
WL1271_FLAG_TX_QUEUE_STOPPED
,
&
wl
->
flags
)
&&
wl
->
tx_queue_count
<=
WL1271_TX_QUEUE_LOW_WATERMARK
)
{
for
(
i
=
0
;
i
<
NUM_TX_QUEUES
;
i
++
)
{
if
(
test_bit
(
i
,
&
wl
->
stopped_queues_map
)
&&
wl
->
tx_queue_count
[
i
]
<=
WL1271_TX_QUEUE_LOW_WATERMARK
)
{
/* firmware buffer has space, restart queues */
spin_lock_irqsave
(
&
wl
->
wl_lock
,
flags
);
ieee80211_wake_queues
(
wl
->
hw
);
clear_bit
(
WL1271_FLAG_TX_QUEUE_STOPPED
,
&
wl
->
flags
);
ieee80211_wake_queue
(
wl
->
hw
,
wl1271_tx_get_mac80211_queue
(
i
));
clear_bit
(
i
,
&
wl
->
stopped_queues_map
);
spin_unlock_irqrestore
(
&
wl
->
wl_lock
,
flags
);
}
}
}
static
struct
sk_buff_head
*
wl1271_select_queue
(
struct
wl1271
*
wl
,
struct
sk_buff_head
*
queues
)
{
int
i
,
q
=
-
1
;
u32
min_blks
=
0xffffffff
;
/*
* Find a non-empty ac where:
* 1. There are packets to transmit
* 2. The FW has the least allocated blocks
*/
for
(
i
=
0
;
i
<
NUM_TX_QUEUES
;
i
++
)
if
(
!
skb_queue_empty
(
&
queues
[
i
])
&&
(
wl
->
tx_allocated_blocks
[
i
]
<
min_blks
))
{
q
=
i
;
min_blks
=
wl
->
tx_allocated_blocks
[
q
];
}
if
(
q
==
-
1
)
return
NULL
;
return
&
queues
[
q
];
}
static
struct
sk_buff
*
wl1271_sta_skb_dequeue
(
struct
wl1271
*
wl
)
{
struct
sk_buff
*
skb
=
NULL
;
unsigned
long
flags
;
struct
sk_buff_head
*
queue
;
skb
=
skb_dequeue
(
&
wl
->
tx_queue
[
CONF_TX_AC_VO
]);
if
(
skb
)
goto
out
;
skb
=
skb_dequeue
(
&
wl
->
tx_queue
[
CONF_TX_AC_VI
]);
if
(
skb
)
queue
=
wl1271_select_queue
(
wl
,
wl
->
tx_queue
);
if
(
!
queue
)
goto
out
;
skb
=
skb_dequeue
(
&
wl
->
tx_queue
[
CONF_TX_AC_BE
]);
if
(
skb
)
goto
out
;
skb
=
skb_dequeue
(
&
wl
->
tx_queue
[
CONF_TX_AC_BK
]);
skb
=
skb_dequeue
(
queue
);
out:
if
(
skb
)
{
int
q
=
wl1271_tx_get_queue
(
skb_get_queue_mapping
(
skb
));
spin_lock_irqsave
(
&
wl
->
wl_lock
,
flags
);
wl
->
tx_queue_count
--
;
wl
->
tx_queue_count
[
q
]
--
;
spin_unlock_irqrestore
(
&
wl
->
wl_lock
,
flags
);
}
...
...
@@ -484,6 +511,7 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl)
struct
sk_buff
*
skb
=
NULL
;
unsigned
long
flags
;
int
i
,
h
,
start_hlid
;
struct
sk_buff_head
*
queue
;
/* start from the link after the last one */
start_hlid
=
(
wl
->
last_tx_hlid
+
1
)
%
AP_MAX_LINKS
;
...
...
@@ -492,25 +520,25 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl)
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
]
);
/* only consider connected stations */
if
(
h
>=
WL1271_AP_STA_HLID_START
&&
!
test_bit
(
h
-
WL1271_AP_STA_HLID_START
,
wl
->
ap_hlid_map
))
continue
;
queue
=
wl1271_select_queue
(
wl
,
wl
->
links
[
h
].
tx_queue
)
;
if
(
!
queue
)
continue
;
skb
=
skb_dequeue
(
queue
);
if
(
skb
)
goto
out
;
break
;
}
out:
if
(
skb
)
{
int
q
=
wl1271_tx_get_queue
(
skb_get_queue_mapping
(
skb
));
wl
->
last_tx_hlid
=
h
;
spin_lock_irqsave
(
&
wl
->
wl_lock
,
flags
);
wl
->
tx_queue_count
--
;
wl
->
tx_queue_count
[
q
]
--
;
spin_unlock_irqrestore
(
&
wl
->
wl_lock
,
flags
);
}
else
{
wl
->
last_tx_hlid
=
0
;
...
...
@@ -531,9 +559,12 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
if
(
!
skb
&&
test_and_clear_bit
(
WL1271_FLAG_DUMMY_PACKET_PENDING
,
&
wl
->
flags
))
{
int
q
;
skb
=
wl
->
dummy_packet
;
q
=
wl1271_tx_get_queue
(
skb_get_queue_mapping
(
skb
));
spin_lock_irqsave
(
&
wl
->
wl_lock
,
flags
);
wl
->
tx_queue_count
--
;
wl
->
tx_queue_count
[
q
]
--
;
spin_unlock_irqrestore
(
&
wl
->
wl_lock
,
flags
);
}
...
...
@@ -558,7 +589,7 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
}
spin_lock_irqsave
(
&
wl
->
wl_lock
,
flags
);
wl
->
tx_queue_count
++
;
wl
->
tx_queue_count
[
q
]
++
;
spin_unlock_irqrestore
(
&
wl
->
wl_lock
,
flags
);
}
...
...
@@ -704,10 +735,24 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
wl
->
stats
.
retry_count
+=
result
->
ack_failures
;
/* update security sequence number */
wl
->
tx_security_seq
+=
(
result
->
lsb_security_sequence_number
-
wl
->
tx_security_last_seq
);
wl
->
tx_security_last_seq
=
result
->
lsb_security_sequence_number
;
/*
* update sequence number only when relevant, i.e. only in
* sessions of TKIP, AES and GEM (not in open or WEP sessions)
*/
if
(
info
->
control
.
hw_key
&&
(
info
->
control
.
hw_key
->
cipher
==
WLAN_CIPHER_SUITE_TKIP
||
info
->
control
.
hw_key
->
cipher
==
WLAN_CIPHER_SUITE_CCMP
||
info
->
control
.
hw_key
->
cipher
==
WL1271_CIPHER_SUITE_GEM
))
{
u8
fw_lsb
=
result
->
tx_security_sequence_number_lsb
;
u8
cur_lsb
=
wl
->
tx_security_last_seq_lsb
;
/*
* update security sequence number, taking care of potential
* wrap-around
*/
wl
->
tx_security_seq
+=
(
fw_lsb
-
cur_lsb
+
256
)
%
256
;
wl
->
tx_security_last_seq_lsb
=
fw_lsb
;
}
/* remove private header from packet */
skb_pull
(
skb
,
sizeof
(
struct
wl1271_tx_hw_descr
));
...
...
@@ -772,23 +817,26 @@ 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
;
int
i
;
unsigned
long
flags
;
struct
ieee80211_tx_info
*
info
;
int
total
[
NUM_TX_QUEUES
];
for
(
i
=
0
;
i
<
NUM_TX_QUEUES
;
i
++
)
{
total
[
i
]
=
0
;
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_ni
(
wl
->
hw
,
skb
);
total
++
;
total
[
i
]
++
;
}
}
spin_lock_irqsave
(
&
wl
->
wl_lock
,
flags
);
wl
->
tx_queue_count
-=
total
;
for
(
i
=
0
;
i
<
NUM_TX_QUEUES
;
i
++
)
wl
->
tx_queue_count
[
i
]
-=
total
[
i
];
spin_unlock_irqrestore
(
&
wl
->
wl_lock
,
flags
);
wl1271_handle_tx_low_watermark
(
wl
);
...
...
@@ -823,10 +871,11 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
ieee80211_tx_status_ni
(
wl
->
hw
,
skb
);
}
}
wl
->
tx_queue_count
[
i
]
=
0
;
}
}
wl
->
tx_queue_count
=
0
;
wl
->
stopped_queues_map
=
0
;
/*
* Make sure the driver is at a consistent state, in case this
...
...
@@ -879,8 +928,10 @@ void wl1271_tx_flush(struct wl1271 *wl)
while
(
!
time_after
(
jiffies
,
timeout
))
{
mutex_lock
(
&
wl
->
mutex
);
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
))
{
wl
->
tx_frames_cnt
,
wl1271_tx_total_queue_count
(
wl
));
if
((
wl
->
tx_frames_cnt
==
0
)
&&
(
wl1271_tx_total_queue_count
(
wl
)
==
0
))
{
mutex_unlock
(
&
wl
->
mutex
);
return
;
}
...
...
drivers/net/wireless/wl12xx/tx.h
View file @
e441a5ea
...
...
@@ -150,7 +150,7 @@ struct wl1271_tx_hw_res_descr {
(from 1st EDCA AIFS counter until TX Complete). */
__le32
medium_delay
;
/* LS-byte of last TKIP seq-num (saved per AC for recovery). */
u8
lsb_security_sequence_number
;
u8
tx_security_sequence_number_lsb
;
/* Retry count - number of transmissions without successful ACK.*/
u8
ack_failures
;
/* The rate that succeeded getting ACK
...
...
@@ -182,6 +182,32 @@ static inline int wl1271_tx_get_queue(int queue)
}
}
static
inline
int
wl1271_tx_get_mac80211_queue
(
int
queue
)
{
switch
(
queue
)
{
case
CONF_TX_AC_VO
:
return
0
;
case
CONF_TX_AC_VI
:
return
1
;
case
CONF_TX_AC_BE
:
return
2
;
case
CONF_TX_AC_BK
:
return
3
;
default:
return
2
;
}
}
static
inline
int
wl1271_tx_total_queue_count
(
struct
wl1271
*
wl
)
{
int
i
,
count
=
0
;
for
(
i
=
0
;
i
<
NUM_TX_QUEUES
;
i
++
)
count
+=
wl
->
tx_queue_count
[
i
];
return
count
;
}
void
wl1271_tx_work
(
struct
work_struct
*
work
);
void
wl1271_tx_work_locked
(
struct
wl1271
*
wl
);
void
wl1271_tx_complete
(
struct
wl1271
*
wl
);
...
...
drivers/net/wireless/wl12xx/wl12xx.h
View file @
e441a5ea
...
...
@@ -144,6 +144,7 @@ extern u32 wl12xx_debug_level;
#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
#define WL1271_TX_SQN_POST_RECOVERY_PADDING 0xff
#define WL1271_CIPHER_SUITE_GEM 0x00147201
...
...
@@ -172,7 +173,6 @@ extern u32 wl12xx_debug_level;
#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
#define ACX_TX_DESCRIPTORS 32
...
...
@@ -424,7 +424,7 @@ struct wl1271 {
/* Accounting for allocated / available TX blocks on HW */
u32
tx_blocks_freed
[
NUM_TX_QUEUES
];
u32
tx_blocks_available
;
u32
tx_allocated_blocks
;
u32
tx_allocated_blocks
[
NUM_TX_QUEUES
]
;
u32
tx_results_count
;
/* Transmitted TX packets counter for chipset interface */
...
...
@@ -438,7 +438,8 @@ struct wl1271 {
/* Frames scheduled for transmission, not handled yet */
struct
sk_buff_head
tx_queue
[
NUM_TX_QUEUES
];
int
tx_queue_count
;
int
tx_queue_count
[
NUM_TX_QUEUES
];
long
stopped_queues_map
;
/* Frames received, not handled yet by mac80211 */
struct
sk_buff_head
deferred_rx_queue
;
...
...
@@ -454,9 +455,16 @@ struct wl1271 {
struct
sk_buff
*
tx_frames
[
ACX_TX_DESCRIPTORS
];
int
tx_frames_cnt
;
/* Security sequence number counters */
u8
tx_security_last_seq
;
s64
tx_security_seq
;
/*
* Security sequence number
* bits 0-15: lower 16 bits part of sequence number
* bits 16-47: higher 32 bits part of sequence number
* bits 48-63: not in use
*/
u64
tx_security_seq
;
/* 8 bits of the last sequence number in use */
u8
tx_security_last_seq_lsb
;
/* FW Rx counter */
u32
rx_counter
;
...
...
@@ -632,8 +640,8 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen);
#define WL1271_DEFAULT_POWER_LEVEL 0
#define WL1271_TX_QUEUE_LOW_WATERMARK
10
#define WL1271_TX_QUEUE_HIGH_WATERMARK 25
#define WL1271_TX_QUEUE_LOW_WATERMARK
32
#define WL1271_TX_QUEUE_HIGH_WATERMARK 25
6
#define WL1271_DEFERRED_QUEUE_LIMIT 64
...
...
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