2007-09-18 15:39:42 -04:00
/*
Broadcom B43 wireless driver
Transmission ( TX / RX ) related functions .
Copyright ( C ) 2005 Martin Langer < martin - langer @ gmx . de >
2007-11-06 22:49:20 +01:00
Copyright ( C ) 2005 Stefano Brivio < stefano . brivio @ polimi . it >
2007-09-18 15:39:42 -04:00
Copyright ( C ) 2005 , 2006 Michael Buesch < mb @ bu3sch . de >
Copyright ( C ) 2005 Danny van Dyk < kugelfang @ gentoo . org >
Copyright ( C ) 2005 Andreas Jaggi < andreas . jaggi @ waterwave . ch >
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
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 ; see the file COPYING . If not , write to
the Free Software Foundation , Inc . , 51 Franklin Steet , Fifth Floor ,
Boston , MA 02110 - 1301 , USA .
*/
# include "xmit.h"
# include "phy.h"
# include "dma.h"
2007-12-26 14:41:30 +01:00
2007-09-18 15:39:42 -04:00
2008-01-24 19:38:38 +01:00
/* Extract the bitrate index out of a CCK PLCP header. */
static int b43_plcp_get_bitrate_idx_cck ( struct b43_plcp_hdr6 * plcp )
2007-09-18 15:39:42 -04:00
{
switch ( plcp - > raw [ 0 ] ) {
case 0x0A :
2008-01-24 19:38:38 +01:00
return 0 ;
2007-09-18 15:39:42 -04:00
case 0x14 :
2008-01-24 19:38:38 +01:00
return 1 ;
2007-09-18 15:39:42 -04:00
case 0x37 :
2008-01-24 19:38:38 +01:00
return 2 ;
2007-09-18 15:39:42 -04:00
case 0x6E :
2008-01-24 19:38:38 +01:00
return 3 ;
2007-09-18 15:39:42 -04:00
}
B43_WARN_ON ( 1 ) ;
2008-01-24 19:38:38 +01:00
return - 1 ;
2007-09-18 15:39:42 -04:00
}
2008-01-24 19:38:38 +01:00
/* Extract the bitrate index out of an OFDM PLCP header. */
static u8 b43_plcp_get_bitrate_idx_ofdm ( struct b43_plcp_hdr6 * plcp , bool aphy )
2007-09-18 15:39:42 -04:00
{
2008-01-24 19:38:38 +01:00
int base = aphy ? 0 : 4 ;
2007-09-18 15:39:42 -04:00
switch ( plcp - > raw [ 0 ] & 0xF ) {
case 0xB :
2008-01-24 19:38:38 +01:00
return base + 0 ;
2007-09-18 15:39:42 -04:00
case 0xF :
2008-01-24 19:38:38 +01:00
return base + 1 ;
2007-09-18 15:39:42 -04:00
case 0xA :
2008-01-24 19:38:38 +01:00
return base + 2 ;
2007-09-18 15:39:42 -04:00
case 0xE :
2008-01-24 19:38:38 +01:00
return base + 3 ;
2007-09-18 15:39:42 -04:00
case 0x9 :
2008-01-24 19:38:38 +01:00
return base + 4 ;
2007-09-18 15:39:42 -04:00
case 0xD :
2008-01-24 19:38:38 +01:00
return base + 5 ;
2007-09-18 15:39:42 -04:00
case 0x8 :
2008-01-24 19:38:38 +01:00
return base + 6 ;
2007-09-18 15:39:42 -04:00
case 0xC :
2008-01-24 19:38:38 +01:00
return base + 7 ;
2007-09-18 15:39:42 -04:00
}
B43_WARN_ON ( 1 ) ;
2008-01-24 19:38:38 +01:00
return - 1 ;
2007-09-18 15:39:42 -04:00
}
u8 b43_plcp_get_ratecode_cck ( const u8 bitrate )
{
switch ( bitrate ) {
case B43_CCK_RATE_1MB :
return 0x0A ;
case B43_CCK_RATE_2MB :
return 0x14 ;
case B43_CCK_RATE_5MB :
return 0x37 ;
case B43_CCK_RATE_11MB :
return 0x6E ;
}
B43_WARN_ON ( 1 ) ;
return 0 ;
}
u8 b43_plcp_get_ratecode_ofdm ( const u8 bitrate )
{
switch ( bitrate ) {
case B43_OFDM_RATE_6MB :
return 0xB ;
case B43_OFDM_RATE_9MB :
return 0xF ;
case B43_OFDM_RATE_12MB :
return 0xA ;
case B43_OFDM_RATE_18MB :
return 0xE ;
case B43_OFDM_RATE_24MB :
return 0x9 ;
case B43_OFDM_RATE_36MB :
return 0xD ;
case B43_OFDM_RATE_48MB :
return 0x8 ;
case B43_OFDM_RATE_54MB :
return 0xC ;
}
B43_WARN_ON ( 1 ) ;
return 0 ;
}
void b43_generate_plcp_hdr ( struct b43_plcp_hdr4 * plcp ,
const u16 octets , const u8 bitrate )
{
__le32 * data = & ( plcp - > data ) ;
__u8 * raw = plcp - > raw ;
if ( b43_is_ofdm_rate ( bitrate ) ) {
2007-09-20 11:13:40 -07:00
u32 d ;
d = b43_plcp_get_ratecode_ofdm ( bitrate ) ;
2007-09-18 15:39:42 -04:00
B43_WARN_ON ( octets & 0xF000 ) ;
2007-09-20 11:13:40 -07:00
d | = ( octets < < 5 ) ;
* data = cpu_to_le32 ( d ) ;
2007-09-18 15:39:42 -04:00
} else {
u32 plen ;
plen = octets * 16 / bitrate ;
if ( ( octets * 16 % bitrate ) > 0 ) {
plen + + ;
if ( ( bitrate = = B43_CCK_RATE_11MB )
& & ( ( octets * 8 % 11 ) < 4 ) ) {
raw [ 1 ] = 0x84 ;
} else
raw [ 1 ] = 0x04 ;
} else
raw [ 1 ] = 0x04 ;
* data | = cpu_to_le32 ( plen < < 16 ) ;
raw [ 0 ] = b43_plcp_get_ratecode_cck ( bitrate ) ;
}
}
static u8 b43_calc_fallback_rate ( u8 bitrate )
{
switch ( bitrate ) {
case B43_CCK_RATE_1MB :
return B43_CCK_RATE_1MB ;
case B43_CCK_RATE_2MB :
return B43_CCK_RATE_1MB ;
case B43_CCK_RATE_5MB :
return B43_CCK_RATE_2MB ;
case B43_CCK_RATE_11MB :
return B43_CCK_RATE_5MB ;
case B43_OFDM_RATE_6MB :
return B43_CCK_RATE_5MB ;
case B43_OFDM_RATE_9MB :
return B43_OFDM_RATE_6MB ;
case B43_OFDM_RATE_12MB :
return B43_OFDM_RATE_9MB ;
case B43_OFDM_RATE_18MB :
return B43_OFDM_RATE_12MB ;
case B43_OFDM_RATE_24MB :
return B43_OFDM_RATE_18MB ;
case B43_OFDM_RATE_36MB :
return B43_OFDM_RATE_24MB ;
case B43_OFDM_RATE_48MB :
return B43_OFDM_RATE_36MB ;
case B43_OFDM_RATE_54MB :
return B43_OFDM_RATE_48MB ;
}
B43_WARN_ON ( 1 ) ;
return 0 ;
}
2008-01-28 14:47:41 -08:00
/* Generate a TX data header. */
2008-01-23 21:44:15 +01:00
int b43_generate_txhdr ( struct b43_wldev * dev ,
u8 * _txhdr ,
const unsigned char * fragment_data ,
unsigned int fragment_len ,
const struct ieee80211_tx_control * txctl ,
u16 cookie )
2007-09-18 15:39:42 -04:00
{
2008-01-28 14:47:41 -08:00
struct b43_txhdr * txhdr = ( struct b43_txhdr * ) _txhdr ;
2007-09-18 15:39:42 -04:00
const struct b43_phy * phy = & dev - > phy ;
const struct ieee80211_hdr * wlhdr =
( const struct ieee80211_hdr * ) fragment_data ;
int use_encryption = ( ! ( txctl - > flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT ) ) ;
u16 fctl = le16_to_cpu ( wlhdr - > frame_control ) ;
2008-01-24 19:38:38 +01:00
struct ieee80211_rate * fbrate ;
2007-09-18 15:39:42 -04:00
u8 rate , rate_fb ;
int rate_ofdm , rate_fb_ofdm ;
unsigned int plcp_fragment_len ;
u32 mac_ctl = 0 ;
u16 phy_ctl = 0 ;
u8 extra_ft = 0 ;
memset ( txhdr , 0 , sizeof ( * txhdr ) ) ;
2008-01-24 19:38:38 +01:00
WARN_ON ( ! txctl - > tx_rate ) ;
rate = txctl - > tx_rate ? txctl - > tx_rate - > hw_value : B43_CCK_RATE_1MB ;
2007-09-18 15:39:42 -04:00
rate_ofdm = b43_is_ofdm_rate ( rate ) ;
2008-01-24 19:38:38 +01:00
fbrate = txctl - > alt_retry_rate ? : txctl - > tx_rate ;
rate_fb = fbrate - > hw_value ;
2007-09-18 15:39:42 -04:00
rate_fb_ofdm = b43_is_ofdm_rate ( rate_fb ) ;
if ( rate_ofdm )
txhdr - > phy_rate = b43_plcp_get_ratecode_ofdm ( rate ) ;
else
txhdr - > phy_rate = b43_plcp_get_ratecode_cck ( rate ) ;
txhdr - > mac_frame_ctl = wlhdr - > frame_control ;
memcpy ( txhdr - > tx_receiver , wlhdr - > addr1 , 6 ) ;
/* Calculate duration for fallback rate */
if ( ( rate_fb = = rate ) | |
( wlhdr - > duration_id & cpu_to_le16 ( 0x8000 ) ) | |
( wlhdr - > duration_id = = cpu_to_le16 ( 0 ) ) ) {
/* If the fallback rate equals the normal rate or the
* dur_id field contains an AID , CFP magic or 0 ,
* use the original dur_id field . */
txhdr - > dur_fb = wlhdr - > duration_id ;
} else {
txhdr - > dur_fb = ieee80211_generic_frame_duration ( dev - > wl - > hw ,
2007-12-19 01:31:26 +01:00
txctl - > vif ,
2007-09-18 15:39:42 -04:00
fragment_len ,
2008-01-24 19:38:38 +01:00
fbrate ) ;
2007-09-18 15:39:42 -04:00
}
plcp_fragment_len = fragment_len + FCS_LEN ;
if ( use_encryption ) {
u8 key_idx = ( u16 ) ( txctl - > key_idx ) ;
struct b43_key * key ;
int wlhdr_len ;
size_t iv_len ;
B43_WARN_ON ( key_idx > = dev - > max_nr_keys ) ;
key = & ( dev - > key [ key_idx ] ) ;
2008-01-23 21:10:56 +01:00
2008-01-23 21:44:15 +01:00
if ( unlikely ( ! key - > keyconf ) ) {
/* This key is invalid. This might only happen
* in a short timeframe after machine resume before
* we were able to reconfigure keys .
* Drop this packet completely . Do not transmit it
* unencrypted to avoid leaking information . */
return - ENOKEY ;
2008-01-23 21:10:56 +01:00
}
2008-01-23 21:44:15 +01:00
/* Hardware appends ICV. */
plcp_fragment_len + = txctl - > icv_len ;
key_idx = b43_kidx_to_fw ( dev , key_idx ) ;
mac_ctl | = ( key_idx < < B43_TXH_MAC_KEYIDX_SHIFT ) &
B43_TXH_MAC_KEYIDX ;
mac_ctl | = ( key - > algorithm < < B43_TXH_MAC_KEYALG_SHIFT ) &
B43_TXH_MAC_KEYALG ;
wlhdr_len = ieee80211_get_hdrlen ( fctl ) ;
iv_len = min ( ( size_t ) txctl - > iv_len ,
ARRAY_SIZE ( txhdr - > iv ) ) ;
memcpy ( txhdr - > iv , ( ( u8 * ) wlhdr ) + wlhdr_len , iv_len ) ;
2007-09-18 15:39:42 -04:00
}
2008-01-28 14:47:41 -08:00
if ( b43_is_old_txhdr_format ( dev ) ) {
b43_generate_plcp_hdr ( ( struct b43_plcp_hdr4 * ) ( & txhdr - > old_format . plcp ) ,
plcp_fragment_len , rate ) ;
} else {
b43_generate_plcp_hdr ( ( struct b43_plcp_hdr4 * ) ( & txhdr - > new_format . plcp ) ,
plcp_fragment_len , rate ) ;
}
2007-09-18 15:39:42 -04:00
b43_generate_plcp_hdr ( ( struct b43_plcp_hdr4 * ) ( & txhdr - > plcp_fb ) ,
plcp_fragment_len , rate_fb ) ;
/* Extra Frame Types */
if ( rate_fb_ofdm )
2008-01-28 14:47:41 -08:00
extra_ft | = B43_TXH_EFT_FB_OFDM ;
else
extra_ft | = B43_TXH_EFT_FB_CCK ;
2007-09-18 15:39:42 -04:00
/* Set channel radio code. Note that the micrcode ORs 0x100 to
* this value before comparing it to the value in SHM , if this
* is a 5 Ghz packet .
*/
txhdr - > chan_radio_code = phy - > channel ;
/* PHY TX Control word */
if ( rate_ofdm )
2008-01-28 14:47:41 -08:00
phy_ctl | = B43_TXH_PHY_ENC_OFDM ;
else
phy_ctl | = B43_TXH_PHY_ENC_CCK ;
2008-01-24 19:38:38 +01:00
if ( txctl - > flags & IEEE80211_TXCTL_SHORT_PREAMBLE )
2008-01-28 14:47:41 -08:00
phy_ctl | = B43_TXH_PHY_SHORTPRMBL ;
2007-12-22 21:54:20 +01:00
switch ( b43_ieee80211_antenna_sanitize ( dev , txctl - > antenna_sel_tx ) ) {
case 0 : /* Default */
2008-01-28 14:47:41 -08:00
phy_ctl | = B43_TXH_PHY_ANT01AUTO ;
2007-09-18 15:39:42 -04:00
break ;
2007-12-22 21:54:20 +01:00
case 1 : /* Antenna 0 */
2008-01-28 14:47:41 -08:00
phy_ctl | = B43_TXH_PHY_ANT0 ;
2007-09-18 15:39:42 -04:00
break ;
2007-12-22 21:54:20 +01:00
case 2 : /* Antenna 1 */
2008-01-28 14:47:41 -08:00
phy_ctl | = B43_TXH_PHY_ANT1 ;
break ;
case 3 : /* Antenna 2 */
phy_ctl | = B43_TXH_PHY_ANT2 ;
break ;
case 4 : /* Antenna 3 */
phy_ctl | = B43_TXH_PHY_ANT3 ;
2007-09-18 15:39:42 -04:00
break ;
default :
B43_WARN_ON ( 1 ) ;
}
/* MAC control */
if ( ! ( txctl - > flags & IEEE80211_TXCTL_NO_ACK ) )
2008-01-28 14:47:41 -08:00
mac_ctl | = B43_TXH_MAC_ACK ;
2007-09-18 15:39:42 -04:00
if ( ! ( ( ( fctl & IEEE80211_FCTL_FTYPE ) = = IEEE80211_FTYPE_CTL ) & &
( ( fctl & IEEE80211_FCTL_STYPE ) = = IEEE80211_STYPE_PSPOLL ) ) )
2008-01-28 14:47:41 -08:00
mac_ctl | = B43_TXH_MAC_HWSEQ ;
2007-09-18 15:39:42 -04:00
if ( txctl - > flags & IEEE80211_TXCTL_FIRST_FRAGMENT )
2008-01-28 14:47:41 -08:00
mac_ctl | = B43_TXH_MAC_STMSDU ;
2007-09-18 15:39:42 -04:00
if ( phy - > type = = B43_PHYTYPE_A )
2008-01-28 14:47:41 -08:00
mac_ctl | = B43_TXH_MAC_5GHZ ;
2007-10-28 16:19:44 +01:00
if ( txctl - > flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT )
2008-01-28 14:47:41 -08:00
mac_ctl | = B43_TXH_MAC_LONGFRAME ;
2007-09-18 15:39:42 -04:00
/* Generate the RTS or CTS-to-self frame */
if ( ( txctl - > flags & IEEE80211_TXCTL_USE_RTS_CTS ) | |
( txctl - > flags & IEEE80211_TXCTL_USE_CTS_PROTECT ) ) {
unsigned int len ;
struct ieee80211_hdr * hdr ;
int rts_rate , rts_rate_fb ;
int rts_rate_ofdm , rts_rate_fb_ofdm ;
2008-01-28 14:47:41 -08:00
struct b43_plcp_hdr6 * plcp ;
2007-09-18 15:39:42 -04:00
2008-01-24 19:38:38 +01:00
WARN_ON ( ! txctl - > rts_cts_rate ) ;
rts_rate = txctl - > rts_cts_rate ? txctl - > rts_cts_rate - > hw_value : B43_CCK_RATE_1MB ;
2007-09-18 15:39:42 -04:00
rts_rate_ofdm = b43_is_ofdm_rate ( rts_rate ) ;
rts_rate_fb = b43_calc_fallback_rate ( rts_rate ) ;
rts_rate_fb_ofdm = b43_is_ofdm_rate ( rts_rate_fb ) ;
if ( txctl - > flags & IEEE80211_TXCTL_USE_CTS_PROTECT ) {
2008-01-28 14:47:41 -08:00
struct ieee80211_cts * cts ;
if ( b43_is_old_txhdr_format ( dev ) ) {
cts = ( struct ieee80211_cts * )
( txhdr - > old_format . rts_frame ) ;
} else {
cts = ( struct ieee80211_cts * )
( txhdr - > new_format . rts_frame ) ;
}
2007-12-19 01:31:26 +01:00
ieee80211_ctstoself_get ( dev - > wl - > hw , txctl - > vif ,
2007-09-18 15:39:42 -04:00
fragment_data , fragment_len ,
2008-01-28 14:47:41 -08:00
txctl , cts ) ;
mac_ctl | = B43_TXH_MAC_SENDCTS ;
2007-09-18 15:39:42 -04:00
len = sizeof ( struct ieee80211_cts ) ;
} else {
2008-01-28 14:47:41 -08:00
struct ieee80211_rts * rts ;
if ( b43_is_old_txhdr_format ( dev ) ) {
rts = ( struct ieee80211_rts * )
( txhdr - > old_format . rts_frame ) ;
} else {
rts = ( struct ieee80211_rts * )
( txhdr - > new_format . rts_frame ) ;
}
2007-12-19 01:31:26 +01:00
ieee80211_rts_get ( dev - > wl - > hw , txctl - > vif ,
2008-01-28 14:47:41 -08:00
fragment_data , fragment_len ,
txctl , rts ) ;
mac_ctl | = B43_TXH_MAC_SENDRTS ;
2007-09-18 15:39:42 -04:00
len = sizeof ( struct ieee80211_rts ) ;
}
len + = FCS_LEN ;
2008-01-28 14:47:41 -08:00
/* Generate the PLCP headers for the RTS/CTS frame */
if ( b43_is_old_txhdr_format ( dev ) )
plcp = & txhdr - > old_format . rts_plcp ;
else
plcp = & txhdr - > new_format . rts_plcp ;
b43_generate_plcp_hdr ( ( struct b43_plcp_hdr4 * ) plcp ,
len , rts_rate ) ;
plcp = & txhdr - > rts_plcp_fb ;
b43_generate_plcp_hdr ( ( struct b43_plcp_hdr4 * ) plcp ,
2007-09-18 15:39:42 -04:00
len , rts_rate_fb ) ;
2008-01-28 14:47:41 -08:00
if ( b43_is_old_txhdr_format ( dev ) ) {
hdr = ( struct ieee80211_hdr * )
( & txhdr - > old_format . rts_frame ) ;
} else {
hdr = ( struct ieee80211_hdr * )
( & txhdr - > new_format . rts_frame ) ;
}
2007-09-18 15:39:42 -04:00
txhdr - > rts_dur_fb = hdr - > duration_id ;
2008-01-28 14:47:41 -08:00
2007-09-18 15:39:42 -04:00
if ( rts_rate_ofdm ) {
2008-01-28 14:47:41 -08:00
extra_ft | = B43_TXH_EFT_RTS_OFDM ;
2007-09-18 15:39:42 -04:00
txhdr - > phy_rate_rts =
b43_plcp_get_ratecode_ofdm ( rts_rate ) ;
2008-01-28 14:47:41 -08:00
} else {
extra_ft | = B43_TXH_EFT_RTS_CCK ;
2007-09-18 15:39:42 -04:00
txhdr - > phy_rate_rts =
b43_plcp_get_ratecode_cck ( rts_rate ) ;
2008-01-28 14:47:41 -08:00
}
2007-09-18 15:39:42 -04:00
if ( rts_rate_fb_ofdm )
2008-01-28 14:47:41 -08:00
extra_ft | = B43_TXH_EFT_RTSFB_OFDM ;
else
extra_ft | = B43_TXH_EFT_RTSFB_CCK ;
2007-09-18 15:39:42 -04:00
}
/* Magic cookie */
2008-01-28 14:47:41 -08:00
if ( b43_is_old_txhdr_format ( dev ) )
txhdr - > old_format . cookie = cpu_to_le16 ( cookie ) ;
else
txhdr - > new_format . cookie = cpu_to_le16 ( cookie ) ;
2007-09-18 15:39:42 -04:00
/* Apply the bitfields */
txhdr - > mac_ctl = cpu_to_le32 ( mac_ctl ) ;
txhdr - > phy_ctl = cpu_to_le16 ( phy_ctl ) ;
txhdr - > extra_ft = extra_ft ;
2008-01-23 21:44:15 +01:00
return 0 ;
2007-09-18 15:39:42 -04:00
}
static s8 b43_rssi_postprocess ( struct b43_wldev * dev ,
u8 in_rssi , int ofdm ,
int adjust_2053 , int adjust_2050 )
{
struct b43_phy * phy = & dev - > phy ;
s32 tmp ;
switch ( phy - > radio_ver ) {
case 0x2050 :
if ( ofdm ) {
tmp = in_rssi ;
if ( tmp > 127 )
tmp - = 256 ;
tmp * = 73 ;
tmp / = 64 ;
if ( adjust_2050 )
tmp + = 25 ;
else
tmp - = 3 ;
} else {
2007-11-09 16:57:18 -06:00
if ( dev - > dev - > bus - > sprom .
2007-09-18 15:39:42 -04:00
boardflags_lo & B43_BFL_RSSI ) {
if ( in_rssi > 63 )
in_rssi = 63 ;
tmp = phy - > nrssi_lt [ in_rssi ] ;
tmp = 31 - tmp ;
tmp * = - 131 ;
tmp / = 128 ;
tmp - = 57 ;
} else {
tmp = in_rssi ;
tmp = 31 - tmp ;
tmp * = - 149 ;
tmp / = 128 ;
tmp - = 68 ;
}
if ( phy - > type = = B43_PHYTYPE_G & & adjust_2050 )
tmp + = 25 ;
}
break ;
case 0x2060 :
if ( in_rssi > 127 )
tmp = in_rssi - 256 ;
else
tmp = in_rssi ;
break ;
default :
tmp = in_rssi ;
tmp - = 11 ;
tmp * = 103 ;
tmp / = 64 ;
if ( adjust_2053 )
tmp - = 109 ;
else
tmp - = 83 ;
}
return ( s8 ) tmp ;
}
//TODO
#if 0
static s8 b43_rssinoise_postprocess ( struct b43_wldev * dev , u8 in_rssi )
{
struct b43_phy * phy = & dev - > phy ;
s8 ret ;
if ( phy - > type = = B43_PHYTYPE_A ) {
//TODO: Incomplete specs.
ret = 0 ;
} else
ret = b43_rssi_postprocess ( dev , in_rssi , 0 , 1 , 1 ) ;
return ret ;
}
# endif
void b43_rx ( struct b43_wldev * dev , struct sk_buff * skb , const void * _rxhdr )
{
struct ieee80211_rx_status status ;
struct b43_plcp_hdr6 * plcp ;
struct ieee80211_hdr * wlhdr ;
const struct b43_rxhdr_fw4 * rxhdr = _rxhdr ;
u16 fctl ;
u16 phystat0 , phystat3 , chanstat , mactime ;
u32 macstat ;
u16 chanid ;
2008-01-24 19:38:38 +01:00
u16 phytype ;
2007-09-18 15:39:42 -04:00
u8 jssi ;
int padding ;
memset ( & status , 0 , sizeof ( status ) ) ;
/* Get metadata about the frame from the header. */
phystat0 = le16_to_cpu ( rxhdr - > phy_status0 ) ;
phystat3 = le16_to_cpu ( rxhdr - > phy_status3 ) ;
jssi = rxhdr - > jssi ;
macstat = le32_to_cpu ( rxhdr - > mac_status ) ;
mactime = le16_to_cpu ( rxhdr - > mac_time ) ;
chanstat = le16_to_cpu ( rxhdr - > channel ) ;
2008-01-24 19:38:38 +01:00
phytype = chanstat & B43_RX_CHAN_PHYTYPE ;
2007-09-18 15:39:42 -04:00
if ( macstat & B43_RX_MAC_FCSERR )
dev - > wl - > ieee_stats . dot11FCSErrorCount + + ;
if ( macstat & B43_RX_MAC_DECERR ) {
/* Decryption with the given key failed.
* Drop the packet . We also won ' t be able to decrypt it with
* the key in software . */
goto drop ;
}
/* Skip PLCP and padding */
padding = ( macstat & B43_RX_MAC_PADDING ) ? 2 : 0 ;
if ( unlikely ( skb - > len < ( sizeof ( struct b43_plcp_hdr6 ) + padding ) ) ) {
b43dbg ( dev - > wl , " RX: Packet size underrun (1) \n " ) ;
goto drop ;
}
plcp = ( struct b43_plcp_hdr6 * ) ( skb - > data + padding ) ;
skb_pull ( skb , sizeof ( struct b43_plcp_hdr6 ) + padding ) ;
/* The skb contains the Wireless Header + payload data now */
if ( unlikely ( skb - > len < ( 2 + 2 + 6 /*minimum hdr */ + FCS_LEN ) ) ) {
b43dbg ( dev - > wl , " RX: Packet size underrun (2) \n " ) ;
goto drop ;
}
wlhdr = ( struct ieee80211_hdr * ) ( skb - > data ) ;
fctl = le16_to_cpu ( wlhdr - > frame_control ) ;
if ( macstat & B43_RX_MAC_DEC ) {
unsigned int keyidx ;
int wlhdr_len ;
keyidx = ( ( macstat & B43_RX_MAC_KEYIDX )
> > B43_RX_MAC_KEYIDX_SHIFT ) ;
/* We must adjust the key index here. We want the "physical"
* key index , but the ucode passed it slightly different .
*/
keyidx = b43_kidx_to_raw ( dev , keyidx ) ;
B43_WARN_ON ( keyidx > = dev - > max_nr_keys ) ;
if ( dev - > key [ keyidx ] . algorithm ! = B43_SEC_ALGO_NONE ) {
wlhdr_len = ieee80211_get_hdrlen ( fctl ) ;
if ( unlikely ( skb - > len < ( wlhdr_len + 3 ) ) ) {
b43dbg ( dev - > wl ,
" RX: Packet size underrun (3) \n " ) ;
goto drop ;
}
status . flag | = RX_FLAG_DECRYPTED ;
}
}
status . ssi = b43_rssi_postprocess ( dev , jssi ,
( phystat0 & B43_RX_PHYST0_OFDM ) ,
( phystat0 & B43_RX_PHYST0_GAINCTL ) ,
( phystat3 & B43_RX_PHYST3_TRSTATE ) ) ;
status . noise = dev - > stats . link_noise ;
/* the next line looks wrong, but is what mac80211 wants */
status . signal = ( jssi * 100 ) / B43_RX_MAX_SSI ;
if ( phystat0 & B43_RX_PHYST0_OFDM )
2008-01-24 19:38:38 +01:00
status . rate_idx = b43_plcp_get_bitrate_idx_ofdm ( plcp ,
phytype = = B43_PHYTYPE_A ) ;
2007-09-18 15:39:42 -04:00
else
2008-01-24 19:38:38 +01:00
status . rate_idx = b43_plcp_get_bitrate_idx_cck ( plcp ) ;
2007-09-18 15:39:42 -04:00
status . antenna = ! ! ( phystat0 & B43_RX_PHYST0_ANT ) ;
2008-01-21 13:41:18 -05:00
/*
* If monitors are present get full 64 - bit timestamp . This
* code assumes we get to process the packet within 16 bits
* of timestamp , i . e . about 65 milliseconds after the PHY
* received the first symbol .
*/
if ( dev - > wl - > radiotap_enabled ) {
u16 low_mactime_now ;
b43_tsf_read ( dev , & status . mactime ) ;
low_mactime_now = status . mactime ;
status . mactime = status . mactime & ~ 0xFFFFULL ;
status . mactime + = mactime ;
if ( low_mactime_now < = mactime )
status . mactime - = 0x10000 ;
status . flag | = RX_FLAG_TSFT ;
}
2007-09-18 15:39:42 -04:00
chanid = ( chanstat & B43_RX_CHAN_ID ) > > B43_RX_CHAN_ID_SHIFT ;
switch ( chanstat & B43_RX_CHAN_PHYTYPE ) {
case B43_PHYTYPE_A :
2008-01-24 19:38:38 +01:00
status . band = IEEE80211_BAND_5GHZ ;
2008-01-02 18:55:53 +01:00
B43_WARN_ON ( 1 ) ;
/* FIXME: We don't really know which value the "chanid" contains.
* So the following assignment might be wrong . */
2008-01-24 19:38:38 +01:00
status . freq = b43_channel_to_freq_5ghz ( chanid ) ;
2007-09-18 15:39:42 -04:00
break ;
case B43_PHYTYPE_G :
2008-01-24 19:38:38 +01:00
status . band = IEEE80211_BAND_2GHZ ;
2008-01-02 18:55:53 +01:00
/* chanid is the radio channel cookie value as used
* to tune the radio . */
2007-09-18 15:39:42 -04:00
status . freq = chanid + 2400 ;
2008-01-02 18:55:53 +01:00
break ;
case B43_PHYTYPE_N :
/* chanid is the SHM channel cookie. Which is the plain
* channel number in b43 . */
2008-01-24 19:38:38 +01:00
if ( chanstat & B43_RX_CHAN_5GHZ ) {
status . band = IEEE80211_BAND_5GHZ ;
status . freq = b43_freq_to_channel_5ghz ( chanid ) ;
} else {
status . band = IEEE80211_BAND_2GHZ ;
status . freq = b43_freq_to_channel_2ghz ( chanid ) ;
}
2007-09-18 15:39:42 -04:00
break ;
default :
B43_WARN_ON ( 1 ) ;
2008-01-02 18:55:53 +01:00
goto drop ;
2007-09-18 15:39:42 -04:00
}
dev - > stats . last_rx = jiffies ;
ieee80211_rx_irqsafe ( dev - > wl - > hw , skb , & status ) ;
return ;
drop :
b43dbg ( dev - > wl , " RX: Packet dropped \n " ) ;
dev_kfree_skb_any ( skb ) ;
}
void b43_handle_txstatus ( struct b43_wldev * dev ,
const struct b43_txstatus * status )
{
b43_debugfs_log_txstat ( dev , status ) ;
if ( status - > intermediate )
return ;
if ( status - > for_ampdu )
return ;
if ( ! status - > acked )
dev - > wl - > ieee_stats . dot11ACKFailureCount + + ;
if ( status - > rts_count ) {
if ( status - > rts_count = = 0xF ) //FIXME
dev - > wl - > ieee_stats . dot11RTSFailureCount + + ;
else
dev - > wl - > ieee_stats . dot11RTSSuccessCount + + ;
}
2007-12-26 14:41:30 +01:00
b43_dma_handle_txstatus ( dev , status ) ;
2007-09-18 15:39:42 -04:00
}
/* Handle TX status report as received through DMA/PIO queues */
void b43_handle_hwtxstatus ( struct b43_wldev * dev ,
const struct b43_hwtxstatus * hw )
{
struct b43_txstatus status ;
u8 tmp ;
status . cookie = le16_to_cpu ( hw - > cookie ) ;
status . seq = le16_to_cpu ( hw - > seq ) ;
status . phy_stat = hw - > phy_stat ;
tmp = hw - > count ;
status . frame_count = ( tmp > > 4 ) ;
status . rts_count = ( tmp & 0x0F ) ;
tmp = hw - > flags ;
status . supp_reason = ( ( tmp & 0x1C ) > > 2 ) ;
status . pm_indicated = ! ! ( tmp & 0x80 ) ;
status . intermediate = ! ! ( tmp & 0x40 ) ;
status . for_ampdu = ! ! ( tmp & 0x20 ) ;
status . acked = ! ! ( tmp & 0x02 ) ;
b43_handle_txstatus ( dev , & status ) ;
}
/* Stop any TX operation on the device (suspend the hardware queues) */
void b43_tx_suspend ( struct b43_wldev * dev )
{
2007-12-26 14:41:30 +01:00
b43_dma_tx_suspend ( dev ) ;
2007-09-18 15:39:42 -04:00
}
/* Resume any TX operation on the device (resume the hardware queues) */
void b43_tx_resume ( struct b43_wldev * dev )
{
2007-12-26 14:41:30 +01:00
b43_dma_tx_resume ( dev ) ;
2007-09-18 15:39:42 -04:00
}
#if 0
static void upload_qos_parms ( struct b43_wldev * dev ,
const u16 * parms , u16 offset )
{
int i ;
for ( i = 0 ; i < B43_NR_QOSPARMS ; i + + ) {
b43_shm_write16 ( dev , B43_SHM_SHARED ,
offset + ( i * 2 ) , parms [ i ] ) ;
}
}
# endif
/* Initialize the QoS parameters */
void b43_qos_init ( struct b43_wldev * dev )
{
/* FIXME: This function must probably be called from the mac80211
* config callback . */
return ;
b43_hf_write ( dev , b43_hf_read ( dev ) | B43_HF_EDCF ) ;
//FIXME kill magic
b43_write16 ( dev , 0x688 , b43_read16 ( dev , 0x688 ) | 0x4 ) ;
/*TODO: We might need some stack support here to get the values. */
}