2009-08-06 16:25:28 +03:00
/*
* This file is part of wl1271
*
* Copyright ( C ) 2009 Nokia Corporation
*
* Contact : Luciano Coelho < luciano . coelho @ nokia . com >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA
* 02110 - 1301 USA
*
*/
# include <linux/kernel.h>
# include <linux/module.h>
2010-10-16 20:27:53 +02:00
# include <linux/etherdevice.h>
2009-08-06 16:25:28 +03:00
2010-11-08 11:20:10 +00:00
# include "wl12xx.h"
2011-10-07 11:02:42 +03:00
# include "debug.h"
2010-11-08 11:20:10 +00:00
# include "io.h"
# include "reg.h"
# include "ps.h"
# include "tx.h"
2011-08-25 12:43:13 +03:00
# include "event.h"
2009-08-06 16:25:28 +03:00
2011-10-05 11:55:45 +02:00
static int wl1271_set_default_wep_key ( struct wl1271 * wl ,
struct wl12xx_vif * wlvif , u8 id )
2010-10-16 21:39:06 +02:00
{
int ret ;
2011-10-05 11:55:45 +02:00
bool is_ap = ( wlvif - > bss_type = = BSS_TYPE_AP_BSS ) ;
2010-10-16 21:39:06 +02:00
if ( is_ap )
2011-08-14 13:17:07 +03:00
ret = wl12xx_cmd_set_default_wep_key ( wl , id ,
2011-10-05 11:55:54 +02:00
wlvif - > ap . bcast_hlid ) ;
2010-10-16 21:39:06 +02:00
else
2011-10-05 11:55:53 +02:00
ret = wl12xx_cmd_set_default_wep_key ( wl , id , wlvif - > sta . hlid ) ;
2010-10-16 21:39:06 +02:00
if ( ret < 0 )
return ret ;
wl1271_debug ( DEBUG_CRYPT , " default wep key idx: %d " , ( int ) id ) ;
return 0 ;
}
2010-10-12 16:20:06 +02:00
static int wl1271_alloc_tx_id ( struct wl1271 * wl , struct sk_buff * skb )
2009-08-06 16:25:28 +03:00
{
2010-10-12 16:20:06 +02:00
int id ;
id = find_first_zero_bit ( wl - > tx_frames_map , ACX_TX_DESCRIPTORS ) ;
if ( id > = ACX_TX_DESCRIPTORS )
return - EBUSY ;
__set_bit ( id , wl - > tx_frames_map ) ;
wl - > tx_frames [ id ] = skb ;
wl - > tx_frames_cnt + + ;
return id ;
}
2009-08-06 16:25:28 +03:00
2010-10-12 16:20:06 +02:00
static void wl1271_free_tx_id ( struct wl1271 * wl , int id )
{
if ( __test_and_clear_bit ( id , wl - > tx_frames_map ) ) {
2011-04-18 16:44:11 +03:00
if ( unlikely ( wl - > tx_frames_cnt = = ACX_TX_DESCRIPTORS ) )
clear_bit ( WL1271_FLAG_FW_TX_BUSY , & wl - > flags ) ;
2010-10-12 16:20:06 +02:00
wl - > tx_frames [ id ] = NULL ;
wl - > tx_frames_cnt - - ;
}
2009-08-06 16:25:28 +03:00
}
2011-02-23 00:22:25 +02:00
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 ) ;
}
2011-10-05 11:56:05 +02:00
static void wl1271_tx_regulate_link ( struct wl1271 * wl ,
struct wl12xx_vif * wlvif ,
u8 hlid )
2011-02-23 00:22:31 +02:00
{
2011-08-25 12:43:15 +03:00
bool fw_ps , single_sta ;
2011-08-14 13:17:35 +03:00
u8 tx_pkts ;
2011-02-23 00:22:31 +02:00
2011-10-05 11:56:05 +02:00
if ( WARN_ON ( ! test_bit ( hlid , wlvif - > links_map ) ) )
2011-02-23 00:22:31 +02:00
return ;
fw_ps = test_bit ( hlid , ( unsigned long * ) & wl - > ap_fw_ps_map ) ;
2011-08-14 13:17:35 +03:00
tx_pkts = wl - > links [ hlid ] . allocated_pkts ;
2011-08-25 12:43:15 +03:00
single_sta = ( wl - > active_sta_count = = 1 ) ;
2011-02-23 00:22:31 +02:00
/*
* 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 .
2011-08-25 12:43:15 +03:00
* Make an exception if this is the only connected station . In this
* case FW - memory congestion is not a problem .
2011-02-23 00:22:31 +02:00
*/
2011-08-25 12:43:15 +03:00
if ( ! single_sta & & fw_ps & & tx_pkts > = WL1271_PS_STA_MAX_PACKETS )
2011-10-10 10:13:13 +02:00
wl12xx_ps_link_start ( wl , wlvif , hlid , true ) ;
2011-02-23 00:22:31 +02:00
}
2011-08-25 12:43:12 +03:00
bool wl12xx_is_dummy_packet ( struct wl1271 * wl , struct sk_buff * skb )
2011-08-14 13:17:15 +03:00
{
return wl - > dummy_packet = = skb ;
}
2011-10-05 11:55:54 +02:00
u8 wl12xx_tx_get_hlid_ap ( struct wl1271 * wl , struct wl12xx_vif * wlvif ,
struct sk_buff * skb )
2011-02-23 00:22:26 +02:00
{
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 ;
2011-10-10 10:13:02 +02:00
if ( ! test_bit ( WLVIF_FLAG_AP_STARTED , & wlvif - > flags ) )
2011-08-14 13:17:15 +03:00
return wl - > system_hlid ;
2011-02-23 00:22:26 +02:00
hdr = ( struct ieee80211_hdr * ) skb - > data ;
if ( ieee80211_is_mgmt ( hdr - > frame_control ) )
2011-10-05 11:55:54 +02:00
return wlvif - > ap . global_hlid ;
2011-02-23 00:22:26 +02:00
else
2011-10-05 11:55:54 +02:00
return wlvif - > ap . bcast_hlid ;
2011-02-23 00:22:26 +02:00
}
}
2011-10-10 10:12:51 +02:00
u8 wl12xx_tx_get_hlid ( struct wl1271 * wl , struct wl12xx_vif * wlvif ,
struct sk_buff * skb )
2011-08-14 13:17:15 +03:00
{
2011-09-15 16:05:47 +03:00
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) skb - > data ;
2011-10-11 13:52:25 +02:00
if ( ! wlvif | | wl12xx_is_dummy_packet ( wl , skb ) )
2011-08-14 13:17:15 +03:00
return wl - > system_hlid ;
2011-10-05 11:55:45 +02:00
if ( wlvif - > bss_type = = BSS_TYPE_AP_BSS )
2011-10-05 11:55:54 +02:00
return wl12xx_tx_get_hlid_ap ( wl , wlvif , skb ) ;
2011-08-14 13:17:15 +03:00
2011-10-10 10:13:00 +02:00
if ( ( test_bit ( WLVIF_FLAG_STA_ASSOCIATED , & wlvif - > flags ) | |
2011-10-10 10:13:01 +02:00
test_bit ( WLVIF_FLAG_IBSS_JOINED , & wlvif - > flags ) ) & &
2011-09-15 16:05:47 +03:00
! ieee80211_is_auth ( hdr - > frame_control ) & &
! ieee80211_is_assoc_req ( hdr - > frame_control ) )
2011-10-05 11:55:53 +02:00
return wlvif - > sta . hlid ;
2011-08-14 13:17:15 +03:00
else
2011-10-05 11:55:57 +02:00
return wlvif - > dev_hlid ;
2011-08-14 13:17:15 +03:00
}
2011-03-31 10:06:58 +02:00
static unsigned int wl12xx_calc_packet_alignment ( struct wl1271 * wl ,
unsigned int packet_length )
{
2011-11-03 08:44:41 +02:00
if ( wl - > quirks & WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT )
2011-03-31 10:06:58 +02:00
return ALIGN ( packet_length , WL1271_TX_ALIGN_TO ) ;
2011-11-03 08:44:41 +02:00
else
return ALIGN ( packet_length , WL12XX_BUS_BLOCK_SIZE ) ;
2011-03-31 10:06:58 +02:00
}
2011-10-10 10:12:55 +02:00
static int wl1271_tx_allocate ( struct wl1271 * wl , struct wl12xx_vif * wlvif ,
2011-10-05 11:55:45 +02:00
struct sk_buff * skb , u32 extra , u32 buf_offset ,
u8 hlid )
2009-08-06 16:25:28 +03:00
{
struct wl1271_tx_hw_descr * desc ;
u32 total_len = skb - > len + sizeof ( struct wl1271_tx_hw_descr ) + extra ;
2011-03-06 16:32:08 +02:00
u32 len ;
2010-02-22 08:38:39 +02:00
u32 total_blocks ;
2011-08-14 13:17:33 +03:00
int id , ret = - EBUSY , ac ;
2011-08-16 19:49:12 +03:00
u32 spare_blocks = wl - > tx_spare_blocks ;
2011-10-10 10:12:55 +02:00
bool is_dummy = false ;
2009-08-06 16:25:28 +03:00
2010-09-30 13:28:28 +02:00
if ( buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE )
2010-10-12 14:49:09 +02:00
return - EAGAIN ;
2010-09-30 13:28:28 +02:00
2009-08-06 16:25:28 +03:00
/* allocate free identifier for the packet */
2010-10-12 16:20:06 +02:00
id = wl1271_alloc_tx_id ( wl , skb ) ;
2009-08-06 16:25:28 +03:00
if ( id < 0 )
return id ;
/* approximate the number of blocks required for this packet
in the firmware */
2011-03-31 10:06:58 +02:00
len = wl12xx_calc_packet_alignment ( wl , total_len ) ;
2011-03-06 16:32:08 +02:00
2011-08-16 19:49:12 +03:00
/* in case of a dummy packet, use default amount of spare mem blocks */
2011-10-10 10:12:55 +02:00
if ( unlikely ( wl12xx_is_dummy_packet ( wl , skb ) ) ) {
is_dummy = true ;
2011-08-16 19:49:12 +03:00
spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT ;
2011-10-10 10:12:55 +02:00
}
2011-08-16 19:49:12 +03:00
2011-03-06 16:32:08 +02:00
total_blocks = ( len + TX_HW_BLOCK_SIZE - 1 ) / TX_HW_BLOCK_SIZE +
2011-03-10 15:24:57 +02:00
spare_blocks ;
2011-03-06 16:32:08 +02:00
2009-08-06 16:25:28 +03:00
if ( total_blocks < = wl - > tx_blocks_available ) {
desc = ( struct wl1271_tx_hw_descr * ) skb_push (
skb , total_len - skb - > len ) ;
2011-03-06 16:32:13 +02:00
/* HW descriptor fields change between wl127x and wl128x */
if ( wl - > chip . id = = CHIP_ID_1283_PG20 ) {
desc - > wl128x_mem . total_mem_blocks = total_blocks ;
} else {
2011-03-10 15:24:57 +02:00
desc - > wl127x_mem . extra_blocks = spare_blocks ;
2011-03-06 16:32:13 +02:00
desc - > wl127x_mem . total_mem_blocks = total_blocks ;
}
2009-08-06 16:25:28 +03:00
desc - > id = id ;
wl - > tx_blocks_available - = total_blocks ;
2011-08-14 13:17:00 +03:00
wl - > tx_allocated_blocks + = total_blocks ;
2009-08-06 16:25:28 +03:00
2012-03-03 22:18:00 +02:00
/* If the FW was empty before, arm the Tx watchdog */
if ( wl - > tx_allocated_blocks = = total_blocks )
wl12xx_rearm_tx_watchdog_locked ( wl ) ;
2011-08-14 13:17:33 +03:00
ac = wl1271_tx_get_queue ( skb_get_queue_mapping ( skb ) ) ;
wl - > tx_allocated_pkts [ ac ] + + ;
2011-08-14 13:17:32 +03:00
2011-10-11 13:52:25 +02:00
if ( ! is_dummy & & wlvif & &
wlvif - > bss_type = = BSS_TYPE_AP_BSS & &
2011-10-05 11:56:05 +02:00
test_bit ( hlid , wlvif - > ap . sta_hlid_map ) )
2011-08-14 13:17:35 +03:00
wl - > links [ hlid ] . allocated_pkts + + ;
2011-02-23 00:22:30 +02:00
2009-08-06 16:25:28 +03:00
ret = 0 ;
wl1271_debug ( DEBUG_TX ,
" tx_allocate: size: %d, blocks: %d, id: %d " ,
total_len , total_blocks , id ) ;
2010-05-24 11:18:17 +03:00
} else {
2010-10-12 16:20:06 +02:00
wl1271_free_tx_id ( wl , id ) ;
2010-05-24 11:18:17 +03:00
}
2009-08-06 16:25:28 +03:00
return ret ;
}
2011-10-10 10:12:55 +02:00
static void wl1271_tx_fill_hdr ( struct wl1271 * wl , struct wl12xx_vif * wlvif ,
2011-10-05 11:55:45 +02:00
struct sk_buff * skb , u32 extra ,
struct ieee80211_tx_info * control , u8 hlid )
2009-08-06 16:25:28 +03:00
{
2010-02-22 08:38:38 +02:00
struct timespec ts ;
2009-08-06 16:25:28 +03:00
struct wl1271_tx_hw_descr * desc ;
2011-03-06 16:32:08 +02:00
int aligned_len , ac , rate_idx ;
2010-02-22 08:38:38 +02:00
s64 hosttime ;
2011-12-08 16:15:58 -05:00
u16 tx_attr = 0 ;
2012-01-31 17:54:42 +02:00
__le16 frame_control ;
struct ieee80211_hdr * hdr ;
u8 * frame_start ;
2011-10-10 10:12:55 +02:00
bool is_dummy ;
2009-08-06 16:25:28 +03:00
desc = ( struct wl1271_tx_hw_descr * ) skb - > data ;
2012-01-31 17:54:42 +02:00
frame_start = ( u8 * ) ( desc + 1 ) ;
hdr = ( struct ieee80211_hdr * ) ( frame_start + extra ) ;
frame_control = hdr - > frame_control ;
2009-08-06 16:25:28 +03:00
2009-10-08 21:56:20 +03:00
/* relocate space for security header */
if ( extra ) {
2012-01-31 17:54:42 +02:00
int hdrlen = ieee80211_hdrlen ( frame_control ) ;
memmove ( frame_start , hdr , hdrlen ) ;
2009-10-08 21:56:20 +03:00
}
2009-08-06 16:25:28 +03:00
/* configure packet life time */
2010-02-22 08:38:38 +02:00
getnstimeofday ( & ts ) ;
hosttime = ( timespec_to_ns ( & ts ) > > 10 ) ;
desc - > start_time = cpu_to_le32 ( hosttime - wl - > time_offset ) ;
2010-10-16 20:27:53 +02:00
2011-10-10 10:12:55 +02:00
is_dummy = wl12xx_is_dummy_packet ( wl , skb ) ;
2011-10-11 13:52:25 +02:00
if ( is_dummy | | ! wlvif | | wlvif - > bss_type ! = BSS_TYPE_AP_BSS )
2010-10-16 20:27:53 +02:00
desc - > life_time = cpu_to_le16 ( TX_HW_MGMT_PKT_LIFETIME_TU ) ;
else
desc - > life_time = cpu_to_le16 ( TX_HW_AP_MODE_PKT_LIFETIME_TU ) ;
2009-08-06 16:25:28 +03:00
2011-03-16 23:03:54 +02:00
/* queue */
2010-02-18 13:25:41 +02:00
ac = wl1271_tx_get_queue ( skb_get_queue_mapping ( skb ) ) ;
2011-03-16 23:03:54 +02:00
desc - > tid = skb - > priority ;
2010-10-16 20:27:53 +02:00
2011-10-10 10:12:55 +02:00
if ( is_dummy ) {
2011-03-06 16:32:14 +02:00
/*
* FW expects the dummy packet to have an invalid session id -
* any session id that is different than the one set in the join
*/
2011-10-05 11:55:55 +02:00
tx_attr = ( SESSION_COUNTER_INVALID < <
2011-03-06 16:32:14 +02:00
TX_HW_ATTR_OFST_SESSION_COUNTER ) &
TX_HW_ATTR_SESSION_COUNTER ;
tx_attr | = TX_HW_ATTR_TX_DUMMY_REQ ;
2011-10-11 13:52:25 +02:00
} else if ( wlvif ) {
2011-03-06 16:32:14 +02:00
/* configure the tx attributes */
2011-10-05 11:55:55 +02:00
tx_attr = wlvif - > session_counter < <
TX_HW_ATTR_OFST_SESSION_COUNTER ;
2011-03-06 16:32:14 +02:00
}
2011-08-14 13:17:11 +03:00
desc - > hlid = hlid ;
2011-10-11 13:52:25 +02:00
if ( is_dummy | | ! wlvif )
2011-10-10 10:12:55 +02:00
rate_idx = 0 ;
else if ( wlvif - > bss_type ! = BSS_TYPE_AP_BSS ) {
2010-10-16 20:27:53 +02:00
/* if the packets are destined for AP (have a STA entry)
send them with AP rate policies , otherwise use default
basic rates */
2011-11-01 09:23:52 +02:00
if ( control - > flags & IEEE80211_TX_CTL_NO_CCK_RATE )
rate_idx = wlvif - > sta . p2p_rate_idx ;
else if ( control - > control . sta )
2011-10-10 10:13:15 +02:00
rate_idx = wlvif - > sta . ap_rate_idx ;
2010-10-16 20:27:53 +02:00
else
2011-10-10 10:13:15 +02:00
rate_idx = wlvif - > sta . basic_rate_idx ;
2010-10-16 20:27:53 +02:00
} else {
2011-10-05 11:55:54 +02:00
if ( hlid = = wlvif - > ap . global_hlid )
2011-10-10 10:13:15 +02:00
rate_idx = wlvif - > ap . mgmt_rate_idx ;
2011-10-05 11:55:54 +02:00
else if ( hlid = = wlvif - > ap . bcast_hlid )
2011-10-10 10:13:15 +02:00
rate_idx = wlvif - > ap . bcast_rate_idx ;
2011-08-14 13:17:21 +03:00
else
2011-10-10 10:13:15 +02:00
rate_idx = wlvif - > ap . ucast_rate_idx [ ac ] ;
2010-10-16 20:27:53 +02:00
}
tx_attr | = rate_idx < < TX_HW_ATTR_OFST_RATE_POLICY ;
2009-08-06 16:25:28 +03:00
desc - > reserved = 0 ;
2011-03-31 10:06:58 +02:00
aligned_len = wl12xx_calc_packet_alignment ( wl , skb - > len ) ;
2011-03-06 16:32:08 +02:00
2011-03-31 10:06:58 +02:00
if ( wl - > chip . id = = CHIP_ID_1283_PG20 ) {
2011-03-06 16:32:08 +02:00
desc - > wl128x_mem . extra_bytes = aligned_len - skb - > len ;
desc - > length = cpu_to_le16 ( aligned_len > > 2 ) ;
2011-03-06 16:32:13 +02:00
wl1271_debug ( DEBUG_TX , " tx_fill_hdr: hlid: %d "
" tx_attr: 0x%x len: %d life: %d mem: %d " ,
desc - > hlid , tx_attr ,
le16_to_cpu ( desc - > length ) ,
le16_to_cpu ( desc - > life_time ) ,
desc - > wl128x_mem . total_mem_blocks ) ;
2011-03-06 16:32:08 +02:00
} else {
int pad ;
2011-03-31 10:06:58 +02:00
/* Store the aligned length in terms of words */
2011-03-06 16:32:08 +02:00
desc - > length = cpu_to_le16 ( aligned_len > > 2 ) ;
/* calculate number of padding bytes */
pad = aligned_len - skb - > len ;
tx_attr | = pad < < TX_HW_ATTR_OFST_LAST_WORD_PAD ;
2009-08-06 16:25:28 +03:00
2011-03-06 16:32:13 +02:00
wl1271_debug ( DEBUG_TX , " tx_fill_hdr: pad: %d hlid: %d "
" tx_attr: 0x%x len: %d life: %d mem: %d " , pad ,
desc - > hlid , tx_attr ,
le16_to_cpu ( desc - > length ) ,
le16_to_cpu ( desc - > life_time ) ,
desc - > wl127x_mem . total_mem_blocks ) ;
2011-03-06 16:32:08 +02:00
}
2009-10-15 10:33:29 +03:00
2012-01-31 17:54:42 +02:00
/* for WEP shared auth - no fw encryption is needed */
if ( ieee80211_is_auth ( frame_control ) & &
ieee80211_has_protected ( frame_control ) )
tx_attr | = TX_HW_ATTR_HOST_ENCRYPT ;
2009-10-15 10:33:29 +03:00
desc - > tx_attr = cpu_to_le16 ( tx_attr ) ;
2009-08-06 16:25:28 +03:00
}
/* caller must hold wl->mutex */
2011-10-10 10:12:55 +02:00
static int wl1271_prepare_tx_frame ( struct wl1271 * wl , struct wl12xx_vif * wlvif ,
struct sk_buff * skb , u32 buf_offset )
2009-08-06 16:25:28 +03:00
{
struct ieee80211_tx_info * info ;
u32 extra = 0 ;
int ret = 0 ;
2010-09-30 13:28:28 +02:00
u32 total_len ;
2011-02-23 00:22:30 +02:00
u8 hlid ;
2011-10-05 11:55:45 +02:00
bool is_dummy ;
2009-08-06 16:25:28 +03:00
if ( ! skb )
return - EINVAL ;
info = IEEE80211_SKB_CB ( skb ) ;
2011-10-05 11:55:45 +02:00
/* TODO: handle dummy packets on multi-vifs */
is_dummy = wl12xx_is_dummy_packet ( wl , skb ) ;
2009-08-06 16:25:28 +03:00
if ( info - > control . hw_key & &
2010-08-10 09:46:38 +02:00
info - > control . hw_key - > cipher = = WLAN_CIPHER_SUITE_TKIP )
2012-02-02 12:22:09 +02:00
extra = WL1271_EXTRA_SPACE_TKIP ;
2009-08-06 16:25:28 +03:00
if ( info - > control . hw_key ) {
2010-10-16 21:39:06 +02:00
bool is_wep ;
u8 idx = info - > control . hw_key - > hw_key_idx ;
u32 cipher = info - > control . hw_key - > cipher ;
is_wep = ( cipher = = WLAN_CIPHER_SUITE_WEP40 ) | |
( cipher = = WLAN_CIPHER_SUITE_WEP104 ) ;
2009-08-06 16:25:28 +03:00
2011-10-05 11:55:59 +02:00
if ( unlikely ( is_wep & & wlvif - > default_key ! = idx ) ) {
2011-10-05 11:55:45 +02:00
ret = wl1271_set_default_wep_key ( wl , wlvif , idx ) ;
2009-08-06 16:25:28 +03:00
if ( ret < 0 )
return ret ;
2011-10-05 11:55:59 +02:00
wlvif - > default_key = idx ;
2009-08-06 16:25:28 +03:00
}
}
2011-10-10 10:12:51 +02:00
hlid = wl12xx_tx_get_hlid ( wl , wlvif , skb ) ;
2011-08-14 13:17:11 +03:00
if ( hlid = = WL12XX_INVALID_LINK_ID ) {
2011-11-08 16:07:52 +02:00
wl1271_error ( " invalid hlid. dropping skb 0x%p " , skb ) ;
2011-08-14 13:17:11 +03:00
return - EINVAL ;
}
2011-02-23 00:22:30 +02:00
2011-10-10 10:12:55 +02:00
ret = wl1271_tx_allocate ( wl , wlvif , skb , extra , buf_offset , hlid ) ;
2009-08-06 16:25:28 +03:00
if ( ret < 0 )
return ret ;
2011-10-10 10:12:55 +02:00
wl1271_tx_fill_hdr ( wl , wlvif , skb , extra , info , hlid ) ;
2011-06-26 10:36:04 +03:00
2011-10-11 13:52:25 +02:00
if ( ! is_dummy & & wlvif & & wlvif - > bss_type = = BSS_TYPE_AP_BSS ) {
2011-02-23 00:22:25 +02:00
wl1271_tx_ap_update_inconnection_sta ( wl , skb ) ;
2011-10-05 11:56:05 +02:00
wl1271_tx_regulate_link ( wl , wlvif , hlid ) ;
2011-02-23 00:22:31 +02:00
}
2011-02-23 00:22:25 +02:00
2010-09-30 13:28:28 +02:00
/*
2011-03-06 16:32:08 +02:00
* 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 .
* In special cases , we want to align to a specific block size
* ( eg . for wl128x with SDIO we align to 256 ) .
2010-09-30 13:28:28 +02:00
*/
2011-03-31 10:06:58 +02:00
total_len = wl12xx_calc_packet_alignment ( wl , skb - > len ) ;
2011-03-06 16:32:08 +02:00
2010-09-30 13:28:28 +02:00
memcpy ( wl - > aggr_buf + buf_offset , skb - > data , skb - > len ) ;
memset ( wl - > aggr_buf + buf_offset + skb - > len , 0 , total_len - skb - > len ) ;
2009-08-06 16:25:28 +03:00
2011-03-31 10:06:59 +02:00
/* Revert side effects in the dummy packet skb, so it can be reused */
2011-10-05 11:55:45 +02:00
if ( is_dummy )
2011-03-31 10:06:59 +02:00
skb_pull ( skb , sizeof ( struct wl1271_tx_hw_descr ) ) ;
2010-09-30 13:28:28 +02:00
return total_len ;
2009-08-06 16:25:28 +03:00
}
2011-09-19 13:51:42 +03:00
u32 wl1271_tx_enabled_rates_get ( struct wl1271 * wl , u32 rate_set ,
enum ieee80211_band rate_band )
2009-12-11 15:41:06 +02:00
{
struct ieee80211_supported_band * band ;
u32 enabled_rates = 0 ;
int bit ;
2011-09-19 13:51:42 +03:00
band = wl - > hw - > wiphy - > bands [ rate_band ] ;
2009-12-11 15:41:06 +02:00
for ( bit = 0 ; bit < band - > n_bitrates ; bit + + ) {
if ( rate_set & 0x1 )
enabled_rates | = band - > bitrates [ bit ] . hw_value ;
rate_set > > = 1 ;
}
2010-10-13 16:09:41 +02:00
/* MCS rates indication are on bits 16 - 23 */
rate_set > > = HW_HT_RATES_OFFSET - band - > n_bitrates ;
for ( bit = 0 ; bit < 8 ; bit + + ) {
if ( rate_set & 0x1 )
enabled_rates | = ( CONF_HW_BIT_RATE_MCS_0 < < bit ) ;
rate_set > > = 1 ;
}
2009-12-11 15:41:06 +02:00
return enabled_rates ;
}
2011-02-23 00:22:26 +02:00
void wl1271_handle_tx_low_watermark ( struct wl1271 * wl )
2010-10-12 14:49:12 +02:00
{
unsigned long flags ;
2011-06-24 13:03:37 +03:00
int i ;
2010-10-12 14:49:12 +02:00
2011-06-24 13:03:37 +03:00
for ( i = 0 ; i < NUM_TX_QUEUES ; i + + ) {
if ( test_bit ( i , & wl - > stopped_queues_map ) & &
2011-07-07 14:25:23 +03:00
wl - > tx_queue_count [ i ] < = WL1271_TX_QUEUE_LOW_WATERMARK ) {
2011-06-24 13:03:37 +03:00
/* firmware buffer has space, restart queues */
spin_lock_irqsave ( & wl - > wl_lock , 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 ) ;
}
2010-10-12 14:49:12 +02:00
}
}
2011-08-14 13:17:33 +03:00
static struct sk_buff_head * wl1271_select_queue ( struct wl1271 * wl ,
struct sk_buff_head * queues )
{
int i , q = - 1 , ac ;
u32 min_pkts = 0xffffffff ;
/*
* Find a non - empty ac where :
* 1. There are packets to transmit
* 2. The FW has the least allocated blocks
*
* We prioritize the ACs according to VO > VI > BE > BK
*/
for ( i = 0 ; i < NUM_TX_QUEUES ; i + + ) {
ac = wl1271_tx_get_queue ( i ) ;
if ( ! skb_queue_empty ( & queues [ ac ] ) & &
( wl - > tx_allocated_pkts [ ac ] < min_pkts ) ) {
q = ac ;
min_pkts = wl - > tx_allocated_pkts [ q ] ;
}
}
if ( q = = - 1 )
return NULL ;
return & queues [ q ] ;
}
2011-10-10 10:12:51 +02:00
static struct sk_buff * wl12xx_lnk_skb_dequeue ( struct wl1271 * wl ,
struct wl1271_link * lnk )
2010-12-13 09:52:37 +02:00
{
2011-10-10 10:12:51 +02:00
struct sk_buff * skb ;
2010-12-13 09:52:37 +02:00
unsigned long flags ;
2011-08-14 13:17:33 +03:00
struct sk_buff_head * queue ;
2010-12-13 09:52:37 +02:00
2011-10-10 10:12:51 +02:00
queue = wl1271_select_queue ( wl , lnk - > tx_queue ) ;
2011-08-14 13:17:33 +03:00
if ( ! queue )
2011-10-10 10:12:51 +02:00
return NULL ;
2011-08-14 13:17:33 +03:00
skb = skb_dequeue ( queue ) ;
2010-12-13 09:52:37 +02:00
if ( skb ) {
2011-07-07 14:25:23 +03:00
int q = wl1271_tx_get_queue ( skb_get_queue_mapping ( skb ) ) ;
2010-12-13 09:52:37 +02:00
spin_lock_irqsave ( & wl - > wl_lock , flags ) ;
2012-02-28 00:41:30 +02:00
WARN_ON_ONCE ( wl - > tx_queue_count [ q ] < = 0 ) ;
2011-07-07 14:25:23 +03:00
wl - > tx_queue_count [ q ] - - ;
2010-12-13 09:52:37 +02:00
spin_unlock_irqrestore ( & wl - > wl_lock , flags ) ;
}
return skb ;
}
2011-10-10 10:12:51 +02:00
static struct sk_buff * wl12xx_vif_skb_dequeue ( struct wl1271 * wl ,
struct wl12xx_vif * wlvif )
2011-02-23 00:22:26 +02:00
{
struct sk_buff * skb = NULL ;
int i , h , start_hlid ;
/* start from the link after the last one */
2011-10-10 10:12:50 +02:00
start_hlid = ( wlvif - > last_tx_hlid + 1 ) % WL12XX_MAX_LINKS ;
2011-02-23 00:22:26 +02:00
/* dequeue according to AC, round robin on each link */
2011-10-05 11:56:05 +02:00
for ( i = 0 ; i < WL12XX_MAX_LINKS ; i + + ) {
h = ( start_hlid + i ) % WL12XX_MAX_LINKS ;
2011-02-23 00:22:26 +02:00
2011-08-14 13:17:33 +03:00
/* only consider connected stations */
2011-10-05 11:56:05 +02:00
if ( ! test_bit ( h , wlvif - > links_map ) )
2011-08-14 13:17:33 +03:00
continue ;
2011-10-10 10:12:51 +02:00
skb = wl12xx_lnk_skb_dequeue ( wl , & wl - > links [ h ] ) ;
if ( ! skb )
2011-08-14 13:17:33 +03:00
continue ;
2011-10-10 10:12:51 +02:00
wlvif - > last_tx_hlid = h ;
break ;
2011-02-23 00:22:26 +02:00
}
2011-10-10 10:12:51 +02:00
if ( ! skb )
2011-10-10 10:12:50 +02:00
wlvif - > last_tx_hlid = 0 ;
2011-02-23 00:22:26 +02:00
return skb ;
}
2011-10-10 10:12:55 +02:00
static struct sk_buff * wl1271_skb_dequeue ( struct wl1271 * wl )
2011-02-23 00:22:26 +02:00
{
2011-03-31 10:06:59 +02:00
unsigned long flags ;
2011-10-10 10:13:17 +02:00
struct wl12xx_vif * wlvif = wl - > last_wlvif ;
2011-03-31 10:06:59 +02:00
struct sk_buff * skb = NULL ;
2012-02-28 00:41:31 +02:00
/* continue from last wlvif (round robin) */
2011-10-10 10:13:17 +02:00
if ( wlvif ) {
wl12xx_for_each_wlvif_continue ( wl , wlvif ) {
skb = wl12xx_vif_skb_dequeue ( wl , wlvif ) ;
if ( skb ) {
wl - > last_wlvif = wlvif ;
break ;
}
}
}
2012-02-28 00:41:31 +02:00
/* dequeue from the system HLID before the restarting wlvif list */
if ( ! skb )
skb = wl12xx_lnk_skb_dequeue ( wl , & wl - > links [ wl - > system_hlid ] ) ;
/* do a new pass over the wlvif list */
2011-10-10 10:13:17 +02:00
if ( ! skb ) {
wl12xx_for_each_wlvif ( wl , wlvif ) {
skb = wl12xx_vif_skb_dequeue ( wl , wlvif ) ;
if ( skb ) {
wl - > last_wlvif = wlvif ;
break ;
}
2012-02-28 00:41:31 +02:00
/*
* No need to continue after last_wlvif . The previous
* pass should have found it .
*/
if ( wlvif = = wl - > last_wlvif )
break ;
2011-10-10 10:13:17 +02:00
}
2011-10-10 10:12:55 +02:00
}
2011-03-31 10:06:59 +02:00
if ( ! skb & &
test_and_clear_bit ( WL1271_FLAG_DUMMY_PACKET_PENDING , & wl - > flags ) ) {
2011-07-07 14:25:23 +03:00
int q ;
2011-03-31 10:06:59 +02:00
skb = wl - > dummy_packet ;
2011-07-07 14:25:23 +03:00
q = wl1271_tx_get_queue ( skb_get_queue_mapping ( skb ) ) ;
2011-03-31 10:06:59 +02:00
spin_lock_irqsave ( & wl - > wl_lock , flags ) ;
2012-02-28 00:41:30 +02:00
WARN_ON_ONCE ( wl - > tx_queue_count [ q ] < = 0 ) ;
2011-07-07 14:25:23 +03:00
wl - > tx_queue_count [ q ] - - ;
2011-03-31 10:06:59 +02:00
spin_unlock_irqrestore ( & wl - > wl_lock , flags ) ;
}
return skb ;
2011-02-23 00:22:26 +02:00
}
2011-10-10 10:12:51 +02:00
static void wl1271_skb_queue_head ( struct wl1271 * wl , struct wl12xx_vif * wlvif ,
2011-10-05 11:55:45 +02:00
struct sk_buff * skb )
2010-12-13 09:52:37 +02:00
{
unsigned long flags ;
int q = wl1271_tx_get_queue ( skb_get_queue_mapping ( skb ) ) ;
2011-03-31 10:06:59 +02:00
if ( wl12xx_is_dummy_packet ( wl , skb ) ) {
set_bit ( WL1271_FLAG_DUMMY_PACKET_PENDING , & wl - > flags ) ;
2011-10-10 10:12:51 +02:00
} else {
u8 hlid = wl12xx_tx_get_hlid ( wl , wlvif , skb ) ;
2011-02-23 00:22:26 +02:00
skb_queue_head ( & wl - > links [ hlid ] . tx_queue [ q ] , skb ) ;
/* make sure we dequeue the same packet next time */
2011-10-10 10:12:50 +02:00
wlvif - > last_tx_hlid = ( hlid + WL12XX_MAX_LINKS - 1 ) %
2011-10-10 10:12:51 +02:00
WL12XX_MAX_LINKS ;
2011-02-23 00:22:26 +02:00
}
2010-12-13 09:52:37 +02:00
spin_lock_irqsave ( & wl - > wl_lock , flags ) ;
2011-07-07 14:25:23 +03:00
wl - > tx_queue_count [ q ] + + ;
2010-12-13 09:52:37 +02:00
spin_unlock_irqrestore ( & wl - > wl_lock , flags ) ;
}
2011-05-15 11:10:29 +03:00
static bool wl1271_tx_is_data_present ( struct sk_buff * skb )
{
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) ( skb - > data ) ;
return ieee80211_is_data_present ( hdr - > frame_control ) ;
}
2011-10-10 10:12:59 +02:00
void wl12xx_rearm_rx_streaming ( struct wl1271 * wl , unsigned long * active_hlids )
{
struct wl12xx_vif * wlvif ;
u32 timeout ;
u8 hlid ;
if ( ! wl - > conf . rx_streaming . interval )
return ;
if ( ! wl - > conf . rx_streaming . always & &
! test_bit ( WL1271_FLAG_SOFT_GEMINI , & wl - > flags ) )
return ;
timeout = wl - > conf . rx_streaming . duration ;
wl12xx_for_each_wlvif_sta ( wl , wlvif ) {
bool found = false ;
for_each_set_bit ( hlid , active_hlids , WL12XX_MAX_LINKS ) {
if ( test_bit ( hlid , wlvif - > links_map ) ) {
found = true ;
break ;
}
}
if ( ! found )
continue ;
/* enable rx streaming */
2011-10-10 10:13:05 +02:00
if ( ! test_bit ( WLVIF_FLAG_RX_STREAMING_STARTED , & wlvif - > flags ) )
2011-10-10 10:12:59 +02:00
ieee80211_queue_work ( wl - > hw ,
& wlvif - > rx_streaming_enable_work ) ;
mod_timer ( & wlvif - > rx_streaming_timer ,
jiffies + msecs_to_jiffies ( timeout ) ) ;
}
}
2011-10-10 10:12:55 +02:00
void wl1271_tx_work_locked ( struct wl1271 * wl )
2009-08-06 16:25:28 +03:00
{
2011-10-10 10:12:55 +02:00
struct wl12xx_vif * wlvif ;
2009-08-06 16:25:28 +03:00
struct sk_buff * skb ;
2011-10-10 10:12:59 +02:00
struct wl1271_tx_hw_descr * desc ;
2010-10-12 14:49:09 +02:00
u32 buf_offset = 0 ;
bool sent_packets = false ;
2011-10-10 10:12:59 +02:00
unsigned long active_hlids [ BITS_TO_LONGS ( WL12XX_MAX_LINKS ) ] = { 0 } ;
2009-08-06 16:25:28 +03:00
int ret ;
if ( unlikely ( wl - > state = = WL1271_STATE_OFF ) )
2011-03-23 22:22:15 +02:00
return ;
2009-08-06 16:25:28 +03:00
2011-10-10 10:12:55 +02:00
while ( ( skb = wl1271_skb_dequeue ( wl ) ) ) {
2011-10-11 13:52:25 +02:00
struct ieee80211_tx_info * info = IEEE80211_SKB_CB ( skb ) ;
2011-10-10 10:12:59 +02:00
bool has_data = false ;
2011-10-10 10:12:55 +02:00
wlvif = NULL ;
2011-10-11 13:52:25 +02:00
if ( ! wl12xx_is_dummy_packet ( wl , skb ) & & info - > control . vif )
wlvif = wl12xx_vif_to_data ( info - > control . vif ) ;
2011-10-10 10:12:55 +02:00
2011-10-10 10:12:59 +02:00
has_data = wlvif & & wl1271_tx_is_data_present ( skb ) ;
2011-10-10 10:12:55 +02:00
ret = wl1271_prepare_tx_frame ( wl , wlvif , skb , buf_offset ) ;
2010-10-12 14:49:09 +02:00
if ( ret = = - EAGAIN ) {
2010-09-30 13:28:28 +02:00
/*
2010-10-12 14:49:09 +02:00
* Aggregation buffer is full .
* Flush buffer and try again .
*/
2011-10-10 10:12:51 +02:00
wl1271_skb_queue_head ( wl , wlvif , skb ) ;
2010-10-12 14:49:09 +02:00
wl1271_write ( wl , WL1271_SLV_MEM_DATA , wl - > aggr_buf ,
2010-12-13 09:52:37 +02:00
buf_offset , true ) ;
2010-10-12 14:49:09 +02:00
sent_packets = true ;
buf_offset = 0 ;
continue ;
} else if ( ret = = - EBUSY ) {
/*
* Firmware buffer is full .
2010-09-30 13:28:28 +02:00
* Queue back last skb , and stop aggregating .
*/
2011-10-10 10:12:51 +02:00
wl1271_skb_queue_head ( wl , wlvif , skb ) ;
2010-10-12 14:49:10 +02:00
/* No work left, avoid scheduling redundant tx work */
set_bit ( WL1271_FLAG_FW_TX_BUSY , & wl - > flags ) ;
2010-02-22 08:38:31 +02:00
goto out_ack ;
2009-08-06 16:25:28 +03:00
} else if ( ret < 0 ) {
2011-12-13 15:26:38 +02:00
if ( wl12xx_is_dummy_packet ( wl , skb ) )
/*
* fw still expects dummy packet ,
* so re - enqueue it
*/
wl1271_skb_queue_head ( wl , wlvif , skb ) ;
else
ieee80211_free_txskb ( wl - > hw , skb ) ;
2010-02-22 08:38:31 +02:00
goto out_ack ;
2009-08-06 16:25:28 +03:00
}
2010-09-30 13:28:28 +02:00
buf_offset + = ret ;
wl - > tx_packets_count + + ;
2011-10-10 10:12:59 +02:00
if ( has_data ) {
desc = ( struct wl1271_tx_hw_descr * ) skb - > data ;
__set_bit ( desc - > hlid , active_hlids ) ;
}
2009-08-06 16:25:28 +03:00
}
2010-02-22 08:38:31 +02:00
out_ack :
2010-09-30 13:28:28 +02:00
if ( buf_offset ) {
wl1271_write ( wl , WL1271_SLV_MEM_DATA , wl - > aggr_buf ,
buf_offset , true ) ;
2010-10-12 14:49:09 +02:00
sent_packets = true ;
}
if ( sent_packets ) {
2011-03-01 15:14:39 +02:00
/*
* Interrupt the firmware with the new packets . This is only
* required for older hardware revisions
*/
if ( wl - > quirks & WL12XX_QUIRK_END_OF_TRANSACTION )
wl1271_write32 ( wl , WL1271_HOST_WR_ACCESS ,
wl - > tx_packets_count ) ;
2011-02-23 00:22:26 +02:00
wl1271_handle_tx_low_watermark ( wl ) ;
2010-09-30 13:28:28 +02:00
}
2011-10-10 10:12:59 +02:00
wl12xx_rearm_rx_streaming ( wl , active_hlids ) ;
2010-10-12 14:49:10 +02:00
}
2009-08-06 16:25:28 +03:00
2010-10-12 14:49:10 +02:00
void wl1271_tx_work ( struct work_struct * work )
{
struct wl1271 * wl = container_of ( work , struct wl1271 , tx_work ) ;
2011-03-23 22:22:15 +02:00
int ret ;
2010-10-12 14:49:10 +02:00
mutex_lock ( & wl - > mutex ) ;
2011-03-23 22:22:15 +02:00
ret = wl1271_ps_elp_wakeup ( wl ) ;
if ( ret < 0 )
goto out ;
2011-10-10 10:12:55 +02:00
wl1271_tx_work_locked ( wl ) ;
2011-03-23 22:22:15 +02:00
2011-04-04 10:38:47 +03:00
wl1271_ps_elp_sleep ( wl ) ;
2011-03-23 22:22:15 +02:00
out :
2009-08-06 16:25:28 +03:00
mutex_unlock ( & wl - > mutex ) ;
}
2012-01-31 17:54:40 +02:00
static u8 wl1271_tx_get_rate_flags ( u8 rate_class_index )
{
2012-01-31 17:54:41 +02:00
u8 flags = 0 ;
2012-01-31 17:54:40 +02:00
if ( rate_class_index > = CONF_HW_RXTX_RATE_MCS_MIN & &
rate_class_index < = CONF_HW_RXTX_RATE_MCS_MAX )
2012-01-31 17:54:41 +02:00
flags | = IEEE80211_TX_RC_MCS ;
if ( rate_class_index = = CONF_HW_RXTX_RATE_MCS7_SGI )
flags | = IEEE80211_TX_RC_SHORT_GI ;
return flags ;
2012-01-31 17:54:40 +02:00
}
2009-08-06 16:25:28 +03:00
static void wl1271_tx_complete_packet ( struct wl1271 * wl ,
struct wl1271_tx_hw_res_descr * result )
{
struct ieee80211_tx_info * info ;
2011-10-10 10:12:58 +02:00
struct ieee80211_vif * vif ;
struct wl12xx_vif * wlvif ;
2009-08-06 16:25:28 +03:00
struct sk_buff * skb ;
int id = result - > id ;
2010-03-26 12:53:12 +02:00
int rate = - 1 ;
2012-01-31 17:54:40 +02:00
u8 rate_flags = 0 ;
2010-03-26 12:53:12 +02:00
u8 retries = 0 ;
2009-08-06 16:25:28 +03:00
/* check for id legality */
2010-02-22 08:38:31 +02:00
if ( unlikely ( id > = ACX_TX_DESCRIPTORS | | wl - > tx_frames [ id ] = = NULL ) ) {
2009-08-06 16:25:28 +03:00
wl1271_warning ( " TX result illegal id: %d " , id ) ;
return ;
}
skb = wl - > tx_frames [ id ] ;
info = IEEE80211_SKB_CB ( skb ) ;
2011-03-31 10:06:59 +02:00
if ( wl12xx_is_dummy_packet ( wl , skb ) ) {
2011-03-06 16:32:14 +02:00
wl1271_free_tx_id ( wl , id ) ;
return ;
}
2011-10-10 10:12:58 +02:00
/* info->control is valid as long as we don't update info->status */
vif = info - > control . vif ;
wlvif = wl12xx_vif_to_data ( vif ) ;
2010-03-26 12:53:12 +02:00
/* update the TX status info */
if ( result - > status = = TX_SUCCESS ) {
if ( ! ( info - > flags & IEEE80211_TX_CTL_NO_ACK ) )
2009-08-06 16:25:28 +03:00
info - > flags | = IEEE80211_TX_STAT_ACK ;
2011-10-10 10:13:09 +02:00
rate = wl1271_rate_to_idx ( result - > rate_class_index ,
wlvif - > band ) ;
2012-01-31 17:54:40 +02:00
rate_flags = wl1271_tx_get_rate_flags ( result - > rate_class_index ) ;
2010-03-26 12:53:12 +02:00
retries = result - > ack_failures ;
} else if ( result - > status = = TX_RETRY_EXCEEDED ) {
wl - > stats . excessive_retries + + ;
retries = result - > ack_failures ;
2009-08-06 16:25:28 +03:00
}
2010-03-26 12:53:12 +02:00
info - > status . rates [ 0 ] . idx = rate ;
info - > status . rates [ 0 ] . count = retries ;
2012-01-31 17:54:40 +02:00
info - > status . rates [ 0 ] . flags = rate_flags ;
2010-03-26 12:53:12 +02:00
info - > status . ack_signal = - 1 ;
2009-08-06 16:25:28 +03:00
wl - > stats . retry_count + = result - > ack_failures ;
2011-06-26 10:36:02 +03:00
/*
* 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 ;
2011-10-10 10:12:58 +02:00
u8 cur_lsb = wlvif - > tx_security_last_seq_lsb ;
2011-06-26 10:36:02 +03:00
/*
* update security sequence number , taking care of potential
* wrap - around
*/
2011-10-10 10:12:58 +02:00
wlvif - > tx_security_seq + = ( fw_lsb - cur_lsb ) & 0xff ;
wlvif - > tx_security_last_seq_lsb = fw_lsb ;
2011-06-26 10:36:02 +03:00
}
2009-10-08 21:56:19 +03:00
2009-10-08 21:56:20 +03:00
/* remove private header from packet */
skb_pull ( skb , sizeof ( struct wl1271_tx_hw_descr ) ) ;
/* remove TKIP header space if present */
2009-08-06 16:25:28 +03:00
if ( info - > control . hw_key & &
2010-08-10 09:46:38 +02:00
info - > control . hw_key - > cipher = = WLAN_CIPHER_SUITE_TKIP ) {
2009-10-08 21:56:20 +03:00
int hdrlen = ieee80211_get_hdrlen_from_skb ( skb ) ;
2012-02-02 12:22:09 +02:00
memmove ( skb - > data + WL1271_EXTRA_SPACE_TKIP , skb - > data ,
hdrlen ) ;
skb_pull ( skb , WL1271_EXTRA_SPACE_TKIP ) ;
2009-10-08 21:56:20 +03:00
}
2009-08-06 16:25:28 +03:00
wl1271_debug ( DEBUG_TX , " tx status id %u skb 0x%p failures %u rate 0x%x "
" status 0x%x " ,
result - > id , skb , result - > ack_failures ,
result - > rate_class_index , result - > status ) ;
/* return the packet to the stack */
2011-03-01 15:14:41 +02:00
skb_queue_tail ( & wl - > deferred_tx_queue , skb ) ;
2011-06-07 12:50:46 +03:00
queue_work ( wl - > freezable_wq , & wl - > netstack_work ) ;
2010-10-12 16:20:06 +02:00
wl1271_free_tx_id ( wl , result - > id ) ;
2009-08-06 16:25:28 +03:00
}
/* Called upon reception of a TX complete interrupt */
2010-02-22 08:38:31 +02:00
void wl1271_tx_complete ( struct wl1271 * wl )
2009-08-06 16:25:28 +03:00
{
struct wl1271_acx_mem_map * memmap =
( struct wl1271_acx_mem_map * ) wl - > target_mem_map ;
2010-02-22 08:38:31 +02:00
u32 count , fw_counter ;
2009-08-06 16:25:28 +03:00
u32 i ;
/* read the tx results from the chipset */
2010-02-18 13:25:55 +02:00
wl1271_read ( wl , le32_to_cpu ( memmap - > tx_result ) ,
wl - > tx_res_if , sizeof ( * wl - > tx_res_if ) , false ) ;
2010-02-22 08:38:31 +02:00
fw_counter = le32_to_cpu ( wl - > tx_res_if - > tx_result_fw_counter ) ;
/* write host counter to chipset (to ack) */
wl1271_write32 ( wl , le32_to_cpu ( memmap - > tx_result ) +
offsetof ( struct wl1271_tx_hw_res_if ,
tx_result_host_counter ) , fw_counter ) ;
count = fw_counter - wl - > tx_results_count ;
2010-02-22 08:38:33 +02:00
wl1271_debug ( DEBUG_TX , " tx_complete received, packets: %d " , count ) ;
2009-08-06 16:25:28 +03:00
/* verify that the result buffer is not getting overrun */
2010-02-22 08:38:31 +02:00
if ( unlikely ( count > TX_HW_RESULT_QUEUE_LEN ) )
2009-08-06 16:25:28 +03:00
wl1271_warning ( " TX result overflow from chipset: %d " , count ) ;
/* process the results */
for ( i = 0 ; i < count ; i + + ) {
struct wl1271_tx_hw_res_descr * result ;
u8 offset = wl - > tx_results_count & TX_HW_RESULT_QUEUE_LEN_MASK ;
/* process the packet */
result = & ( wl - > tx_res_if - > tx_results_queue [ offset ] ) ;
wl1271_tx_complete_packet ( wl , result ) ;
wl - > tx_results_count + + ;
}
}
2011-02-23 00:22:26 +02:00
void wl1271_tx_reset_link_queues ( struct wl1271 * wl , u8 hlid )
{
struct sk_buff * skb ;
2011-07-07 14:25:23 +03:00
int i ;
2011-02-23 00:22:26 +02:00
unsigned long flags ;
2011-02-23 00:22:27 +02:00
struct ieee80211_tx_info * info ;
2011-07-07 14:25:23 +03:00
int total [ NUM_TX_QUEUES ] ;
2011-02-23 00:22:26 +02:00
for ( i = 0 ; i < NUM_TX_QUEUES ; i + + ) {
2011-07-07 14:25:23 +03:00
total [ i ] = 0 ;
2011-02-23 00:22:26 +02:00
while ( ( skb = skb_dequeue ( & wl - > links [ hlid ] . tx_queue [ i ] ) ) ) {
wl1271_debug ( DEBUG_TX , " link freeing skb 0x%p " , skb ) ;
2011-08-14 13:17:18 +03:00
if ( ! wl12xx_is_dummy_packet ( wl , 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 ) ;
}
2011-07-07 14:25:23 +03:00
total [ i ] + + ;
2011-02-23 00:22:26 +02:00
}
}
spin_lock_irqsave ( & wl - > wl_lock , flags ) ;
2011-07-07 14:25:23 +03:00
for ( i = 0 ; i < NUM_TX_QUEUES ; i + + )
wl - > tx_queue_count [ i ] - = total [ i ] ;
2011-02-23 00:22:26 +02:00
spin_unlock_irqrestore ( & wl - > wl_lock , flags ) ;
wl1271_handle_tx_low_watermark ( wl ) ;
}
2011-04-18 14:15:28 +03:00
/* caller must hold wl->mutex and TX must be stopped */
2011-10-10 10:12:51 +02:00
void wl12xx_tx_reset_wlvif ( struct wl1271 * wl , struct wl12xx_vif * wlvif )
2009-08-06 16:25:28 +03:00
{
int i ;
/* TX failure */
2011-10-10 10:12:51 +02:00
for_each_set_bit ( i , wlvif - > links_map , WL12XX_MAX_LINKS ) {
if ( wlvif - > bss_type = = BSS_TYPE_AP_BSS )
2011-10-05 11:56:05 +02:00
wl1271_free_sta ( wl , wlvif , i ) ;
2011-10-10 10:12:51 +02:00
else
wlvif - > sta . ba_rx_bitmap = 0 ;
2011-08-25 12:43:17 +03:00
2011-10-10 10:12:51 +02:00
wl - > links [ i ] . allocated_pkts = 0 ;
wl - > links [ i ] . prev_freed_pkts = 0 ;
2009-08-06 16:25:28 +03:00
}
2011-10-10 10:12:51 +02:00
wlvif - > last_tx_hlid = 0 ;
}
/* caller must hold wl->mutex and TX must be stopped */
void wl12xx_tx_reset ( struct wl1271 * wl , bool reset_tx_queues )
{
int i ;
struct sk_buff * skb ;
struct ieee80211_tx_info * info ;
2011-02-23 00:22:26 +02:00
2012-02-28 00:41:30 +02:00
/* only reset the queues if something bad happened */
if ( WARN_ON_ONCE ( wl1271_tx_total_queue_count ( wl ) ! = 0 ) ) {
for ( i = 0 ; i < WL12XX_MAX_LINKS ; i + + )
wl1271_tx_reset_link_queues ( wl , i ) ;
for ( i = 0 ; i < NUM_TX_QUEUES ; i + + )
wl - > tx_queue_count [ i ] = 0 ;
}
2011-08-25 12:43:17 +03:00
2011-06-24 13:03:37 +03:00
wl - > stopped_queues_map = 0 ;
2009-08-06 16:25:28 +03:00
2010-10-12 14:49:12 +02:00
/*
* Make sure the driver is at a consistent state , in case this
* function is called from a context other than interface removal .
2011-04-18 14:15:28 +03:00
* This call will always wake the TX queues .
2010-10-12 14:49:12 +02:00
*/
2011-04-18 14:15:28 +03:00
if ( reset_tx_queues )
wl1271_handle_tx_low_watermark ( wl ) ;
2010-10-12 14:49:12 +02:00
2011-02-28 00:16:13 +02:00
for ( i = 0 ; i < ACX_TX_DESCRIPTORS ; i + + ) {
if ( wl - > tx_frames [ i ] = = NULL )
continue ;
skb = wl - > tx_frames [ i ] ;
wl1271_free_tx_id ( wl , i ) ;
wl1271_debug ( DEBUG_TX , " freeing skb 0x%p " , skb ) ;
2011-03-31 10:06:59 +02:00
if ( ! wl12xx_is_dummy_packet ( wl , skb ) ) {
2011-03-06 16:32:14 +02:00
/*
* Remove private headers before passing the skb to
* mac80211
*/
info = IEEE80211_SKB_CB ( skb ) ;
skb_pull ( skb , sizeof ( struct wl1271_tx_hw_descr ) ) ;
if ( info - > control . hw_key & &
info - > control . hw_key - > cipher = =
WLAN_CIPHER_SUITE_TKIP ) {
int hdrlen = ieee80211_get_hdrlen_from_skb ( skb ) ;
2012-02-02 12:22:09 +02:00
memmove ( skb - > data + WL1271_EXTRA_SPACE_TKIP ,
2011-03-06 16:32:14 +02:00
skb - > data , hdrlen ) ;
2012-02-02 12:22:09 +02:00
skb_pull ( skb , WL1271_EXTRA_SPACE_TKIP ) ;
2011-03-06 16:32:14 +02:00
}
2011-02-28 00:16:13 +02:00
2011-03-06 16:32:14 +02:00
info - > status . rates [ 0 ] . idx = - 1 ;
info - > status . rates [ 0 ] . count = 0 ;
2011-02-28 00:16:13 +02:00
2011-06-07 10:40:39 +03:00
ieee80211_tx_status_ni ( wl - > hw , skb ) ;
2011-03-06 16:32:14 +02:00
}
2011-02-28 00:16:13 +02:00
}
2010-05-24 11:18:17 +03:00
}
# define WL1271_TX_FLUSH_TIMEOUT 500000
/* caller must *NOT* hold wl->mutex */
void wl1271_tx_flush ( struct wl1271 * wl )
{
unsigned long timeout ;
2012-02-28 00:41:32 +02:00
int i ;
2010-05-24 11:18:17 +03:00
timeout = jiffies + usecs_to_jiffies ( WL1271_TX_FLUSH_TIMEOUT ) ;
while ( ! time_after ( jiffies , timeout ) ) {
mutex_lock ( & wl - > mutex ) ;
2011-02-23 00:22:26 +02:00
wl1271_debug ( DEBUG_TX , " flushing tx buffer: %d %d " ,
2011-07-07 14:25:23 +03:00
wl - > tx_frames_cnt ,
wl1271_tx_total_queue_count ( wl ) ) ;
if ( ( wl - > tx_frames_cnt = = 0 ) & &
( wl1271_tx_total_queue_count ( wl ) = = 0 ) ) {
2010-05-24 11:18:17 +03:00
mutex_unlock ( & wl - > mutex ) ;
return ;
}
mutex_unlock ( & wl - > mutex ) ;
msleep ( 1 ) ;
}
wl1271_warning ( " Unable to flush all TX buffers, timed out. " ) ;
2012-02-28 00:41:32 +02:00
/* forcibly flush all Tx buffers on our queues */
mutex_lock ( & wl - > mutex ) ;
for ( i = 0 ; i < WL12XX_MAX_LINKS ; i + + )
wl1271_tx_reset_link_queues ( wl , i ) ;
mutex_unlock ( & wl - > mutex ) ;
2009-08-06 16:25:28 +03:00
}
2010-10-16 18:19:53 +02:00
2011-09-19 13:51:42 +03:00
u32 wl1271_tx_min_rate_get ( struct wl1271 * wl , u32 rate_set )
2010-10-16 18:19:53 +02:00
{
2011-09-19 13:51:42 +03:00
if ( WARN_ON ( ! rate_set ) )
return 0 ;
2010-10-16 18:19:53 +02:00
2011-09-19 13:51:42 +03:00
return BIT ( __ffs ( rate_set ) ) ;
2010-10-16 18:19:53 +02:00
}