2011-02-21 11:27:26 -08:00
/******************************************************************************
*
* GPL LICENSE SUMMARY
*
* Copyright ( c ) 2008 - 2011 Intel Corporation . All rights reserved .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of version 2 of the GNU General Public License 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 Street , Fifth Floor , Boston , MA 02110 ,
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE . GPL .
*
* Contact Information :
* Intel Linux Wireless < ilw @ linux . intel . com >
* Intel Corporation , 5200 N . E . Elam Young Parkway , Hillsboro , OR 97124 - 6497
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/etherdevice.h>
# include <linux/sched.h>
# include <linux/slab.h>
2011-11-15 13:40:15 +01:00
# include <linux/types.h>
# include <linux/lockdep.h>
# include <linux/init.h>
# include <linux/pci.h>
# include <linux/dma-mapping.h>
# include <linux/delay.h>
# include <linux/skbuff.h>
2011-02-21 11:27:26 -08:00
# include <net/mac80211.h>
2011-11-15 14:19:34 +01:00
# include "common.h"
2011-02-21 11:27:26 -08:00
2011-12-23 08:13:43 +01:00
int
_il_poll_bit ( struct il_priv * il , u32 addr , u32 bits , u32 mask , int timeout )
{
const int interval = 10 ; /* microseconds */
int t = 0 ;
do {
if ( ( _il_rd ( il , addr ) & mask ) = = ( bits & mask ) )
return t ;
udelay ( interval ) ;
t + = interval ;
} while ( t < timeout ) ;
return - ETIMEDOUT ;
}
EXPORT_SYMBOL ( _il_poll_bit ) ;
void
il_set_bit ( struct il_priv * p , u32 r , u32 m )
{
unsigned long reg_flags ;
spin_lock_irqsave ( & p - > reg_lock , reg_flags ) ;
_il_set_bit ( p , r , m ) ;
spin_unlock_irqrestore ( & p - > reg_lock , reg_flags ) ;
}
EXPORT_SYMBOL ( il_set_bit ) ;
void
il_clear_bit ( struct il_priv * p , u32 r , u32 m )
{
unsigned long reg_flags ;
spin_lock_irqsave ( & p - > reg_lock , reg_flags ) ;
_il_clear_bit ( p , r , m ) ;
spin_unlock_irqrestore ( & p - > reg_lock , reg_flags ) ;
}
EXPORT_SYMBOL ( il_clear_bit ) ;
int
_il_grab_nic_access ( struct il_priv * il )
{
int ret ;
u32 val ;
/* this bit wakes up the NIC */
_il_set_bit ( il , CSR_GP_CNTRL , CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ ) ;
/*
* These bits say the device is running , and should keep running for
* at least a short while ( at least as long as MAC_ACCESS_REQ stays 1 ) ,
* but they do not indicate that embedded SRAM is restored yet ;
* 3945 and 4965 have volatile SRAM , and must save / restore contents
* to / from host DRAM when sleeping / waking for power - saving .
* Each direction takes approximately 1 / 4 millisecond ; with this
* overhead , it ' s a good idea to grab and hold MAC_ACCESS_REQUEST if a
* series of register accesses are expected ( e . g . reading Event Log ) ,
* to keep device from sleeping .
*
* CSR_UCODE_DRV_GP1 register bit MAC_SLEEP = = 0 indicates that
* SRAM is okay / restored . We don ' t check that here because this call
* is just for hardware register access ; but GP1 MAC_SLEEP check is a
* good idea before accessing 3945 / 4965 SRAM ( e . g . reading Event Log ) .
*
*/
ret =
_il_poll_bit ( il , CSR_GP_CNTRL , CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN ,
( CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP ) , 15000 ) ;
if ( ret < 0 ) {
val = _il_rd ( il , CSR_GP_CNTRL ) ;
IL_ERR ( " MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X \n " , val ) ;
_il_wr ( il , CSR_RESET , CSR_RESET_REG_FLAG_FORCE_NMI ) ;
return - EIO ;
}
return 0 ;
}
EXPORT_SYMBOL_GPL ( _il_grab_nic_access ) ;
int
il_poll_bit ( struct il_priv * il , u32 addr , u32 mask , int timeout )
{
const int interval = 10 ; /* microseconds */
int t = 0 ;
do {
if ( ( il_rd ( il , addr ) & mask ) = = mask )
return t ;
udelay ( interval ) ;
t + = interval ;
} while ( t < timeout ) ;
return - ETIMEDOUT ;
}
EXPORT_SYMBOL ( il_poll_bit ) ;
u32
il_rd_prph ( struct il_priv * il , u32 reg )
{
unsigned long reg_flags ;
u32 val ;
spin_lock_irqsave ( & il - > reg_lock , reg_flags ) ;
_il_grab_nic_access ( il ) ;
val = _il_rd_prph ( il , reg ) ;
_il_release_nic_access ( il ) ;
spin_unlock_irqrestore ( & il - > reg_lock , reg_flags ) ;
return val ;
}
EXPORT_SYMBOL ( il_rd_prph ) ;
void
il_wr_prph ( struct il_priv * il , u32 addr , u32 val )
{
unsigned long reg_flags ;
spin_lock_irqsave ( & il - > reg_lock , reg_flags ) ;
if ( ! _il_grab_nic_access ( il ) ) {
_il_wr_prph ( il , addr , val ) ;
_il_release_nic_access ( il ) ;
}
spin_unlock_irqrestore ( & il - > reg_lock , reg_flags ) ;
}
EXPORT_SYMBOL ( il_wr_prph ) ;
u32
il_read_targ_mem ( struct il_priv * il , u32 addr )
{
unsigned long reg_flags ;
u32 value ;
spin_lock_irqsave ( & il - > reg_lock , reg_flags ) ;
_il_grab_nic_access ( il ) ;
_il_wr ( il , HBUS_TARG_MEM_RADDR , addr ) ;
rmb ( ) ;
value = _il_rd ( il , HBUS_TARG_MEM_RDAT ) ;
_il_release_nic_access ( il ) ;
spin_unlock_irqrestore ( & il - > reg_lock , reg_flags ) ;
return value ;
}
EXPORT_SYMBOL ( il_read_targ_mem ) ;
void
il_write_targ_mem ( struct il_priv * il , u32 addr , u32 val )
{
unsigned long reg_flags ;
spin_lock_irqsave ( & il - > reg_lock , reg_flags ) ;
if ( ! _il_grab_nic_access ( il ) ) {
_il_wr ( il , HBUS_TARG_MEM_WADDR , addr ) ;
wmb ( ) ;
_il_wr ( il , HBUS_TARG_MEM_WDAT , val ) ;
_il_release_nic_access ( il ) ;
}
spin_unlock_irqrestore ( & il - > reg_lock , reg_flags ) ;
}
EXPORT_SYMBOL ( il_write_targ_mem ) ;
2011-11-15 14:45:59 +01:00
const char *
il_get_cmd_string ( u8 cmd )
2011-11-15 13:40:15 +01:00
{
switch ( cmd ) {
IL_CMD ( N_ALIVE ) ;
IL_CMD ( N_ERROR ) ;
IL_CMD ( C_RXON ) ;
IL_CMD ( C_RXON_ASSOC ) ;
IL_CMD ( C_QOS_PARAM ) ;
IL_CMD ( C_RXON_TIMING ) ;
IL_CMD ( C_ADD_STA ) ;
IL_CMD ( C_REM_STA ) ;
IL_CMD ( C_WEPKEY ) ;
IL_CMD ( N_3945_RX ) ;
IL_CMD ( C_TX ) ;
IL_CMD ( C_RATE_SCALE ) ;
IL_CMD ( C_LEDS ) ;
IL_CMD ( C_TX_LINK_QUALITY_CMD ) ;
IL_CMD ( C_CHANNEL_SWITCH ) ;
IL_CMD ( N_CHANNEL_SWITCH ) ;
IL_CMD ( C_SPECTRUM_MEASUREMENT ) ;
IL_CMD ( N_SPECTRUM_MEASUREMENT ) ;
IL_CMD ( C_POWER_TBL ) ;
IL_CMD ( N_PM_SLEEP ) ;
IL_CMD ( N_PM_DEBUG_STATS ) ;
IL_CMD ( C_SCAN ) ;
IL_CMD ( C_SCAN_ABORT ) ;
IL_CMD ( N_SCAN_START ) ;
IL_CMD ( N_SCAN_RESULTS ) ;
IL_CMD ( N_SCAN_COMPLETE ) ;
IL_CMD ( N_BEACON ) ;
IL_CMD ( C_TX_BEACON ) ;
IL_CMD ( C_TX_PWR_TBL ) ;
IL_CMD ( C_BT_CONFIG ) ;
IL_CMD ( C_STATS ) ;
IL_CMD ( N_STATS ) ;
IL_CMD ( N_CARD_STATE ) ;
IL_CMD ( N_MISSED_BEACONS ) ;
IL_CMD ( C_CT_KILL_CONFIG ) ;
IL_CMD ( C_SENSITIVITY ) ;
IL_CMD ( C_PHY_CALIBRATION ) ;
IL_CMD ( N_RX_PHY ) ;
IL_CMD ( N_RX_MPDU ) ;
IL_CMD ( N_RX ) ;
IL_CMD ( N_COMPRESSED_BA ) ;
default :
return " UNKNOWN " ;
}
}
EXPORT_SYMBOL ( il_get_cmd_string ) ;
# define HOST_COMPLETE_TIMEOUT (HZ / 2)
2011-11-15 14:45:59 +01:00
static void
il_generic_cmd_callback ( struct il_priv * il , struct il_device_cmd * cmd ,
struct il_rx_pkt * pkt )
2011-11-15 13:40:15 +01:00
{
if ( pkt - > hdr . flags & IL_CMD_FAILED_MSK ) {
IL_ERR ( " Bad return from %s (0x%08X) \n " ,
2011-11-15 14:45:59 +01:00
il_get_cmd_string ( cmd - > hdr . cmd ) , pkt - > hdr . flags ) ;
2011-11-15 13:40:15 +01:00
return ;
}
# ifdef CONFIG_IWLEGACY_DEBUG
switch ( cmd - > hdr . cmd ) {
case C_TX_LINK_QUALITY_CMD :
case C_SENSITIVITY :
D_HC_DUMP ( " back from %s (0x%08X) \n " ,
2011-11-15 14:45:59 +01:00
il_get_cmd_string ( cmd - > hdr . cmd ) , pkt - > hdr . flags ) ;
2011-11-15 13:40:15 +01:00
break ;
default :
2011-11-15 14:45:59 +01:00
D_HC ( " back from %s (0x%08X) \n " , il_get_cmd_string ( cmd - > hdr . cmd ) ,
pkt - > hdr . flags ) ;
2011-11-15 13:40:15 +01:00
}
# endif
}
static int
il_send_cmd_async ( struct il_priv * il , struct il_host_cmd * cmd )
{
int ret ;
BUG_ON ( ! ( cmd - > flags & CMD_ASYNC ) ) ;
/* An asynchronous command can not expect an SKB to be set. */
BUG_ON ( cmd - > flags & CMD_WANT_SKB ) ;
/* Assign a generic callback if one is not provided */
if ( ! cmd - > callback )
cmd - > callback = il_generic_cmd_callback ;
if ( test_bit ( S_EXIT_PENDING , & il - > status ) )
return - EBUSY ;
ret = il_enqueue_hcmd ( il , cmd ) ;
if ( ret < 0 ) {
IL_ERR ( " Error sending %s: enqueue_hcmd failed: %d \n " ,
2011-11-15 14:45:59 +01:00
il_get_cmd_string ( cmd - > id ) , ret ) ;
2011-11-15 13:40:15 +01:00
return ret ;
}
return 0 ;
}
2011-11-15 14:45:59 +01:00
int
il_send_cmd_sync ( struct il_priv * il , struct il_host_cmd * cmd )
2011-11-15 13:40:15 +01:00
{
int cmd_idx ;
int ret ;
lockdep_assert_held ( & il - > mutex ) ;
BUG_ON ( cmd - > flags & CMD_ASYNC ) ;
2011-11-15 14:45:59 +01:00
/* A synchronous command can not have a callback set. */
2011-11-15 13:40:15 +01:00
BUG_ON ( cmd - > callback ) ;
D_INFO ( " Attempting to send sync command %s \n " ,
2011-11-15 14:45:59 +01:00
il_get_cmd_string ( cmd - > id ) ) ;
2011-11-15 13:40:15 +01:00
set_bit ( S_HCMD_ACTIVE , & il - > status ) ;
D_INFO ( " Setting HCMD_ACTIVE for command %s \n " ,
2011-11-15 14:45:59 +01:00
il_get_cmd_string ( cmd - > id ) ) ;
2011-11-15 13:40:15 +01:00
cmd_idx = il_enqueue_hcmd ( il , cmd ) ;
if ( cmd_idx < 0 ) {
ret = cmd_idx ;
IL_ERR ( " Error sending %s: enqueue_hcmd failed: %d \n " ,
2011-11-15 14:45:59 +01:00
il_get_cmd_string ( cmd - > id ) , ret ) ;
2011-11-15 13:40:15 +01:00
goto out ;
}
ret = wait_event_timeout ( il - > wait_command_queue ,
2011-11-15 14:45:59 +01:00
! test_bit ( S_HCMD_ACTIVE , & il - > status ) ,
HOST_COMPLETE_TIMEOUT ) ;
2011-11-15 13:40:15 +01:00
if ( ! ret ) {
if ( test_bit ( S_HCMD_ACTIVE , & il - > status ) ) {
2011-11-15 14:45:59 +01:00
IL_ERR ( " Error sending %s: time out after %dms. \n " ,
il_get_cmd_string ( cmd - > id ) ,
jiffies_to_msecs ( HOST_COMPLETE_TIMEOUT ) ) ;
2011-11-15 13:40:15 +01:00
clear_bit ( S_HCMD_ACTIVE , & il - > status ) ;
2011-11-15 14:45:59 +01:00
D_INFO ( " Clearing HCMD_ACTIVE for command %s \n " ,
il_get_cmd_string ( cmd - > id ) ) ;
2011-11-15 13:40:15 +01:00
ret = - ETIMEDOUT ;
goto cancel ;
}
}
if ( test_bit ( S_RF_KILL_HW , & il - > status ) ) {
IL_ERR ( " Command %s aborted: RF KILL Switch \n " ,
2011-11-15 14:45:59 +01:00
il_get_cmd_string ( cmd - > id ) ) ;
2011-11-15 13:40:15 +01:00
ret = - ECANCELED ;
goto fail ;
}
if ( test_bit ( S_FW_ERROR , & il - > status ) ) {
IL_ERR ( " Command %s failed: FW Error \n " ,
2011-11-15 14:45:59 +01:00
il_get_cmd_string ( cmd - > id ) ) ;
2011-11-15 13:40:15 +01:00
ret = - EIO ;
goto fail ;
}
if ( ( cmd - > flags & CMD_WANT_SKB ) & & ! cmd - > reply_page ) {
IL_ERR ( " Error: Response NULL in '%s' \n " ,
2011-11-15 14:45:59 +01:00
il_get_cmd_string ( cmd - > id ) ) ;
2011-11-15 13:40:15 +01:00
ret = - EIO ;
goto cancel ;
}
ret = 0 ;
goto out ;
cancel :
if ( cmd - > flags & CMD_WANT_SKB ) {
/*
* Cancel the CMD_WANT_SKB flag for the cmd in the
* TX cmd queue . Otherwise in case the cmd comes
* in later , it will possibly set an invalid
* address ( cmd - > meta . source ) .
*/
2011-11-15 14:45:59 +01:00
il - > txq [ il - > cmd_queue ] . meta [ cmd_idx ] . flags & = ~ CMD_WANT_SKB ;
2011-11-15 13:40:15 +01:00
}
fail :
if ( cmd - > reply_page ) {
il_free_pages ( il , cmd - > reply_page ) ;
cmd - > reply_page = 0 ;
}
out :
return ret ;
}
EXPORT_SYMBOL ( il_send_cmd_sync ) ;
2011-11-15 14:45:59 +01:00
int
il_send_cmd ( struct il_priv * il , struct il_host_cmd * cmd )
2011-11-15 13:40:15 +01:00
{
if ( cmd - > flags & CMD_ASYNC )
return il_send_cmd_async ( il , cmd ) ;
return il_send_cmd_sync ( il , cmd ) ;
}
EXPORT_SYMBOL ( il_send_cmd ) ;
int
il_send_cmd_pdu ( struct il_priv * il , u8 id , u16 len , const void * data )
{
struct il_host_cmd cmd = {
. id = id ,
. len = len ,
. data = data ,
} ;
return il_send_cmd_sync ( il , & cmd ) ;
}
EXPORT_SYMBOL ( il_send_cmd_pdu ) ;
2011-11-15 14:45:59 +01:00
int
il_send_cmd_pdu_async ( struct il_priv * il , u8 id , u16 len , const void * data ,
2011-11-15 14:51:01 +01:00
void ( * callback ) ( struct il_priv * il ,
struct il_device_cmd * cmd ,
struct il_rx_pkt * pkt ) )
2011-11-15 13:40:15 +01:00
{
struct il_host_cmd cmd = {
. id = id ,
. len = len ,
. data = data ,
} ;
cmd . flags | = CMD_ASYNC ;
cmd . callback = callback ;
return il_send_cmd_async ( il , & cmd ) ;
}
EXPORT_SYMBOL ( il_send_cmd_pdu_async ) ;
/* default: IL_LED_BLINK(0) using blinking idx table */
static int led_mode ;
module_param ( led_mode , int , S_IRUGO ) ;
2011-11-15 14:45:59 +01:00
MODULE_PARM_DESC ( led_mode ,
" 0=system default, " " 1=On(RF On)/Off(RF Off), 2=blinking " ) ;
2011-11-15 13:40:15 +01:00
/* Throughput OFF time(ms) ON time (ms)
* > 300 25 25
* > 200 to 300 40 40
* > 100 to 200 55 55
* > 70 to 100 65 65
* > 50 to 70 75 75
* > 20 to 50 85 85
* > 10 to 20 95 95
* > 5 to 10 110 110
* > 1 to 5 130 130
* > 0 to 1 167 167
* < = 0 SOLID ON
*/
static const struct ieee80211_tpt_blink il_blink [ ] = {
2011-11-15 14:51:01 +01:00
{ . throughput = 0 , . blink_time = 334 } ,
{ . throughput = 1 * 1024 - 1 , . blink_time = 260 } ,
{ . throughput = 5 * 1024 - 1 , . blink_time = 220 } ,
{ . throughput = 10 * 1024 - 1 , . blink_time = 190 } ,
{ . throughput = 20 * 1024 - 1 , . blink_time = 170 } ,
{ . throughput = 50 * 1024 - 1 , . blink_time = 150 } ,
{ . throughput = 70 * 1024 - 1 , . blink_time = 130 } ,
{ . throughput = 100 * 1024 - 1 , . blink_time = 110 } ,
{ . throughput = 200 * 1024 - 1 , . blink_time = 80 } ,
{ . throughput = 300 * 1024 - 1 , . blink_time = 50 } ,
2011-11-15 13:40:15 +01:00
} ;
/*
* Adjust led blink rate to compensate on a MAC Clock difference on every HW
* Led blink rate analysis showed an average deviation of 0 % on 3945 ,
* 5 % on 4965 HW .
* Need to compensate on the led on / off time per HW according to the deviation
* to achieve the desired led frequency
* The calculation is : ( 100 - averageDeviation ) / 100 * blinkTime
* For code efficiency the calculation will be :
* compensation = ( 100 - averageDeviation ) * 64 / 100
* NewBlinkTime = ( compensation * BlinkTime ) / 64
*/
2011-11-15 14:45:59 +01:00
static inline u8
il_blink_compensation ( struct il_priv * il , u8 time , u16 compensation )
2011-11-15 13:40:15 +01:00
{
if ( ! compensation ) {
IL_ERR ( " undefined blink compensation: "
2011-11-15 14:45:59 +01:00
" use pre-defined blinking time \n " ) ;
2011-11-15 13:40:15 +01:00
return time ;
}
2011-11-15 14:45:59 +01:00
return ( u8 ) ( ( time * compensation ) > > 6 ) ;
2011-11-15 13:40:15 +01:00
}
/* Set led pattern command */
2011-11-15 14:45:59 +01:00
static int
il_led_cmd ( struct il_priv * il , unsigned long on , unsigned long off )
2011-11-15 13:40:15 +01:00
{
struct il_led_cmd led_cmd = {
. id = IL_LED_LINK ,
. interval = IL_DEF_LED_INTRVL
} ;
int ret ;
if ( ! test_bit ( S_READY , & il - > status ) )
return - EBUSY ;
if ( il - > blink_on = = on & & il - > blink_off = = off )
return 0 ;
if ( off = = 0 ) {
/* led is SOLID_ON */
on = IL_LED_SOLID ;
}
D_LED ( " Led blink time compensation=%u \n " ,
2011-11-15 14:45:59 +01:00
il - > cfg - > base_params - > led_compensation ) ;
led_cmd . on =
il_blink_compensation ( il , on ,
il - > cfg - > base_params - > led_compensation ) ;
led_cmd . off =
il_blink_compensation ( il , off ,
il - > cfg - > base_params - > led_compensation ) ;
2011-11-15 13:40:15 +01:00
ret = il - > cfg - > ops - > led - > cmd ( il , & led_cmd ) ;
if ( ! ret ) {
il - > blink_on = on ;
il - > blink_off = off ;
}
return ret ;
}
2011-11-15 14:45:59 +01:00
static void
il_led_brightness_set ( struct led_classdev * led_cdev ,
enum led_brightness brightness )
2011-11-15 13:40:15 +01:00
{
struct il_priv * il = container_of ( led_cdev , struct il_priv , led ) ;
unsigned long on = 0 ;
if ( brightness > 0 )
on = IL_LED_SOLID ;
il_led_cmd ( il , on , 0 ) ;
}
2011-11-15 14:45:59 +01:00
static int
il_led_blink_set ( struct led_classdev * led_cdev , unsigned long * delay_on ,
unsigned long * delay_off )
2011-11-15 13:40:15 +01:00
{
struct il_priv * il = container_of ( led_cdev , struct il_priv , led ) ;
return il_led_cmd ( il , * delay_on , * delay_off ) ;
}
2011-11-15 14:45:59 +01:00
void
il_leds_init ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
int mode = led_mode ;
int ret ;
if ( mode = = IL_LED_DEFAULT )
mode = il - > cfg - > led_mode ;
2011-11-15 14:45:59 +01:00
il - > led . name =
kasprintf ( GFP_KERNEL , " %s-led " , wiphy_name ( il - > hw - > wiphy ) ) ;
2011-11-15 13:40:15 +01:00
il - > led . brightness_set = il_led_brightness_set ;
il - > led . blink_set = il_led_blink_set ;
il - > led . max_brightness = 1 ;
switch ( mode ) {
case IL_LED_DEFAULT :
WARN_ON ( 1 ) ;
break ;
case IL_LED_BLINK :
il - > led . default_trigger =
2011-11-15 14:45:59 +01:00
ieee80211_create_tpt_led_trigger ( il - > hw ,
IEEE80211_TPT_LEDTRIG_FL_CONNECTED ,
il_blink ,
ARRAY_SIZE ( il_blink ) ) ;
2011-11-15 13:40:15 +01:00
break ;
case IL_LED_RF_STATE :
2011-11-15 14:45:59 +01:00
il - > led . default_trigger = ieee80211_get_radio_led_name ( il - > hw ) ;
2011-11-15 13:40:15 +01:00
break ;
}
ret = led_classdev_register ( & il - > pci_dev - > dev , & il - > led ) ;
if ( ret ) {
kfree ( il - > led . name ) ;
return ;
}
il - > led_registered = true ;
}
EXPORT_SYMBOL ( il_leds_init ) ;
2011-11-15 14:45:59 +01:00
void
il_leds_exit ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
if ( ! il - > led_registered )
return ;
led_classdev_unregister ( & il - > led ) ;
kfree ( il - > led . name ) ;
}
EXPORT_SYMBOL ( il_leds_exit ) ;
/************************** EEPROM BANDS ****************************
*
* The il_eeprom_band definitions below provide the mapping from the
* EEPROM contents to the specific channel number supported for each
* band .
*
* For example , il_priv - > eeprom . band_3_channels [ 4 ] from the band_3
* definition below maps to physical channel 42 in the 5.2 GHz spectrum .
* The specific geography and calibration information for that channel
* is contained in the eeprom map itself .
*
* During init , we copy the eeprom information and channel map
* information into il - > channel_info_24 / 52 and il - > channel_map_24 / 52
*
* channel_map_24 / 52 provides the idx in the channel_info array for a
* given channel . We have to have two separate maps as there is channel
* overlap with the 2.4 GHz and 5.2 GHz spectrum as seen in band_1 and
* band_2
*
* A value of 0xff stored in the channel_map indicates that the channel
* is not supported by the hardware at all .
*
* A value of 0xfe in the channel_map indicates that the channel is not
* valid for Tx with the current hardware . This means that
* while the system can tune and receive on a given channel , it may not
* be able to associate or transmit any frames on that
* channel . There is no corresponding channel information for that
* entry .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* 2.4 GHz */
const u8 il_eeprom_band_1 [ 14 ] = {
1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14
} ;
/* 5.2 GHz bands */
static const u8 il_eeprom_band_2 [ ] = { /* 4915-5080MHz */
183 , 184 , 185 , 187 , 188 , 189 , 192 , 196 , 7 , 8 , 11 , 12 , 16
} ;
static const u8 il_eeprom_band_3 [ ] = { /* 5170-5320MHz */
34 , 36 , 38 , 40 , 42 , 44 , 46 , 48 , 52 , 56 , 60 , 64
} ;
static const u8 il_eeprom_band_4 [ ] = { /* 5500-5700MHz */
100 , 104 , 108 , 112 , 116 , 120 , 124 , 128 , 132 , 136 , 140
} ;
static const u8 il_eeprom_band_5 [ ] = { /* 5725-5825MHz */
145 , 149 , 153 , 157 , 161 , 165
} ;
2011-11-15 14:45:59 +01:00
static const u8 il_eeprom_band_6 [ ] = { /* 2.4 ht40 channel */
2011-11-15 13:40:15 +01:00
1 , 2 , 3 , 4 , 5 , 6 , 7
} ;
2011-11-15 14:45:59 +01:00
static const u8 il_eeprom_band_7 [ ] = { /* 5.2 ht40 channel */
2011-11-15 13:40:15 +01:00
36 , 44 , 52 , 60 , 100 , 108 , 116 , 124 , 132 , 149 , 157
} ;
/******************************************************************************
*
* EEPROM related functions
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-11-15 14:45:59 +01:00
static int
il_eeprom_verify_signature ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
u32 gp = _il_rd ( il , CSR_EEPROM_GP ) & CSR_EEPROM_GP_VALID_MSK ;
int ret = 0 ;
D_EEPROM ( " EEPROM signature=0x%08x \n " , gp ) ;
switch ( gp ) {
case CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K :
case CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K :
break ;
default :
2011-11-15 14:45:59 +01:00
IL_ERR ( " bad EEPROM signature, " " EEPROM_GP=0x%08x \n " , gp ) ;
2011-11-15 13:40:15 +01:00
ret = - ENOENT ;
break ;
}
return ret ;
}
2011-11-15 14:45:59 +01:00
const u8 *
il_eeprom_query_addr ( const struct il_priv * il , size_t offset )
2011-11-15 13:40:15 +01:00
{
BUG_ON ( offset > = il - > cfg - > base_params - > eeprom_size ) ;
return & il - > eeprom [ offset ] ;
}
EXPORT_SYMBOL ( il_eeprom_query_addr ) ;
2011-11-15 14:45:59 +01:00
u16
2011-11-15 14:51:01 +01:00
il_eeprom_query16 ( const struct il_priv * il , size_t offset )
2011-11-15 13:40:15 +01:00
{
if ( ! il - > eeprom )
return 0 ;
2011-11-15 14:45:59 +01:00
return ( u16 ) il - > eeprom [ offset ] | ( ( u16 ) il - > eeprom [ offset + 1 ] < < 8 ) ;
2011-11-15 13:40:15 +01:00
}
EXPORT_SYMBOL ( il_eeprom_query16 ) ;
/**
* il_eeprom_init - read EEPROM contents
*
* Load the EEPROM contents from adapter into il - > eeprom
*
* NOTE : This routine uses the non - debug IO access functions .
*/
2011-11-15 14:45:59 +01:00
int
il_eeprom_init ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
__le16 * e ;
u32 gp = _il_rd ( il , CSR_EEPROM_GP ) ;
int sz ;
int ret ;
u16 addr ;
/* allocate eeprom */
sz = il - > cfg - > base_params - > eeprom_size ;
D_EEPROM ( " NVM size = %d \n " , sz ) ;
il - > eeprom = kzalloc ( sz , GFP_KERNEL ) ;
if ( ! il - > eeprom ) {
ret = - ENOMEM ;
goto alloc_err ;
}
2011-11-15 14:45:59 +01:00
e = ( __le16 * ) il - > eeprom ;
2011-11-15 13:40:15 +01:00
il - > cfg - > ops - > lib - > apm_ops . init ( il ) ;
ret = il_eeprom_verify_signature ( il ) ;
if ( ret < 0 ) {
IL_ERR ( " EEPROM not found, EEPROM_GP=0x%08x \n " , gp ) ;
ret = - ENOENT ;
goto err ;
}
/* Make sure driver (instead of uCode) is allowed to read EEPROM */
ret = il - > cfg - > ops - > lib - > eeprom_ops . acquire_semaphore ( il ) ;
if ( ret < 0 ) {
IL_ERR ( " Failed to acquire EEPROM semaphore. \n " ) ;
ret = - ENOENT ;
goto err ;
}
/* eeprom is an array of 16bit values */
for ( addr = 0 ; addr < sz ; addr + = sizeof ( u16 ) ) {
u32 r ;
_il_wr ( il , CSR_EEPROM_REG ,
2011-11-15 14:45:59 +01:00
CSR_EEPROM_REG_MSK_ADDR & ( addr < < 1 ) ) ;
2011-11-15 13:40:15 +01:00
2011-11-15 14:45:59 +01:00
ret =
_il_poll_bit ( il , CSR_EEPROM_REG ,
CSR_EEPROM_REG_READ_VALID_MSK ,
CSR_EEPROM_REG_READ_VALID_MSK ,
IL_EEPROM_ACCESS_TIMEOUT ) ;
2011-11-15 13:40:15 +01:00
if ( ret < 0 ) {
2011-11-15 14:45:59 +01:00
IL_ERR ( " Time out reading EEPROM[%d] \n " , addr ) ;
2011-11-15 13:40:15 +01:00
goto done ;
}
r = _il_rd ( il , CSR_EEPROM_REG ) ;
e [ addr / 2 ] = cpu_to_le16 ( r > > 16 ) ;
}
2011-11-15 14:45:59 +01:00
D_EEPROM ( " NVM Type: %s, version: 0x%x \n " , " EEPROM " ,
il_eeprom_query16 ( il , EEPROM_VERSION ) ) ;
2011-11-15 13:40:15 +01:00
ret = 0 ;
done :
il - > cfg - > ops - > lib - > eeprom_ops . release_semaphore ( il ) ;
err :
if ( ret )
il_eeprom_free ( il ) ;
/* Reset chip to save power until we load uCode during "up". */
il_apm_stop ( il ) ;
alloc_err :
return ret ;
}
EXPORT_SYMBOL ( il_eeprom_init ) ;
2011-11-15 14:45:59 +01:00
void
il_eeprom_free ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
kfree ( il - > eeprom ) ;
il - > eeprom = NULL ;
}
EXPORT_SYMBOL ( il_eeprom_free ) ;
2011-11-15 14:45:59 +01:00
static void
il_init_band_reference ( const struct il_priv * il , int eep_band ,
int * eeprom_ch_count ,
const struct il_eeprom_channel * * eeprom_ch_info ,
2011-11-15 14:51:01 +01:00
const u8 * * eeprom_ch_idx )
2011-11-15 13:40:15 +01:00
{
2011-11-15 14:45:59 +01:00
u32 offset =
il - > cfg - > ops - > lib - > eeprom_ops . regulatory_bands [ eep_band - 1 ] ;
2011-11-15 13:40:15 +01:00
switch ( eep_band ) {
case 1 : /* 2.4GHz band */
* eeprom_ch_count = ARRAY_SIZE ( il_eeprom_band_1 ) ;
2011-11-15 14:45:59 +01:00
* eeprom_ch_info =
( struct il_eeprom_channel * ) il_eeprom_query_addr ( il ,
offset ) ;
2011-11-15 13:40:15 +01:00
* eeprom_ch_idx = il_eeprom_band_1 ;
break ;
case 2 : /* 4.9GHz band */
* eeprom_ch_count = ARRAY_SIZE ( il_eeprom_band_2 ) ;
2011-11-15 14:45:59 +01:00
* eeprom_ch_info =
( struct il_eeprom_channel * ) il_eeprom_query_addr ( il ,
offset ) ;
2011-11-15 13:40:15 +01:00
* eeprom_ch_idx = il_eeprom_band_2 ;
break ;
case 3 : /* 5.2GHz band */
* eeprom_ch_count = ARRAY_SIZE ( il_eeprom_band_3 ) ;
2011-11-15 14:45:59 +01:00
* eeprom_ch_info =
( struct il_eeprom_channel * ) il_eeprom_query_addr ( il ,
offset ) ;
2011-11-15 13:40:15 +01:00
* eeprom_ch_idx = il_eeprom_band_3 ;
break ;
case 4 : /* 5.5GHz band */
* eeprom_ch_count = ARRAY_SIZE ( il_eeprom_band_4 ) ;
2011-11-15 14:45:59 +01:00
* eeprom_ch_info =
( struct il_eeprom_channel * ) il_eeprom_query_addr ( il ,
offset ) ;
2011-11-15 13:40:15 +01:00
* eeprom_ch_idx = il_eeprom_band_4 ;
break ;
case 5 : /* 5.7GHz band */
* eeprom_ch_count = ARRAY_SIZE ( il_eeprom_band_5 ) ;
2011-11-15 14:45:59 +01:00
* eeprom_ch_info =
( struct il_eeprom_channel * ) il_eeprom_query_addr ( il ,
offset ) ;
2011-11-15 13:40:15 +01:00
* eeprom_ch_idx = il_eeprom_band_5 ;
break ;
case 6 : /* 2.4GHz ht40 channels */
* eeprom_ch_count = ARRAY_SIZE ( il_eeprom_band_6 ) ;
2011-11-15 14:45:59 +01:00
* eeprom_ch_info =
( struct il_eeprom_channel * ) il_eeprom_query_addr ( il ,
offset ) ;
2011-11-15 13:40:15 +01:00
* eeprom_ch_idx = il_eeprom_band_6 ;
break ;
case 7 : /* 5 GHz ht40 channels */
* eeprom_ch_count = ARRAY_SIZE ( il_eeprom_band_7 ) ;
2011-11-15 14:45:59 +01:00
* eeprom_ch_info =
( struct il_eeprom_channel * ) il_eeprom_query_addr ( il ,
offset ) ;
2011-11-15 13:40:15 +01:00
* eeprom_ch_idx = il_eeprom_band_7 ;
break ;
default :
BUG ( ) ;
}
}
# define CHECK_AND_PRINT(x) ((eeprom_ch->flags & EEPROM_CHANNEL_##x) \
? # x " " : " " )
/**
* il_mod_ht40_chan_info - Copy ht40 channel info into driver ' s il .
*
* Does not set up a command , or touch hardware .
*/
2011-11-15 14:45:59 +01:00
static int
il_mod_ht40_chan_info ( struct il_priv * il , enum ieee80211_band band , u16 channel ,
const struct il_eeprom_channel * eeprom_ch ,
u8 clear_ht40_extension_channel )
2011-11-15 13:40:15 +01:00
{
struct il_channel_info * ch_info ;
2011-11-15 14:45:59 +01:00
ch_info =
( struct il_channel_info * ) il_get_channel_info ( il , band , channel ) ;
2011-11-15 13:40:15 +01:00
if ( ! il_is_channel_valid ( ch_info ) )
return - 1 ;
D_EEPROM ( " HT40 Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm): "
2011-11-15 14:45:59 +01:00
" Ad-Hoc %ssupported \n " , ch_info - > channel ,
il_is_channel_a_band ( ch_info ) ? " 5.2 " : " 2.4 " ,
CHECK_AND_PRINT ( IBSS ) , CHECK_AND_PRINT ( ACTIVE ) ,
CHECK_AND_PRINT ( RADAR ) , CHECK_AND_PRINT ( WIDE ) ,
CHECK_AND_PRINT ( DFS ) , eeprom_ch - > flags ,
eeprom_ch - > max_power_avg ,
( ( eeprom_ch - > flags & EEPROM_CHANNEL_IBSS ) & &
! ( eeprom_ch - > flags & EEPROM_CHANNEL_RADAR ) ) ? " " : " not " ) ;
2011-11-15 13:40:15 +01:00
ch_info - > ht40_eeprom = * eeprom_ch ;
ch_info - > ht40_max_power_avg = eeprom_ch - > max_power_avg ;
ch_info - > ht40_flags = eeprom_ch - > flags ;
if ( eeprom_ch - > flags & EEPROM_CHANNEL_VALID )
ch_info - > ht40_extension_channel & =
2011-11-15 14:45:59 +01:00
~ clear_ht40_extension_channel ;
2011-11-15 13:40:15 +01:00
return 0 ;
}
# define CHECK_AND_PRINT_I(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
? # x " " : " " )
/**
* il_init_channel_map - Set up driver ' s info for all possible channels
*/
2011-11-15 14:45:59 +01:00
int
il_init_channel_map ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
int eeprom_ch_count = 0 ;
const u8 * eeprom_ch_idx = NULL ;
const struct il_eeprom_channel * eeprom_ch_info = NULL ;
int band , ch ;
struct il_channel_info * ch_info ;
if ( il - > channel_count ) {
D_EEPROM ( " Channel map already initialized. \n " ) ;
return 0 ;
}
D_EEPROM ( " Initializing regulatory info from EEPROM \n " ) ;
il - > channel_count =
2011-11-15 14:45:59 +01:00
ARRAY_SIZE ( il_eeprom_band_1 ) + ARRAY_SIZE ( il_eeprom_band_2 ) +
ARRAY_SIZE ( il_eeprom_band_3 ) + ARRAY_SIZE ( il_eeprom_band_4 ) +
2011-11-15 13:40:15 +01:00
ARRAY_SIZE ( il_eeprom_band_5 ) ;
2011-11-15 14:45:59 +01:00
D_EEPROM ( " Parsing data for %d channels. \n " , il - > channel_count ) ;
2011-11-15 13:40:15 +01:00
2011-11-15 14:45:59 +01:00
il - > channel_info =
kzalloc ( sizeof ( struct il_channel_info ) * il - > channel_count ,
GFP_KERNEL ) ;
2011-11-15 13:40:15 +01:00
if ( ! il - > channel_info ) {
IL_ERR ( " Could not allocate channel_info \n " ) ;
il - > channel_count = 0 ;
return - ENOMEM ;
}
ch_info = il - > channel_info ;
/* Loop through the 5 EEPROM bands adding them in order to the
* channel map we maintain ( that contains additional information than
* what just in the EEPROM ) */
for ( band = 1 ; band < = 5 ; band + + ) {
il_init_band_reference ( il , band , & eeprom_ch_count ,
2011-11-15 14:45:59 +01:00
& eeprom_ch_info , & eeprom_ch_idx ) ;
2011-11-15 13:40:15 +01:00
/* Loop through each band adding each of the channels */
for ( ch = 0 ; ch < eeprom_ch_count ; ch + + ) {
ch_info - > channel = eeprom_ch_idx [ ch ] ;
2011-11-15 14:45:59 +01:00
ch_info - > band =
( band = =
1 ) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ ;
2011-11-15 13:40:15 +01:00
/* permanently store EEPROM's channel regulatory flags
* and max power in channel info database . */
ch_info - > eeprom = eeprom_ch_info [ ch ] ;
/* Copy the run-time flags so they are there even on
* invalid channels */
ch_info - > flags = eeprom_ch_info [ ch ] . flags ;
/* First write that ht40 is not enabled, and then enable
* one by one */
ch_info - > ht40_extension_channel =
2011-11-15 14:45:59 +01:00
IEEE80211_CHAN_NO_HT40 ;
2011-11-15 13:40:15 +01:00
if ( ! ( il_is_channel_valid ( ch_info ) ) ) {
2011-11-15 14:45:59 +01:00
D_EEPROM ( " Ch. %d Flags %x [%sGHz] - "
" No traffic \n " , ch_info - > channel ,
ch_info - > flags ,
il_is_channel_a_band ( ch_info ) ? " 5.2 " :
" 2.4 " ) ;
2011-11-15 13:40:15 +01:00
ch_info + + ;
continue ;
}
/* Initialize regulatory-based run-time data */
ch_info - > max_power_avg = ch_info - > curr_txpow =
eeprom_ch_info [ ch ] . max_power_avg ;
ch_info - > scan_power = eeprom_ch_info [ ch ] . max_power_avg ;
ch_info - > min_power = 0 ;
2011-11-15 14:45:59 +01:00
D_EEPROM ( " Ch. %d [%sGHz] " " %s%s%s%s%s%s(0x%02x %ddBm): "
" Ad-Hoc %ssupported \n " , ch_info - > channel ,
il_is_channel_a_band ( ch_info ) ? " 5.2 " : " 2.4 " ,
CHECK_AND_PRINT_I ( VALID ) ,
CHECK_AND_PRINT_I ( IBSS ) ,
CHECK_AND_PRINT_I ( ACTIVE ) ,
CHECK_AND_PRINT_I ( RADAR ) ,
CHECK_AND_PRINT_I ( WIDE ) ,
CHECK_AND_PRINT_I ( DFS ) ,
eeprom_ch_info [ ch ] . flags ,
eeprom_ch_info [ ch ] . max_power_avg ,
( ( eeprom_ch_info [ ch ] .
flags & EEPROM_CHANNEL_IBSS ) & &
! ( eeprom_ch_info [ ch ] .
flags & EEPROM_CHANNEL_RADAR ) ) ? " " :
" not " ) ;
2011-11-15 13:40:15 +01:00
ch_info + + ;
}
}
/* Check if we do have HT40 channels */
if ( il - > cfg - > ops - > lib - > eeprom_ops . regulatory_bands [ 5 ] = =
EEPROM_REGULATORY_BAND_NO_HT40 & &
il - > cfg - > ops - > lib - > eeprom_ops . regulatory_bands [ 6 ] = =
EEPROM_REGULATORY_BAND_NO_HT40 )
return 0 ;
/* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */
for ( band = 6 ; band < = 7 ; band + + ) {
enum ieee80211_band ieeeband ;
il_init_band_reference ( il , band , & eeprom_ch_count ,
2011-11-15 14:45:59 +01:00
& eeprom_ch_info , & eeprom_ch_idx ) ;
2011-11-15 13:40:15 +01:00
/* EEPROM band 6 is 2.4, band 7 is 5 GHz */
ieeeband =
2011-11-15 14:45:59 +01:00
( band = = 6 ) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ ;
2011-11-15 13:40:15 +01:00
/* Loop through each band adding each of the channels */
for ( ch = 0 ; ch < eeprom_ch_count ; ch + + ) {
/* Set up driver's info for lower half */
2011-11-15 14:45:59 +01:00
il_mod_ht40_chan_info ( il , ieeeband , eeprom_ch_idx [ ch ] ,
& eeprom_ch_info [ ch ] ,
IEEE80211_CHAN_NO_HT40PLUS ) ;
2011-11-15 13:40:15 +01:00
/* Set up driver's info for upper half */
il_mod_ht40_chan_info ( il , ieeeband ,
2011-11-15 14:45:59 +01:00
eeprom_ch_idx [ ch ] + 4 ,
& eeprom_ch_info [ ch ] ,
IEEE80211_CHAN_NO_HT40MINUS ) ;
2011-11-15 13:40:15 +01:00
}
}
return 0 ;
}
EXPORT_SYMBOL ( il_init_channel_map ) ;
/*
* il_free_channel_map - undo allocations in il_init_channel_map
*/
2011-11-15 14:45:59 +01:00
void
il_free_channel_map ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
kfree ( il - > channel_info ) ;
il - > channel_count = 0 ;
}
EXPORT_SYMBOL ( il_free_channel_map ) ;
/**
* il_get_channel_info - Find driver ' s ilate channel info
*
* Based on band and channel number .
*/
2011-11-15 14:45:59 +01:00
const struct il_channel_info *
il_get_channel_info ( const struct il_priv * il , enum ieee80211_band band ,
u16 channel )
2011-11-15 13:40:15 +01:00
{
int i ;
switch ( band ) {
case IEEE80211_BAND_5GHZ :
for ( i = 14 ; i < il - > channel_count ; i + + ) {
if ( il - > channel_info [ i ] . channel = = channel )
return & il - > channel_info [ i ] ;
}
break ;
case IEEE80211_BAND_2GHZ :
if ( channel > = 1 & & channel < = 14 )
return & il - > channel_info [ channel - 1 ] ;
break ;
default :
BUG ( ) ;
}
return NULL ;
}
EXPORT_SYMBOL ( il_get_channel_info ) ;
/*
* Setting power level allows the card to go to sleep when not busy .
*
* We calculate a sleep command based on the required latency , which
* we get from mac80211 . In order to handle thermal throttling , we can
* also use pre - defined power levels .
*/
/*
* This defines the old power levels . They are still used by default
* ( level 1 ) and for thermal throttle ( levels 3 through 5 )
*/
struct il_power_vec_entry {
struct il_powertable_cmd cmd ;
2011-11-15 14:45:59 +01:00
u8 no_dtim ; /* number of skip dtim */
2011-11-15 13:40:15 +01:00
} ;
2011-11-15 14:45:59 +01:00
static void
il_power_sleep_cam_cmd ( struct il_priv * il , struct il_powertable_cmd * cmd )
2011-11-15 13:40:15 +01:00
{
memset ( cmd , 0 , sizeof ( * cmd ) ) ;
if ( il - > power_data . pci_pm )
cmd - > flags | = IL_POWER_PCI_PM_MSK ;
D_POWER ( " Sleep command for CAM \n " ) ;
}
static int
il_set_power ( struct il_priv * il , struct il_powertable_cmd * cmd )
{
D_POWER ( " Sending power/sleep command \n " ) ;
D_POWER ( " Flags value = 0x%08X \n " , cmd - > flags ) ;
2011-11-15 14:45:59 +01:00
D_POWER ( " Tx timeout = %u \n " , le32_to_cpu ( cmd - > tx_data_timeout ) ) ;
D_POWER ( " Rx timeout = %u \n " , le32_to_cpu ( cmd - > rx_data_timeout ) ) ;
D_POWER ( " Sleep interval vector = { %d , %d , %d , %d , %d } \n " ,
le32_to_cpu ( cmd - > sleep_interval [ 0 ] ) ,
le32_to_cpu ( cmd - > sleep_interval [ 1 ] ) ,
le32_to_cpu ( cmd - > sleep_interval [ 2 ] ) ,
le32_to_cpu ( cmd - > sleep_interval [ 3 ] ) ,
le32_to_cpu ( cmd - > sleep_interval [ 4 ] ) ) ;
2011-11-15 13:40:15 +01:00
return il_send_cmd_pdu ( il , C_POWER_TBL ,
2011-11-15 14:45:59 +01:00
sizeof ( struct il_powertable_cmd ) , cmd ) ;
2011-11-15 13:40:15 +01:00
}
int
2011-11-15 14:45:59 +01:00
il_power_set_mode ( struct il_priv * il , struct il_powertable_cmd * cmd , bool force )
2011-11-15 13:40:15 +01:00
{
int ret ;
bool update_chains ;
lockdep_assert_held ( & il - > mutex ) ;
/* Don't update the RX chain when chain noise calibration is running */
update_chains = il - > chain_noise_data . state = = IL_CHAIN_NOISE_DONE | |
2011-11-15 14:45:59 +01:00
il - > chain_noise_data . state = = IL_CHAIN_NOISE_ALIVE ;
2011-11-15 13:40:15 +01:00
if ( ! memcmp ( & il - > power_data . sleep_cmd , cmd , sizeof ( * cmd ) ) & & ! force )
return 0 ;
if ( ! il_is_ready_rf ( il ) )
return - EIO ;
/* scan complete use sleep_power_next, need to be updated */
memcpy ( & il - > power_data . sleep_cmd_next , cmd , sizeof ( * cmd ) ) ;
if ( test_bit ( S_SCANNING , & il - > status ) & & ! force ) {
D_INFO ( " Defer power set mode while scanning \n " ) ;
return 0 ;
}
if ( cmd - > flags & IL_POWER_DRIVER_ALLOW_SLEEP_MSK )
set_bit ( S_POWER_PMI , & il - > status ) ;
ret = il_set_power ( il , cmd ) ;
if ( ! ret ) {
if ( ! ( cmd - > flags & IL_POWER_DRIVER_ALLOW_SLEEP_MSK ) )
clear_bit ( S_POWER_PMI , & il - > status ) ;
if ( il - > cfg - > ops - > lib - > update_chain_flags & & update_chains )
il - > cfg - > ops - > lib - > update_chain_flags ( il ) ;
else if ( il - > cfg - > ops - > lib - > update_chain_flags )
2011-11-15 14:45:59 +01:00
D_POWER ( " Cannot update the power, chain noise "
" calibration running: %d \n " ,
il - > chain_noise_data . state ) ;
2011-11-15 13:40:15 +01:00
memcpy ( & il - > power_data . sleep_cmd , cmd , sizeof ( * cmd ) ) ;
} else
IL_ERR ( " set power fail, ret = %d " , ret ) ;
return ret ;
}
2011-11-15 14:45:59 +01:00
int
il_power_update_mode ( struct il_priv * il , bool force )
2011-11-15 13:40:15 +01:00
{
struct il_powertable_cmd cmd ;
il_power_sleep_cam_cmd ( il , & cmd ) ;
return il_power_set_mode ( il , & cmd , force ) ;
}
EXPORT_SYMBOL ( il_power_update_mode ) ;
/* initialize to default */
2011-11-15 14:45:59 +01:00
void
il_power_initialize ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
u16 lctl = il_pcie_link_ctl ( il ) ;
il - > power_data . pci_pm = ! ( lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN ) ;
il - > power_data . debug_sleep_level_override = - 1 ;
2011-11-15 14:45:59 +01:00
memset ( & il - > power_data . sleep_cmd , 0 , sizeof ( il - > power_data . sleep_cmd ) ) ;
2011-11-15 13:40:15 +01:00
}
EXPORT_SYMBOL ( il_power_initialize ) ;
/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
* sending probe req . This should be set long enough to hear probe responses
* from more than one AP . */
2011-11-15 14:45:59 +01:00
# define IL_ACTIVE_DWELL_TIME_24 (30) /* all times in msec */
2011-11-15 13:40:15 +01:00
# define IL_ACTIVE_DWELL_TIME_52 (20)
# define IL_ACTIVE_DWELL_FACTOR_24GHZ (3)
# define IL_ACTIVE_DWELL_FACTOR_52GHZ (2)
/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
* Must be set longer than active dwell time .
* For the most reliable scan , set > AP beacon interval ( typically 100 msec ) . */
2011-11-15 14:45:59 +01:00
# define IL_PASSIVE_DWELL_TIME_24 (20) /* all times in msec */
2011-11-15 13:40:15 +01:00
# define IL_PASSIVE_DWELL_TIME_52 (10)
# define IL_PASSIVE_DWELL_BASE (100)
# define IL_CHANNEL_TUNE_TIME 5
2011-11-15 14:45:59 +01:00
static int
il_send_scan_abort ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
int ret ;
struct il_rx_pkt * pkt ;
struct il_host_cmd cmd = {
. id = C_SCAN_ABORT ,
. flags = CMD_WANT_SKB ,
} ;
/* Exit instantly with error when device is not ready
* to receive scan abort command or it does not perform
* hardware scan currently */
if ( ! test_bit ( S_READY , & il - > status ) | |
! test_bit ( S_GEO_CONFIGURED , & il - > status ) | |
! test_bit ( S_SCAN_HW , & il - > status ) | |
test_bit ( S_FW_ERROR , & il - > status ) | |
test_bit ( S_EXIT_PENDING , & il - > status ) )
return - EIO ;
ret = il_send_cmd_sync ( il , & cmd ) ;
if ( ret )
return ret ;
pkt = ( struct il_rx_pkt * ) cmd . reply_page ;
if ( pkt - > u . status ! = CAN_ABORT_STATUS ) {
/* The scan abort will return 1 for success or
* 2 for " failure " . A failure condition can be
* due to simply not being in an active scan which
* can occur if we send the scan abort before we
* the microcode has notified us that a scan is
* completed . */
D_SCAN ( " SCAN_ABORT ret %d. \n " , pkt - > u . status ) ;
ret = - EIO ;
}
il_free_pages ( il , cmd . reply_page ) ;
return ret ;
}
2011-11-15 14:45:59 +01:00
static void
il_complete_scan ( struct il_priv * il , bool aborted )
2011-11-15 13:40:15 +01:00
{
/* check if scan was requested from mac80211 */
if ( il - > scan_request ) {
D_SCAN ( " Complete scan in mac80211 \n " ) ;
ieee80211_scan_completed ( il - > hw , aborted ) ;
}
il - > scan_vif = NULL ;
il - > scan_request = NULL ;
}
2011-11-15 14:45:59 +01:00
void
il_force_scan_end ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
lockdep_assert_held ( & il - > mutex ) ;
if ( ! test_bit ( S_SCANNING , & il - > status ) ) {
D_SCAN ( " Forcing scan end while not scanning \n " ) ;
return ;
}
D_SCAN ( " Forcing scan end \n " ) ;
clear_bit ( S_SCANNING , & il - > status ) ;
clear_bit ( S_SCAN_HW , & il - > status ) ;
clear_bit ( S_SCAN_ABORTING , & il - > status ) ;
il_complete_scan ( il , true ) ;
}
2011-11-15 14:45:59 +01:00
static void
il_do_scan_abort ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
int ret ;
lockdep_assert_held ( & il - > mutex ) ;
if ( ! test_bit ( S_SCANNING , & il - > status ) ) {
D_SCAN ( " Not performing scan to abort \n " ) ;
return ;
}
if ( test_and_set_bit ( S_SCAN_ABORTING , & il - > status ) ) {
D_SCAN ( " Scan abort in progress \n " ) ;
return ;
}
ret = il_send_scan_abort ( il ) ;
if ( ret ) {
D_SCAN ( " Send scan abort failed %d \n " , ret ) ;
il_force_scan_end ( il ) ;
} else
D_SCAN ( " Successfully send scan abort \n " ) ;
}
/**
* il_scan_cancel - Cancel any currently executing HW scan
*/
2011-11-15 14:45:59 +01:00
int
il_scan_cancel ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
D_SCAN ( " Queuing abort scan \n " ) ;
queue_work ( il - > workqueue , & il - > abort_scan ) ;
return 0 ;
}
EXPORT_SYMBOL ( il_scan_cancel ) ;
/**
* il_scan_cancel_timeout - Cancel any currently executing HW scan
* @ ms : amount of time to wait ( in milliseconds ) for scan to abort
*
*/
2011-11-15 14:45:59 +01:00
int
il_scan_cancel_timeout ( struct il_priv * il , unsigned long ms )
2011-11-15 13:40:15 +01:00
{
unsigned long timeout = jiffies + msecs_to_jiffies ( ms ) ;
lockdep_assert_held ( & il - > mutex ) ;
D_SCAN ( " Scan cancel timeout \n " ) ;
il_do_scan_abort ( il ) ;
while ( time_before_eq ( jiffies , timeout ) ) {
if ( ! test_bit ( S_SCAN_HW , & il - > status ) )
break ;
msleep ( 20 ) ;
}
return test_bit ( S_SCAN_HW , & il - > status ) ;
}
EXPORT_SYMBOL ( il_scan_cancel_timeout ) ;
/* Service response to C_SCAN (0x80) */
2011-11-15 14:45:59 +01:00
static void
il_hdl_scan ( struct il_priv * il , struct il_rx_buf * rxb )
2011-11-15 13:40:15 +01:00
{
# ifdef CONFIG_IWLEGACY_DEBUG
struct il_rx_pkt * pkt = rxb_addr ( rxb ) ;
struct il_scanreq_notification * notif =
( struct il_scanreq_notification * ) pkt - > u . raw ;
D_SCAN ( " Scan request status = 0x%x \n " , notif - > status ) ;
# endif
}
/* Service N_SCAN_START (0x82) */
2011-11-15 14:45:59 +01:00
static void
il_hdl_scan_start ( struct il_priv * il , struct il_rx_buf * rxb )
2011-11-15 13:40:15 +01:00
{
struct il_rx_pkt * pkt = rxb_addr ( rxb ) ;
struct il_scanstart_notification * notif =
( struct il_scanstart_notification * ) pkt - > u . raw ;
il - > scan_start_tsf = le32_to_cpu ( notif - > tsf_low ) ;
2011-11-15 14:45:59 +01:00
D_SCAN ( " Scan start: " " %d [802.11%s] "
" (TSF: 0x%08X:%08X) - %d (beacon timer %u) \n " , notif - > channel ,
notif - > band ? " bg " : " a " , le32_to_cpu ( notif - > tsf_high ) ,
le32_to_cpu ( notif - > tsf_low ) , notif - > status , notif - > beacon_timer ) ;
2011-11-15 13:40:15 +01:00
}
/* Service N_SCAN_RESULTS (0x83) */
2011-11-15 14:45:59 +01:00
static void
il_hdl_scan_results ( struct il_priv * il , struct il_rx_buf * rxb )
2011-11-15 13:40:15 +01:00
{
# ifdef CONFIG_IWLEGACY_DEBUG
struct il_rx_pkt * pkt = rxb_addr ( rxb ) ;
struct il_scanresults_notification * notif =
( struct il_scanresults_notification * ) pkt - > u . raw ;
2011-11-15 14:45:59 +01:00
D_SCAN ( " Scan ch.res: " " %d [802.11%s] " " (TSF: 0x%08X:%08X) - %d "
" elapsed=%lu usec \n " , notif - > channel , notif - > band ? " bg " : " a " ,
le32_to_cpu ( notif - > tsf_high ) , le32_to_cpu ( notif - > tsf_low ) ,
le32_to_cpu ( notif - > stats [ 0 ] ) ,
le32_to_cpu ( notif - > tsf_low ) - il - > scan_start_tsf ) ;
2011-11-15 13:40:15 +01:00
# endif
}
/* Service N_SCAN_COMPLETE (0x84) */
2011-11-15 14:45:59 +01:00
static void
il_hdl_scan_complete ( struct il_priv * il , struct il_rx_buf * rxb )
2011-11-15 13:40:15 +01:00
{
# ifdef CONFIG_IWLEGACY_DEBUG
struct il_rx_pkt * pkt = rxb_addr ( rxb ) ;
struct il_scancomplete_notification * scan_notif = ( void * ) pkt - > u . raw ;
# endif
2011-11-15 14:45:59 +01:00
D_SCAN ( " Scan complete: %d channels (TSF 0x%08X:%08X) - %d \n " ,
scan_notif - > scanned_channels , scan_notif - > tsf_low ,
scan_notif - > tsf_high , scan_notif - > status ) ;
2011-11-15 13:40:15 +01:00
/* The HW is no longer scanning */
clear_bit ( S_SCAN_HW , & il - > status ) ;
D_SCAN ( " Scan on %sGHz took %dms \n " ,
2011-11-15 14:45:59 +01:00
( il - > scan_band = = IEEE80211_BAND_2GHZ ) ? " 2.4 " : " 5.2 " ,
jiffies_to_msecs ( jiffies - il - > scan_start ) ) ;
2011-11-15 13:40:15 +01:00
queue_work ( il - > workqueue , & il - > scan_completed ) ;
}
2011-11-15 14:45:59 +01:00
void
il_setup_rx_scan_handlers ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
/* scan handlers */
il - > handlers [ C_SCAN ] = il_hdl_scan ;
2011-11-15 14:45:59 +01:00
il - > handlers [ N_SCAN_START ] = il_hdl_scan_start ;
il - > handlers [ N_SCAN_RESULTS ] = il_hdl_scan_results ;
il - > handlers [ N_SCAN_COMPLETE ] = il_hdl_scan_complete ;
2011-11-15 13:40:15 +01:00
}
EXPORT_SYMBOL ( il_setup_rx_scan_handlers ) ;
2011-11-15 14:45:59 +01:00
inline u16
il_get_active_dwell_time ( struct il_priv * il , enum ieee80211_band band ,
u8 n_probes )
2011-11-15 13:40:15 +01:00
{
if ( band = = IEEE80211_BAND_5GHZ )
return IL_ACTIVE_DWELL_TIME_52 +
2011-11-15 14:45:59 +01:00
IL_ACTIVE_DWELL_FACTOR_52GHZ * ( n_probes + 1 ) ;
2011-11-15 13:40:15 +01:00
else
return IL_ACTIVE_DWELL_TIME_24 +
2011-11-15 14:45:59 +01:00
IL_ACTIVE_DWELL_FACTOR_24GHZ * ( n_probes + 1 ) ;
2011-11-15 13:40:15 +01:00
}
EXPORT_SYMBOL ( il_get_active_dwell_time ) ;
2011-11-15 14:45:59 +01:00
u16
2011-11-15 14:51:01 +01:00
il_get_passive_dwell_time ( struct il_priv * il , enum ieee80211_band band ,
struct ieee80211_vif * vif )
2011-11-15 13:40:15 +01:00
{
u16 value ;
2011-11-15 14:45:59 +01:00
u16 passive =
( band = =
IEEE80211_BAND_2GHZ ) ? IL_PASSIVE_DWELL_BASE +
IL_PASSIVE_DWELL_TIME_24 : IL_PASSIVE_DWELL_BASE +
IL_PASSIVE_DWELL_TIME_52 ;
2011-11-15 13:40:15 +01:00
if ( il_is_any_associated ( il ) ) {
/*
* If we ' re associated , we clamp the maximum passive
* dwell time to be 98 % of the smallest beacon interval
* ( minus 2 * channel tune time )
*/
2012-02-03 17:31:57 +01:00
value = il - > vif ? il - > vif - > bss_conf . beacon_int : 0 ;
2011-11-15 13:40:15 +01:00
if ( value > IL_PASSIVE_DWELL_BASE | | ! value )
value = IL_PASSIVE_DWELL_BASE ;
value = ( value * 98 ) / 100 - IL_CHANNEL_TUNE_TIME * 2 ;
passive = min ( value , passive ) ;
}
return passive ;
}
EXPORT_SYMBOL ( il_get_passive_dwell_time ) ;
2011-11-15 14:45:59 +01:00
void
il_init_scan_params ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
u8 ant_idx = fls ( il - > hw_params . valid_tx_ant ) - 1 ;
if ( ! il - > scan_tx_ant [ IEEE80211_BAND_5GHZ ] )
il - > scan_tx_ant [ IEEE80211_BAND_5GHZ ] = ant_idx ;
if ( ! il - > scan_tx_ant [ IEEE80211_BAND_2GHZ ] )
il - > scan_tx_ant [ IEEE80211_BAND_2GHZ ] = ant_idx ;
}
EXPORT_SYMBOL ( il_init_scan_params ) ;
2011-11-15 14:45:59 +01:00
static int
il_scan_initiate ( struct il_priv * il , struct ieee80211_vif * vif )
2011-11-15 13:40:15 +01:00
{
int ret ;
lockdep_assert_held ( & il - > mutex ) ;
if ( WARN_ON ( ! il - > cfg - > ops - > utils - > request_scan ) )
return - EOPNOTSUPP ;
cancel_delayed_work ( & il - > scan_check ) ;
if ( ! il_is_ready_rf ( il ) ) {
IL_WARN ( " Request scan called when driver not ready. \n " ) ;
return - EIO ;
}
if ( test_bit ( S_SCAN_HW , & il - > status ) ) {
2011-11-15 14:45:59 +01:00
D_SCAN ( " Multiple concurrent scan requests in parallel. \n " ) ;
2011-11-15 13:40:15 +01:00
return - EBUSY ;
}
if ( test_bit ( S_SCAN_ABORTING , & il - > status ) ) {
D_SCAN ( " Scan request while abort pending. \n " ) ;
return - EBUSY ;
}
D_SCAN ( " Starting scan... \n " ) ;
set_bit ( S_SCANNING , & il - > status ) ;
il - > scan_start = jiffies ;
ret = il - > cfg - > ops - > utils - > request_scan ( il , vif ) ;
if ( ret ) {
clear_bit ( S_SCANNING , & il - > status ) ;
return ret ;
}
queue_delayed_work ( il - > workqueue , & il - > scan_check ,
IL_SCAN_CHECK_WATCHDOG ) ;
return 0 ;
}
2011-11-15 14:45:59 +01:00
int
il_mac_hw_scan ( struct ieee80211_hw * hw , struct ieee80211_vif * vif ,
struct cfg80211_scan_request * req )
2011-11-15 13:40:15 +01:00
{
struct il_priv * il = hw - > priv ;
int ret ;
D_MAC80211 ( " enter \n " ) ;
if ( req - > n_channels = = 0 )
return - EINVAL ;
mutex_lock ( & il - > mutex ) ;
if ( test_bit ( S_SCANNING , & il - > status ) ) {
D_SCAN ( " Scan already in progress. \n " ) ;
ret = - EAGAIN ;
goto out_unlock ;
}
/* mac80211 will only ask for one band at a time */
il - > scan_request = req ;
il - > scan_vif = vif ;
il - > scan_band = req - > channels [ 0 ] - > band ;
ret = il_scan_initiate ( il , vif ) ;
D_MAC80211 ( " leave \n " ) ;
out_unlock :
mutex_unlock ( & il - > mutex ) ;
return ret ;
}
EXPORT_SYMBOL ( il_mac_hw_scan ) ;
2011-11-15 14:45:59 +01:00
static void
il_bg_scan_check ( struct work_struct * data )
2011-11-15 13:40:15 +01:00
{
struct il_priv * il =
container_of ( data , struct il_priv , scan_check . work ) ;
D_SCAN ( " Scan check work \n " ) ;
/* Since we are here firmware does not finish scan and
* most likely is in bad shape , so we don ' t bother to
* send abort command , just force scan complete to mac80211 */
mutex_lock ( & il - > mutex ) ;
il_force_scan_end ( il ) ;
mutex_unlock ( & il - > mutex ) ;
}
/**
* il_fill_probe_req - fill in all required fields and IE for probe request
*/
u16
il_fill_probe_req ( struct il_priv * il , struct ieee80211_mgmt * frame ,
2011-11-15 14:51:01 +01:00
const u8 * ta , const u8 * ies , int ie_len , int left )
2011-11-15 13:40:15 +01:00
{
int len = 0 ;
u8 * pos = NULL ;
/* Make sure there is enough space for the probe request,
* two mandatory IEs and the data */
left - = 24 ;
if ( left < 0 )
return 0 ;
frame - > frame_control = cpu_to_le16 ( IEEE80211_STYPE_PROBE_REQ ) ;
memcpy ( frame - > da , il_bcast_addr , ETH_ALEN ) ;
memcpy ( frame - > sa , ta , ETH_ALEN ) ;
memcpy ( frame - > bssid , il_bcast_addr , ETH_ALEN ) ;
frame - > seq_ctrl = 0 ;
len + = 24 ;
/* ...next IE... */
pos = & frame - > u . probe_req . variable [ 0 ] ;
/* fill in our indirect SSID IE */
left - = 2 ;
if ( left < 0 )
return 0 ;
* pos + + = WLAN_EID_SSID ;
* pos + + = 0 ;
len + = 2 ;
if ( WARN_ON ( left < ie_len ) )
return len ;
if ( ies & & ie_len ) {
memcpy ( pos , ies , ie_len ) ;
len + = ie_len ;
}
2011-11-15 14:45:59 +01:00
return ( u16 ) len ;
2011-11-15 13:40:15 +01:00
}
EXPORT_SYMBOL ( il_fill_probe_req ) ;
2011-11-15 14:45:59 +01:00
static void
il_bg_abort_scan ( struct work_struct * work )
2011-11-15 13:40:15 +01:00
{
struct il_priv * il = container_of ( work , struct il_priv , abort_scan ) ;
D_SCAN ( " Abort scan work \n " ) ;
/* We keep scan_check work queued in case when firmware will not
* report back scan completed notification */
mutex_lock ( & il - > mutex ) ;
il_scan_cancel_timeout ( il , 200 ) ;
mutex_unlock ( & il - > mutex ) ;
}
2011-11-15 14:45:59 +01:00
static void
il_bg_scan_completed ( struct work_struct * work )
2011-11-15 13:40:15 +01:00
{
2011-11-15 14:45:59 +01:00
struct il_priv * il = container_of ( work , struct il_priv , scan_completed ) ;
2011-11-15 13:40:15 +01:00
bool aborted ;
D_SCAN ( " Completed scan. \n " ) ;
cancel_delayed_work ( & il - > scan_check ) ;
mutex_lock ( & il - > mutex ) ;
aborted = test_and_clear_bit ( S_SCAN_ABORTING , & il - > status ) ;
if ( aborted )
D_SCAN ( " Aborted scan completed. \n " ) ;
if ( ! test_and_clear_bit ( S_SCANNING , & il - > status ) ) {
D_SCAN ( " Scan already completed. \n " ) ;
goto out_settings ;
}
il_complete_scan ( il , aborted ) ;
out_settings :
/* Can we still talk to firmware ? */
if ( ! il_is_ready_rf ( il ) )
goto out ;
/*
* We do not commit power settings while scan is pending ,
* do it now if the settings changed .
*/
il_power_set_mode ( il , & il - > power_data . sleep_cmd_next , false ) ;
il_set_tx_power ( il , il - > tx_power_next , false ) ;
il - > cfg - > ops - > utils - > post_scan ( il ) ;
out :
mutex_unlock ( & il - > mutex ) ;
}
2011-11-15 14:45:59 +01:00
void
il_setup_scan_deferred_work ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
INIT_WORK ( & il - > scan_completed , il_bg_scan_completed ) ;
INIT_WORK ( & il - > abort_scan , il_bg_abort_scan ) ;
INIT_DELAYED_WORK ( & il - > scan_check , il_bg_scan_check ) ;
}
EXPORT_SYMBOL ( il_setup_scan_deferred_work ) ;
2011-11-15 14:45:59 +01:00
void
il_cancel_scan_deferred_work ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
cancel_work_sync ( & il - > abort_scan ) ;
cancel_work_sync ( & il - > scan_completed ) ;
if ( cancel_delayed_work_sync ( & il - > scan_check ) ) {
mutex_lock ( & il - > mutex ) ;
il_force_scan_end ( il ) ;
mutex_unlock ( & il - > mutex ) ;
}
}
EXPORT_SYMBOL ( il_cancel_scan_deferred_work ) ;
/* il->sta_lock must be held */
2011-11-15 14:45:59 +01:00
static void
il_sta_ucode_activate ( struct il_priv * il , u8 sta_id )
2011-11-15 13:40:15 +01:00
{
if ( ! ( il - > stations [ sta_id ] . used & IL_STA_DRIVER_ACTIVE ) )
2011-11-15 14:45:59 +01:00
IL_ERR ( " ACTIVATE a non DRIVER active station id %u addr %pM \n " ,
sta_id , il - > stations [ sta_id ] . sta . sta . addr ) ;
2011-11-15 13:40:15 +01:00
if ( il - > stations [ sta_id ] . used & IL_STA_UCODE_ACTIVE ) {
2011-11-15 14:45:59 +01:00
D_ASSOC ( " STA id %u addr %pM already present "
" in uCode (according to driver) \n " , sta_id ,
il - > stations [ sta_id ] . sta . sta . addr ) ;
2011-11-15 13:40:15 +01:00
} else {
il - > stations [ sta_id ] . used | = IL_STA_UCODE_ACTIVE ;
2011-11-15 14:45:59 +01:00
D_ASSOC ( " Added STA id %u addr %pM to uCode \n " , sta_id ,
il - > stations [ sta_id ] . sta . sta . addr ) ;
2011-11-15 13:40:15 +01:00
}
}
2011-11-15 14:45:59 +01:00
static int
il_process_add_sta_resp ( struct il_priv * il , struct il_addsta_cmd * addsta ,
struct il_rx_pkt * pkt , bool sync )
2011-11-15 13:40:15 +01:00
{
u8 sta_id = addsta - > sta . sta_id ;
unsigned long flags ;
int ret = - EIO ;
if ( pkt - > hdr . flags & IL_CMD_FAILED_MSK ) {
2011-11-15 14:45:59 +01:00
IL_ERR ( " Bad return from C_ADD_STA (0x%08X) \n " , pkt - > hdr . flags ) ;
2011-11-15 13:40:15 +01:00
return ret ;
}
2011-11-15 14:45:59 +01:00
D_INFO ( " Processing response for adding station %u \n " , sta_id ) ;
2011-11-15 13:40:15 +01:00
spin_lock_irqsave ( & il - > sta_lock , flags ) ;
switch ( pkt - > u . add_sta . status ) {
case ADD_STA_SUCCESS_MSK :
D_INFO ( " C_ADD_STA PASSED \n " ) ;
il_sta_ucode_activate ( il , sta_id ) ;
ret = 0 ;
break ;
case ADD_STA_NO_ROOM_IN_TBL :
2011-11-15 14:45:59 +01:00
IL_ERR ( " Adding station %d failed, no room in table. \n " , sta_id ) ;
2011-11-15 13:40:15 +01:00
break ;
case ADD_STA_NO_BLOCK_ACK_RESOURCE :
2011-11-15 14:45:59 +01:00
IL_ERR ( " Adding station %d failed, no block ack resource. \n " ,
sta_id ) ;
2011-11-15 13:40:15 +01:00
break ;
case ADD_STA_MODIFY_NON_EXIST_STA :
IL_ERR ( " Attempting to modify non-existing station %d \n " ,
2011-11-15 14:45:59 +01:00
sta_id ) ;
2011-11-15 13:40:15 +01:00
break ;
default :
2011-11-15 14:45:59 +01:00
D_ASSOC ( " Received C_ADD_STA:(0x%08X) \n " , pkt - > u . add_sta . status ) ;
2011-11-15 13:40:15 +01:00
break ;
}
D_INFO ( " %s station id %u addr %pM \n " ,
2011-11-15 14:45:59 +01:00
il - > stations [ sta_id ] . sta . mode = =
STA_CONTROL_MODIFY_MSK ? " Modified " : " Added " , sta_id ,
il - > stations [ sta_id ] . sta . sta . addr ) ;
2011-11-15 13:40:15 +01:00
/*
* XXX : The MAC address in the command buffer is often changed from
* the original sent to the device . That is , the MAC address
* written to the command buffer often is not the same MAC address
* read from the command buffer when the command returns . This
* issue has not yet been resolved and this debugging is left to
* observe the problem .
*/
D_INFO ( " %s station according to cmd buffer %pM \n " ,
2011-11-15 14:45:59 +01:00
il - > stations [ sta_id ] . sta . mode = =
STA_CONTROL_MODIFY_MSK ? " Modified " : " Added " , addsta - > sta . addr ) ;
2011-11-15 13:40:15 +01:00
spin_unlock_irqrestore ( & il - > sta_lock , flags ) ;
return ret ;
}
2011-11-15 14:45:59 +01:00
static void
il_add_sta_callback ( struct il_priv * il , struct il_device_cmd * cmd ,
struct il_rx_pkt * pkt )
2011-11-15 13:40:15 +01:00
{
2011-11-15 14:45:59 +01:00
struct il_addsta_cmd * addsta = ( struct il_addsta_cmd * ) cmd - > cmd . payload ;
2011-11-15 13:40:15 +01:00
il_process_add_sta_resp ( il , addsta , pkt , false ) ;
}
2011-11-15 14:45:59 +01:00
int
il_send_add_sta ( struct il_priv * il , struct il_addsta_cmd * sta , u8 flags )
2011-11-15 13:40:15 +01:00
{
struct il_rx_pkt * pkt = NULL ;
int ret = 0 ;
u8 data [ sizeof ( * sta ) ] ;
struct il_host_cmd cmd = {
. id = C_ADD_STA ,
. flags = flags ,
. data = data ,
} ;
u8 sta_id __maybe_unused = sta - > sta . sta_id ;
2011-11-15 14:45:59 +01:00
D_INFO ( " Adding sta %u (%pM) %ssynchronously \n " , sta_id , sta - > sta . addr ,
flags & CMD_ASYNC ? " a " : " " ) ;
2011-11-15 13:40:15 +01:00
if ( flags & CMD_ASYNC )
cmd . callback = il_add_sta_callback ;
else {
cmd . flags | = CMD_WANT_SKB ;
might_sleep ( ) ;
}
cmd . len = il - > cfg - > ops - > utils - > build_addsta_hcmd ( sta , data ) ;
ret = il_send_cmd ( il , & cmd ) ;
if ( ret | | ( flags & CMD_ASYNC ) )
return ret ;
if ( ret = = 0 ) {
pkt = ( struct il_rx_pkt * ) cmd . reply_page ;
ret = il_process_add_sta_resp ( il , sta , pkt , true ) ;
}
il_free_pages ( il , cmd . reply_page ) ;
return ret ;
}
EXPORT_SYMBOL ( il_send_add_sta ) ;
2011-11-15 14:45:59 +01:00
static void
2012-02-03 17:31:57 +01:00
il_set_ht_add_station ( struct il_priv * il , u8 idx , struct ieee80211_sta * sta )
2011-11-15 13:40:15 +01:00
{
struct ieee80211_sta_ht_cap * sta_ht_inf = & sta - > ht_cap ;
__le32 sta_flags ;
u8 mimo_ps_mode ;
if ( ! sta | | ! sta_ht_inf - > ht_supported )
goto done ;
mimo_ps_mode = ( sta_ht_inf - > cap & IEEE80211_HT_CAP_SM_PS ) > > 2 ;
D_ASSOC ( " spatial multiplexing power save mode: %s \n " ,
2011-11-15 14:51:01 +01:00
( mimo_ps_mode = = WLAN_HT_CAP_SM_PS_STATIC ) ? " static " :
( mimo_ps_mode = = WLAN_HT_CAP_SM_PS_DYNAMIC ) ? " dynamic " :
" disabled " ) ;
2011-11-15 13:40:15 +01:00
sta_flags = il - > stations [ idx ] . sta . station_flags ;
sta_flags & = ~ ( STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK ) ;
switch ( mimo_ps_mode ) {
case WLAN_HT_CAP_SM_PS_STATIC :
sta_flags | = STA_FLG_MIMO_DIS_MSK ;
break ;
case WLAN_HT_CAP_SM_PS_DYNAMIC :
sta_flags | = STA_FLG_RTS_MIMO_PROT_MSK ;
break ;
case WLAN_HT_CAP_SM_PS_DISABLED :
break ;
default :
IL_WARN ( " Invalid MIMO PS mode %d \n " , mimo_ps_mode ) ;
break ;
}
2011-11-15 14:45:59 +01:00
sta_flags | =
cpu_to_le32 ( ( u32 ) sta_ht_inf - >
ampdu_factor < < STA_FLG_MAX_AGG_SIZE_POS ) ;
2011-11-15 13:40:15 +01:00
2011-11-15 14:45:59 +01:00
sta_flags | =
cpu_to_le32 ( ( u32 ) sta_ht_inf - >
ampdu_density < < STA_FLG_AGG_MPDU_DENSITY_POS ) ;
2011-11-15 13:40:15 +01:00
2012-02-03 17:31:57 +01:00
if ( il_is_ht40_tx_allowed ( il , & sta - > ht_cap ) )
2011-11-15 13:40:15 +01:00
sta_flags | = STA_FLG_HT40_EN_MSK ;
else
sta_flags & = ~ STA_FLG_HT40_EN_MSK ;
il - > stations [ idx ] . sta . station_flags = sta_flags ;
2011-11-15 14:45:59 +01:00
done :
2011-11-15 13:40:15 +01:00
return ;
}
/**
* il_prep_station - Prepare station information for addition
*
* should be called with sta_lock held
*/
2011-11-15 14:45:59 +01:00
u8
2012-02-03 17:31:57 +01:00
il_prep_station ( struct il_priv * il , const u8 * addr , bool is_ap ,
struct ieee80211_sta * sta )
2011-11-15 13:40:15 +01:00
{
struct il_station_entry * station ;
int i ;
u8 sta_id = IL_INVALID_STATION ;
u16 rate ;
if ( is_ap )
2012-02-03 17:31:43 +01:00
sta_id = IL_AP_ID ;
2011-11-15 13:40:15 +01:00
else if ( is_broadcast_ether_addr ( addr ) )
2012-02-03 17:31:44 +01:00
sta_id = il - > hw_params . bcast_id ;
2011-11-15 13:40:15 +01:00
else
for ( i = IL_STA_ID ; i < il - > hw_params . max_stations ; i + + ) {
2011-11-15 14:45:59 +01:00
if ( ! compare_ether_addr
( il - > stations [ i ] . sta . sta . addr , addr ) ) {
2011-11-15 13:40:15 +01:00
sta_id = i ;
break ;
}
if ( ! il - > stations [ i ] . used & &
sta_id = = IL_INVALID_STATION )
sta_id = i ;
}
/*
* These two conditions have the same outcome , but keep them
* separate
*/
if ( unlikely ( sta_id = = IL_INVALID_STATION ) )
return sta_id ;
/*
* uCode is not able to deal with multiple requests to add a
* station . Keep track if one is in progress so that we do not send
* another .
*/
if ( il - > stations [ sta_id ] . used & IL_STA_UCODE_INPROGRESS ) {
2011-11-15 14:45:59 +01:00
D_INFO ( " STA %d already in process of being added. \n " , sta_id ) ;
2011-11-15 13:40:15 +01:00
return sta_id ;
}
if ( ( il - > stations [ sta_id ] . used & IL_STA_DRIVER_ACTIVE ) & &
( il - > stations [ sta_id ] . used & IL_STA_UCODE_ACTIVE ) & &
! compare_ether_addr ( il - > stations [ sta_id ] . sta . sta . addr , addr ) ) {
2011-11-15 14:45:59 +01:00
D_ASSOC ( " STA %d (%pM) already added, not adding again. \n " ,
sta_id , addr ) ;
2011-11-15 13:40:15 +01:00
return sta_id ;
}
station = & il - > stations [ sta_id ] ;
station - > used = IL_STA_DRIVER_ACTIVE ;
2011-11-15 14:45:59 +01:00
D_ASSOC ( " Add STA to driver ID %d: %pM \n " , sta_id , addr ) ;
2011-11-15 13:40:15 +01:00
il - > num_stations + + ;
/* Set up the C_ADD_STA command to send to device */
memset ( & station - > sta , 0 , sizeof ( struct il_addsta_cmd ) ) ;
memcpy ( station - > sta . sta . addr , addr , ETH_ALEN ) ;
station - > sta . mode = 0 ;
station - > sta . sta . sta_id = sta_id ;
2012-02-03 17:31:49 +01:00
station - > sta . station_flags = 0 ;
2011-11-15 13:40:15 +01:00
/*
* OK to call unconditionally , since local stations ( IBSS BSSID
* STA and broadcast STA ) pass in a NULL sta , and mac80211
* doesn ' t allow HT IBSS .
*/
2012-02-03 17:31:57 +01:00
il_set_ht_add_station ( il , sta_id , sta ) ;
2011-11-15 13:40:15 +01:00
/* 3945 only */
2011-11-15 14:45:59 +01:00
rate = ( il - > band = = IEEE80211_BAND_5GHZ ) ? RATE_6M_PLCP : RATE_1M_PLCP ;
2011-11-15 13:40:15 +01:00
/* Turn on both antennas for the station... */
station - > sta . rate_n_flags = cpu_to_le16 ( rate | RATE_MCS_ANT_AB_MSK ) ;
return sta_id ;
}
EXPORT_SYMBOL_GPL ( il_prep_station ) ;
# define STA_WAIT_TIMEOUT (HZ / 2)
/**
* il_add_station_common -
*/
int
2012-02-03 17:31:57 +01:00
il_add_station_common ( struct il_priv * il , const u8 * addr , bool is_ap ,
struct ieee80211_sta * sta , u8 * sta_id_r )
2011-11-15 13:40:15 +01:00
{
unsigned long flags_spin ;
int ret = 0 ;
u8 sta_id ;
struct il_addsta_cmd sta_cmd ;
* sta_id_r = 0 ;
spin_lock_irqsave ( & il - > sta_lock , flags_spin ) ;
2012-02-03 17:31:57 +01:00
sta_id = il_prep_station ( il , addr , is_ap , sta ) ;
2011-11-15 13:40:15 +01:00
if ( sta_id = = IL_INVALID_STATION ) {
2011-11-15 14:45:59 +01:00
IL_ERR ( " Unable to prepare station %pM for addition \n " , addr ) ;
2011-11-15 13:40:15 +01:00
spin_unlock_irqrestore ( & il - > sta_lock , flags_spin ) ;
return - EINVAL ;
}
/*
* uCode is not able to deal with multiple requests to add a
* station . Keep track if one is in progress so that we do not send
* another .
*/
if ( il - > stations [ sta_id ] . used & IL_STA_UCODE_INPROGRESS ) {
2011-11-15 14:45:59 +01:00
D_INFO ( " STA %d already in process of being added. \n " , sta_id ) ;
2011-11-15 13:40:15 +01:00
spin_unlock_irqrestore ( & il - > sta_lock , flags_spin ) ;
return - EEXIST ;
}
if ( ( il - > stations [ sta_id ] . used & IL_STA_DRIVER_ACTIVE ) & &
( il - > stations [ sta_id ] . used & IL_STA_UCODE_ACTIVE ) ) {
2011-11-15 14:45:59 +01:00
D_ASSOC ( " STA %d (%pM) already added, not adding again. \n " ,
2011-11-15 13:40:15 +01:00
sta_id , addr ) ;
spin_unlock_irqrestore ( & il - > sta_lock , flags_spin ) ;
return - EEXIST ;
}
il - > stations [ sta_id ] . used | = IL_STA_UCODE_INPROGRESS ;
memcpy ( & sta_cmd , & il - > stations [ sta_id ] . sta ,
2011-11-15 14:45:59 +01:00
sizeof ( struct il_addsta_cmd ) ) ;
2011-11-15 13:40:15 +01:00
spin_unlock_irqrestore ( & il - > sta_lock , flags_spin ) ;
/* Add station to device's station table */
ret = il_send_add_sta ( il , & sta_cmd , CMD_SYNC ) ;
if ( ret ) {
spin_lock_irqsave ( & il - > sta_lock , flags_spin ) ;
IL_ERR ( " Adding station %pM failed. \n " ,
2011-11-15 14:45:59 +01:00
il - > stations [ sta_id ] . sta . sta . addr ) ;
2011-11-15 13:40:15 +01:00
il - > stations [ sta_id ] . used & = ~ IL_STA_DRIVER_ACTIVE ;
il - > stations [ sta_id ] . used & = ~ IL_STA_UCODE_INPROGRESS ;
spin_unlock_irqrestore ( & il - > sta_lock , flags_spin ) ;
}
* sta_id_r = sta_id ;
return ret ;
}
EXPORT_SYMBOL ( il_add_station_common ) ;
/**
* il_sta_ucode_deactivate - deactivate ucode status for a station
*
* il - > sta_lock must be held
*/
2011-11-15 14:45:59 +01:00
static void
il_sta_ucode_deactivate ( struct il_priv * il , u8 sta_id )
2011-11-15 13:40:15 +01:00
{
/* Ucode must be active and driver must be non active */
2011-11-15 14:45:59 +01:00
if ( ( il - > stations [ sta_id ] .
used & ( IL_STA_UCODE_ACTIVE | IL_STA_DRIVER_ACTIVE ) ) ! =
IL_STA_UCODE_ACTIVE )
2011-11-15 13:40:15 +01:00
IL_ERR ( " removed non active STA %u \n " , sta_id ) ;
il - > stations [ sta_id ] . used & = ~ IL_STA_UCODE_ACTIVE ;
memset ( & il - > stations [ sta_id ] , 0 , sizeof ( struct il_station_entry ) ) ;
D_ASSOC ( " Removed STA %u \n " , sta_id ) ;
}
2011-11-15 14:45:59 +01:00
static int
il_send_remove_station ( struct il_priv * il , const u8 * addr , int sta_id ,
bool temporary )
2011-11-15 13:40:15 +01:00
{
struct il_rx_pkt * pkt ;
int ret ;
unsigned long flags_spin ;
struct il_rem_sta_cmd rm_sta_cmd ;
struct il_host_cmd cmd = {
. id = C_REM_STA ,
. len = sizeof ( struct il_rem_sta_cmd ) ,
. flags = CMD_SYNC ,
. data = & rm_sta_cmd ,
} ;
memset ( & rm_sta_cmd , 0 , sizeof ( rm_sta_cmd ) ) ;
rm_sta_cmd . num_sta = 1 ;
memcpy ( & rm_sta_cmd . addr , addr , ETH_ALEN ) ;
cmd . flags | = CMD_WANT_SKB ;
ret = il_send_cmd ( il , & cmd ) ;
if ( ret )
return ret ;
pkt = ( struct il_rx_pkt * ) cmd . reply_page ;
if ( pkt - > hdr . flags & IL_CMD_FAILED_MSK ) {
2011-11-15 14:45:59 +01:00
IL_ERR ( " Bad return from C_REM_STA (0x%08X) \n " , pkt - > hdr . flags ) ;
2011-11-15 13:40:15 +01:00
ret = - EIO ;
}
if ( ! ret ) {
switch ( pkt - > u . rem_sta . status ) {
case REM_STA_SUCCESS_MSK :
if ( ! temporary ) {
spin_lock_irqsave ( & il - > sta_lock , flags_spin ) ;
il_sta_ucode_deactivate ( il , sta_id ) ;
spin_unlock_irqrestore ( & il - > sta_lock ,
2011-11-15 14:45:59 +01:00
flags_spin ) ;
2011-11-15 13:40:15 +01:00
}
D_ASSOC ( " C_REM_STA PASSED \n " ) ;
break ;
default :
ret = - EIO ;
IL_ERR ( " C_REM_STA failed \n " ) ;
break ;
}
}
il_free_pages ( il , cmd . reply_page ) ;
return ret ;
}
/**
* il_remove_station - Remove driver ' s knowledge of station .
*/
2011-11-15 14:45:59 +01:00
int
il_remove_station ( struct il_priv * il , const u8 sta_id , const u8 * addr )
2011-11-15 13:40:15 +01:00
{
unsigned long flags ;
if ( ! il_is_ready ( il ) ) {
2011-11-15 14:45:59 +01:00
D_INFO ( " Unable to remove station %pM, device not ready. \n " ,
addr ) ;
2011-11-15 13:40:15 +01:00
/*
* It is typical for stations to be removed when we are
* going down . Return success since device will be down
* soon anyway
*/
return 0 ;
}
2011-11-15 14:45:59 +01:00
D_ASSOC ( " Removing STA from driver:%d %pM \n " , sta_id , addr ) ;
2011-11-15 13:40:15 +01:00
if ( WARN_ON ( sta_id = = IL_INVALID_STATION ) )
return - EINVAL ;
spin_lock_irqsave ( & il - > sta_lock , flags ) ;
if ( ! ( il - > stations [ sta_id ] . used & IL_STA_DRIVER_ACTIVE ) ) {
2011-11-15 14:45:59 +01:00
D_INFO ( " Removing %pM but non DRIVER active \n " , addr ) ;
2011-11-15 13:40:15 +01:00
goto out_err ;
}
if ( ! ( il - > stations [ sta_id ] . used & IL_STA_UCODE_ACTIVE ) ) {
2011-11-15 14:45:59 +01:00
D_INFO ( " Removing %pM but non UCODE active \n " , addr ) ;
2011-11-15 13:40:15 +01:00
goto out_err ;
}
if ( il - > stations [ sta_id ] . used & IL_STA_LOCAL ) {
kfree ( il - > stations [ sta_id ] . lq ) ;
il - > stations [ sta_id ] . lq = NULL ;
}
il - > stations [ sta_id ] . used & = ~ IL_STA_DRIVER_ACTIVE ;
il - > num_stations - - ;
BUG_ON ( il - > num_stations < 0 ) ;
spin_unlock_irqrestore ( & il - > sta_lock , flags ) ;
return il_send_remove_station ( il , addr , sta_id , false ) ;
out_err :
spin_unlock_irqrestore ( & il - > sta_lock , flags ) ;
return - EINVAL ;
}
EXPORT_SYMBOL_GPL ( il_remove_station ) ;
/**
* il_clear_ucode_stations - clear ucode station table bits
*
* This function clears all the bits in the driver indicating
* which stations are active in the ucode . Call when something
* other than explicit station management would cause this in
* the ucode , e . g . unassociated RXON .
*/
2011-11-15 14:45:59 +01:00
void
2012-02-03 17:31:57 +01:00
il_clear_ucode_stations ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
int i ;
unsigned long flags_spin ;
bool cleared = false ;
D_INFO ( " Clearing ucode stations in driver \n " ) ;
spin_lock_irqsave ( & il - > sta_lock , flags_spin ) ;
for ( i = 0 ; i < il - > hw_params . max_stations ; i + + ) {
if ( il - > stations [ i ] . used & IL_STA_UCODE_ACTIVE ) {
2011-11-15 14:45:59 +01:00
D_INFO ( " Clearing ucode active for station %d \n " , i ) ;
2011-11-15 13:40:15 +01:00
il - > stations [ i ] . used & = ~ IL_STA_UCODE_ACTIVE ;
cleared = true ;
}
}
spin_unlock_irqrestore ( & il - > sta_lock , flags_spin ) ;
if ( ! cleared )
2011-11-15 14:45:59 +01:00
D_INFO ( " No active stations found to be cleared \n " ) ;
2011-11-15 13:40:15 +01:00
}
EXPORT_SYMBOL ( il_clear_ucode_stations ) ;
/**
* il_restore_stations ( ) - Restore driver known stations to device
*
* All stations considered active by driver , but not present in ucode , is
* restored .
*
* Function sleeps .
*/
void
2012-02-03 17:31:57 +01:00
il_restore_stations ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
struct il_addsta_cmd sta_cmd ;
struct il_link_quality_cmd lq ;
unsigned long flags_spin ;
int i ;
bool found = false ;
int ret ;
bool send_lq ;
if ( ! il_is_ready ( il ) ) {
2011-11-15 14:45:59 +01:00
D_INFO ( " Not ready yet, not restoring any stations. \n " ) ;
2011-11-15 13:40:15 +01:00
return ;
}
D_ASSOC ( " Restoring all known stations ... start. \n " ) ;
spin_lock_irqsave ( & il - > sta_lock , flags_spin ) ;
for ( i = 0 ; i < il - > hw_params . max_stations ; i + + ) {
if ( ( il - > stations [ i ] . used & IL_STA_DRIVER_ACTIVE ) & &
! ( il - > stations [ i ] . used & IL_STA_UCODE_ACTIVE ) ) {
D_ASSOC ( " Restoring sta %pM \n " ,
2011-11-15 14:45:59 +01:00
il - > stations [ i ] . sta . sta . addr ) ;
2011-11-15 13:40:15 +01:00
il - > stations [ i ] . sta . mode = 0 ;
il - > stations [ i ] . used | = IL_STA_UCODE_INPROGRESS ;
found = true ;
}
}
for ( i = 0 ; i < il - > hw_params . max_stations ; i + + ) {
if ( ( il - > stations [ i ] . used & IL_STA_UCODE_INPROGRESS ) ) {
memcpy ( & sta_cmd , & il - > stations [ i ] . sta ,
sizeof ( struct il_addsta_cmd ) ) ;
send_lq = false ;
if ( il - > stations [ i ] . lq ) {
memcpy ( & lq , il - > stations [ i ] . lq ,
sizeof ( struct il_link_quality_cmd ) ) ;
send_lq = true ;
}
spin_unlock_irqrestore ( & il - > sta_lock , flags_spin ) ;
ret = il_send_add_sta ( il , & sta_cmd , CMD_SYNC ) ;
if ( ret ) {
spin_lock_irqsave ( & il - > sta_lock , flags_spin ) ;
IL_ERR ( " Adding station %pM failed. \n " ,
2011-11-15 14:45:59 +01:00
il - > stations [ i ] . sta . sta . addr ) ;
il - > stations [ i ] . used & = ~ IL_STA_DRIVER_ACTIVE ;
2011-11-15 13:40:15 +01:00
il - > stations [ i ] . used & =
2011-11-15 14:45:59 +01:00
~ IL_STA_UCODE_INPROGRESS ;
2011-11-15 13:40:15 +01:00
spin_unlock_irqrestore ( & il - > sta_lock ,
2011-11-15 14:45:59 +01:00
flags_spin ) ;
2011-11-15 13:40:15 +01:00
}
/*
* Rate scaling has already been initialized , send
* current LQ command
*/
if ( send_lq )
2012-02-03 17:31:57 +01:00
il_send_lq_cmd ( il , & lq , CMD_SYNC , true ) ;
2011-11-15 13:40:15 +01:00
spin_lock_irqsave ( & il - > sta_lock , flags_spin ) ;
il - > stations [ i ] . used & = ~ IL_STA_UCODE_INPROGRESS ;
}
}
spin_unlock_irqrestore ( & il - > sta_lock , flags_spin ) ;
if ( ! found )
D_INFO ( " Restoring all known stations "
2011-11-15 14:45:59 +01:00
" .... no stations to be restored. \n " ) ;
2011-11-15 13:40:15 +01:00
else
2011-11-15 14:45:59 +01:00
D_INFO ( " Restoring all known stations " " .... complete. \n " ) ;
2011-11-15 13:40:15 +01:00
}
EXPORT_SYMBOL ( il_restore_stations ) ;
2011-11-15 14:45:59 +01:00
int
il_get_free_ucode_key_idx ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
int i ;
for ( i = 0 ; i < il - > sta_key_max_num ; i + + )
if ( ! test_and_set_bit ( i , & il - > ucode_key_table ) )
return i ;
return WEP_INVALID_OFFSET ;
}
EXPORT_SYMBOL ( il_get_free_ucode_key_idx ) ;
2011-11-15 14:45:59 +01:00
void
il_dealloc_bcast_stations ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
unsigned long flags ;
int i ;
spin_lock_irqsave ( & il - > sta_lock , flags ) ;
for ( i = 0 ; i < il - > hw_params . max_stations ; i + + ) {
if ( ! ( il - > stations [ i ] . used & IL_STA_BCAST ) )
continue ;
il - > stations [ i ] . used & = ~ IL_STA_UCODE_ACTIVE ;
il - > num_stations - - ;
BUG_ON ( il - > num_stations < 0 ) ;
kfree ( il - > stations [ i ] . lq ) ;
il - > stations [ i ] . lq = NULL ;
}
spin_unlock_irqrestore ( & il - > sta_lock , flags ) ;
}
EXPORT_SYMBOL_GPL ( il_dealloc_bcast_stations ) ;
# ifdef CONFIG_IWLEGACY_DEBUG
2011-11-15 14:45:59 +01:00
static void
il_dump_lq_cmd ( struct il_priv * il , struct il_link_quality_cmd * lq )
2011-11-15 13:40:15 +01:00
{
int i ;
D_RATE ( " lq station id 0x%x \n " , lq - > sta_id ) ;
2011-11-15 14:45:59 +01:00
D_RATE ( " lq ant 0x%X 0x%X \n " , lq - > general_params . single_stream_ant_msk ,
lq - > general_params . dual_stream_ant_msk ) ;
2011-11-15 13:40:15 +01:00
for ( i = 0 ; i < LINK_QUAL_MAX_RETRY_NUM ; i + + )
2011-11-15 14:45:59 +01:00
D_RATE ( " lq idx %d 0x%X \n " , i , lq - > rs_table [ i ] . rate_n_flags ) ;
2011-11-15 13:40:15 +01:00
}
# else
2011-11-15 14:45:59 +01:00
static inline void
il_dump_lq_cmd ( struct il_priv * il , struct il_link_quality_cmd * lq )
2011-11-15 13:40:15 +01:00
{
}
# endif
/**
* il_is_lq_table_valid ( ) - Test one aspect of LQ cmd for validity
*
* It sometimes happens when a HT rate has been in use and we
* loose connectivity with AP then mac80211 will first tell us that the
* current channel is not HT anymore before removing the station . In such a
* scenario the RXON flags will be updated to indicate we are not
* communicating HT anymore , but the LQ command may still contain HT rates .
* Test for this to prevent driver from sending LQ command between the time
* RXON flags are updated and when LQ command is updated .
*/
2011-11-15 14:45:59 +01:00
static bool
2012-02-03 17:31:57 +01:00
il_is_lq_table_valid ( struct il_priv * il , struct il_link_quality_cmd * lq )
2011-11-15 13:40:15 +01:00
{
int i ;
2012-02-03 17:31:52 +01:00
if ( il - > ht . enabled )
2011-11-15 13:40:15 +01:00
return true ;
2012-02-03 17:31:37 +01:00
D_INFO ( " Channel %u is not an HT channel \n " , il - > active . channel ) ;
2011-11-15 13:40:15 +01:00
for ( i = 0 ; i < LINK_QUAL_MAX_RETRY_NUM ; i + + ) {
2011-11-15 14:45:59 +01:00
if ( le32_to_cpu ( lq - > rs_table [ i ] . rate_n_flags ) & RATE_MCS_HT_MSK ) {
D_INFO ( " idx %d of LQ expects HT channel \n " , i ) ;
2011-11-15 13:40:15 +01:00
return false ;
}
}
return true ;
}
/**
* il_send_lq_cmd ( ) - Send link quality command
* @ init : This command is sent as part of station initialization right
* after station has been added .
*
* The link quality command is sent as the last step of station creation .
* This is the special case in which init is set and we call a callback in
* this case to clear the state indicating that station creation is in
* progress .
*/
2011-11-15 14:45:59 +01:00
int
2012-02-03 17:31:57 +01:00
il_send_lq_cmd ( struct il_priv * il , struct il_link_quality_cmd * lq ,
u8 flags , bool init )
2011-11-15 13:40:15 +01:00
{
int ret = 0 ;
unsigned long flags_spin ;
struct il_host_cmd cmd = {
. id = C_TX_LINK_QUALITY_CMD ,
. len = sizeof ( struct il_link_quality_cmd ) ,
. flags = flags ,
. data = lq ,
} ;
if ( WARN_ON ( lq - > sta_id = = IL_INVALID_STATION ) )
return - EINVAL ;
spin_lock_irqsave ( & il - > sta_lock , flags_spin ) ;
if ( ! ( il - > stations [ lq - > sta_id ] . used & IL_STA_DRIVER_ACTIVE ) ) {
spin_unlock_irqrestore ( & il - > sta_lock , flags_spin ) ;
return - EINVAL ;
}
spin_unlock_irqrestore ( & il - > sta_lock , flags_spin ) ;
il_dump_lq_cmd ( il , lq ) ;
BUG_ON ( init & & ( cmd . flags & CMD_ASYNC ) ) ;
2012-02-03 17:31:57 +01:00
if ( il_is_lq_table_valid ( il , lq ) )
2011-11-15 13:40:15 +01:00
ret = il_send_cmd ( il , & cmd ) ;
else
ret = - EINVAL ;
if ( cmd . flags & CMD_ASYNC )
return ret ;
if ( init ) {
D_INFO ( " init LQ command complete, "
2011-11-15 14:45:59 +01:00
" clearing sta addition status for sta %d \n " ,
lq - > sta_id ) ;
2011-11-15 13:40:15 +01:00
spin_lock_irqsave ( & il - > sta_lock , flags_spin ) ;
il - > stations [ lq - > sta_id ] . used & = ~ IL_STA_UCODE_INPROGRESS ;
spin_unlock_irqrestore ( & il - > sta_lock , flags_spin ) ;
}
return ret ;
}
EXPORT_SYMBOL ( il_send_lq_cmd ) ;
2011-11-15 14:45:59 +01:00
int
il_mac_sta_remove ( struct ieee80211_hw * hw , struct ieee80211_vif * vif ,
struct ieee80211_sta * sta )
2011-11-15 13:40:15 +01:00
{
struct il_priv * il = hw - > priv ;
struct il_station_priv_common * sta_common = ( void * ) sta - > drv_priv ;
int ret ;
2011-11-15 14:45:59 +01:00
D_INFO ( " received request to remove station %pM \n " , sta - > addr ) ;
2011-11-15 13:40:15 +01:00
mutex_lock ( & il - > mutex ) ;
2011-11-15 14:45:59 +01:00
D_INFO ( " proceeding to remove station %pM \n " , sta - > addr ) ;
2011-11-15 13:40:15 +01:00
ret = il_remove_station ( il , sta_common - > sta_id , sta - > addr ) ;
if ( ret )
2011-11-15 14:45:59 +01:00
IL_ERR ( " Error removing station %pM \n " , sta - > addr ) ;
2011-11-15 13:40:15 +01:00
mutex_unlock ( & il - > mutex ) ;
return ret ;
}
EXPORT_SYMBOL ( il_mac_sta_remove ) ;
/************************** RX-FUNCTIONS ****************************/
/*
* Rx theory of operation
*
* Driver allocates a circular buffer of Receive Buffer Descriptors ( RBDs ) ,
* each of which point to Receive Buffers to be filled by the NIC . These get
* used not only for Rx frames , but for any command response or notification
* from the NIC . The driver and NIC manage the Rx buffers by means
* of idxes into the circular buffer .
*
* Rx Queue Indexes
* The host / firmware share two idx registers for managing the Rx buffers .
*
* The READ idx maps to the first position that the firmware may be writing
* to - - the driver can read up to ( but not including ) this position and get
* good data .
* The READ idx is managed by the firmware once the card is enabled .
*
* The WRITE idx maps to the last position the driver has read from - - the
* position preceding WRITE is the last slot the firmware can place a packet .
*
* The queue is empty ( no good data ) if WRITE = READ - 1 , and is full if
* WRITE = READ .
*
* During initialization , the host sets up the READ queue position to the first
* IDX position , and WRITE to the last ( READ - 1 wrapped )
*
* When the firmware places a packet in a buffer , it will advance the READ idx
* and fire the RX interrupt . The driver can then query the READ idx and
* process as many packets as possible , moving the WRITE idx forward as it
* resets the Rx queue buffers with new memory .
*
* The management in the driver is as follows :
* + A list of pre - allocated SKBs is stored in iwl - > rxq - > rx_free . When
* iwl - > rxq - > free_count drops to or below RX_LOW_WATERMARK , work is scheduled
* to replenish the iwl - > rxq - > rx_free .
* + In il_rx_replenish ( scheduled ) if ' processed ' ! = ' read ' then the
* iwl - > rxq is replenished and the READ IDX is updated ( updating the
* ' processed ' and ' read ' driver idxes as well )
* + A received packet is processed and handed to the kernel network stack ,
* detached from the iwl - > rxq . The driver ' processed ' idx is updated .
* + The Host / Firmware iwl - > rxq is replenished at tasklet time from the rx_free
* list . If there are no allocated buffers in iwl - > rxq - > rx_free , the READ
* IDX is not incremented and iwl - > status ( RX_STALLED ) is set . If there
* were enough free buffers and RX_STALLED is set it is cleared .
*
*
* Driver sequence :
*
* il_rx_queue_alloc ( ) Allocates rx_free
* il_rx_replenish ( ) Replenishes rx_free list from rx_used , and calls
* il_rx_queue_restock
* il_rx_queue_restock ( ) Moves available buffers from rx_free into Rx
* queue , updates firmware pointers , and updates
* the WRITE idx . If insufficient rx_free buffers
* are available , schedules il_rx_replenish
*
* - - enable interrupts - -
* ISR - il_rx ( ) Detach il_rx_bufs from pool up to the
* READ IDX , detaching the SKB from the pool .
* Moves the packet buffer from queue to rx_used .
* Calls il_rx_queue_restock to refill any empty
* slots .
* . . .
*
*/
/**
* il_rx_queue_space - Return number of free slots available in queue .
*/
2011-11-15 14:45:59 +01:00
int
il_rx_queue_space ( const struct il_rx_queue * q )
2011-11-15 13:40:15 +01:00
{
int s = q - > read - q - > write ;
if ( s < = 0 )
s + = RX_QUEUE_SIZE ;
/* keep some buffer to not confuse full and empty queue */
s - = 2 ;
if ( s < 0 )
s = 0 ;
return s ;
}
EXPORT_SYMBOL ( il_rx_queue_space ) ;
/**
* il_rx_queue_update_write_ptr - Update the write pointer for the RX queue
*/
void
2011-11-15 14:45:59 +01:00
il_rx_queue_update_write_ptr ( struct il_priv * il , struct il_rx_queue * q )
2011-11-15 13:40:15 +01:00
{
unsigned long flags ;
u32 rx_wrt_ptr_reg = il - > hw_params . rx_wrt_ptr_reg ;
u32 reg ;
spin_lock_irqsave ( & q - > lock , flags ) ;
if ( q - > need_update = = 0 )
goto exit_unlock ;
/* If power-saving is in use, make sure device is awake */
if ( test_bit ( S_POWER_PMI , & il - > status ) ) {
reg = _il_rd ( il , CSR_UCODE_DRV_GP1 ) ;
if ( reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP ) {
2011-11-15 14:45:59 +01:00
D_INFO ( " Rx queue requesting wakeup, " " GP1 = 0x%x \n " ,
reg ) ;
2011-11-15 13:40:15 +01:00
il_set_bit ( il , CSR_GP_CNTRL ,
2011-11-15 14:45:59 +01:00
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ ) ;
2011-11-15 13:40:15 +01:00
goto exit_unlock ;
}
q - > write_actual = ( q - > write & ~ 0x7 ) ;
2011-11-15 14:45:59 +01:00
il_wr ( il , rx_wrt_ptr_reg , q - > write_actual ) ;
2011-11-15 13:40:15 +01:00
2011-11-15 14:45:59 +01:00
/* Else device is assumed to be awake */
2011-11-15 13:40:15 +01:00
} else {
/* Device expects a multiple of 8 */
q - > write_actual = ( q - > write & ~ 0x7 ) ;
2011-11-15 14:45:59 +01:00
il_wr ( il , rx_wrt_ptr_reg , q - > write_actual ) ;
2011-11-15 13:40:15 +01:00
}
q - > need_update = 0 ;
2011-11-15 14:45:59 +01:00
exit_unlock :
2011-11-15 13:40:15 +01:00
spin_unlock_irqrestore ( & q - > lock , flags ) ;
}
EXPORT_SYMBOL ( il_rx_queue_update_write_ptr ) ;
2011-11-15 14:45:59 +01:00
int
il_rx_queue_alloc ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
struct il_rx_queue * rxq = & il - > rxq ;
struct device * dev = & il - > pci_dev - > dev ;
int i ;
spin_lock_init ( & rxq - > lock ) ;
INIT_LIST_HEAD ( & rxq - > rx_free ) ;
INIT_LIST_HEAD ( & rxq - > rx_used ) ;
/* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
2011-11-15 14:45:59 +01:00
rxq - > bd =
dma_alloc_coherent ( dev , 4 * RX_QUEUE_SIZE , & rxq - > bd_dma ,
GFP_KERNEL ) ;
2011-11-15 13:40:15 +01:00
if ( ! rxq - > bd )
goto err_bd ;
2011-11-15 14:45:59 +01:00
rxq - > rb_stts =
dma_alloc_coherent ( dev , sizeof ( struct il_rb_status ) ,
& rxq - > rb_stts_dma , GFP_KERNEL ) ;
2011-11-15 13:40:15 +01:00
if ( ! rxq - > rb_stts )
goto err_rb ;
/* Fill the rx_used queue with _all_ of the Rx buffers */
for ( i = 0 ; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE ; i + + )
list_add_tail ( & rxq - > pool [ i ] . list , & rxq - > rx_used ) ;
/* Set us so that we have processed and used all buffers, but have
* not restocked the Rx queue with fresh buffers */
rxq - > read = rxq - > write = 0 ;
rxq - > write_actual = 0 ;
rxq - > free_count = 0 ;
rxq - > need_update = 0 ;
return 0 ;
err_rb :
dma_free_coherent ( & il - > pci_dev - > dev , 4 * RX_QUEUE_SIZE , rxq - > bd ,
rxq - > bd_dma ) ;
err_bd :
return - ENOMEM ;
}
2011-11-15 14:45:59 +01:00
EXPORT_SYMBOL ( il_rx_queue_alloc ) ;
2011-11-15 13:40:15 +01:00
2011-11-15 14:45:59 +01:00
void
il_hdl_spectrum_measurement ( struct il_priv * il , struct il_rx_buf * rxb )
2011-11-15 13:40:15 +01:00
{
struct il_rx_pkt * pkt = rxb_addr ( rxb ) ;
struct il_spectrum_notification * report = & ( pkt - > u . spectrum_notif ) ;
if ( ! report - > state ) {
2011-11-15 14:45:59 +01:00
D_11H ( " Spectrum Measure Notification: Start \n " ) ;
2011-11-15 13:40:15 +01:00
return ;
}
memcpy ( & il - > measure_report , report , sizeof ( * report ) ) ;
il - > measurement_status | = MEASUREMENT_READY ;
}
EXPORT_SYMBOL ( il_hdl_spectrum_measurement ) ;
/*
* returns non - zero if packet should be dropped
*/
2011-11-15 14:45:59 +01:00
int
il_set_decrypted_flag ( struct il_priv * il , struct ieee80211_hdr * hdr ,
u32 decrypt_res , struct ieee80211_rx_status * stats )
2011-11-15 13:40:15 +01:00
{
u16 fc = le16_to_cpu ( hdr - > frame_control ) ;
/*
* All contexts have the same setting here due to it being
* a module parameter , so OK to check any context .
*/
2012-02-03 17:31:37 +01:00
if ( il - > active . filter_flags & RXON_FILTER_DIS_DECRYPT_MSK )
2011-11-15 13:40:15 +01:00
return 0 ;
if ( ! ( fc & IEEE80211_FCTL_PROTECTED ) )
return 0 ;
D_RX ( " decrypt_res:0x%x \n " , decrypt_res ) ;
switch ( decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK ) {
case RX_RES_STATUS_SEC_TYPE_TKIP :
/* The uCode has got a bad phase 1 Key, pushes the packet.
* Decryption will be done in SW . */
if ( ( decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK ) = =
RX_RES_STATUS_BAD_KEY_TTAK )
break ;
case RX_RES_STATUS_SEC_TYPE_WEP :
if ( ( decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK ) = =
RX_RES_STATUS_BAD_ICV_MIC ) {
/* bad ICV, the packet is destroyed since the
* decryption is inplace , drop it */
D_RX ( " Packet destroyed \n " ) ;
return - 1 ;
}
case RX_RES_STATUS_SEC_TYPE_CCMP :
if ( ( decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK ) = =
RX_RES_STATUS_DECRYPT_OK ) {
D_RX ( " hw decrypt successfully!!! \n " ) ;
stats - > flag | = RX_FLAG_DECRYPTED ;
}
break ;
default :
break ;
}
return 0 ;
}
EXPORT_SYMBOL ( il_set_decrypted_flag ) ;
/**
* il_txq_update_write_ptr - Send new write idx to hardware
*/
void
il_txq_update_write_ptr ( struct il_priv * il , struct il_tx_queue * txq )
{
u32 reg = 0 ;
int txq_id = txq - > q . id ;
if ( txq - > need_update = = 0 )
return ;
/* if we're trying to save power */
if ( test_bit ( S_POWER_PMI , & il - > status ) ) {
/* wake up nic if it's powered down ...
* uCode will wake up , and interrupt us again , so next
* time we ' ll skip this part . */
reg = _il_rd ( il , CSR_UCODE_DRV_GP1 ) ;
if ( reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP ) {
2011-11-15 14:45:59 +01:00
D_INFO ( " Tx queue %d requesting wakeup, " " GP1 = 0x%x \n " ,
txq_id , reg ) ;
2011-11-15 13:40:15 +01:00
il_set_bit ( il , CSR_GP_CNTRL ,
2011-11-15 14:45:59 +01:00
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ ) ;
2011-11-15 13:40:15 +01:00
return ;
}
2011-11-15 14:45:59 +01:00
il_wr ( il , HBUS_TARG_WRPTR , txq - > q . write_ptr | ( txq_id < < 8 ) ) ;
2011-11-15 13:40:15 +01:00
/*
* else not in power - save mode ,
* uCode will never sleep when we ' re
* trying to tx ( during RFKILL , we ' re not trying to tx ) .
*/
} else
2011-11-15 14:45:59 +01:00
_il_wr ( il , HBUS_TARG_WRPTR , txq - > q . write_ptr | ( txq_id < < 8 ) ) ;
2011-11-15 13:40:15 +01:00
txq - > need_update = 0 ;
}
EXPORT_SYMBOL ( il_txq_update_write_ptr ) ;
/**
* il_tx_queue_unmap - Unmap any remaining DMA mappings and free skb ' s
*/
2011-11-15 14:45:59 +01:00
void
il_tx_queue_unmap ( struct il_priv * il , int txq_id )
2011-11-15 13:40:15 +01:00
{
struct il_tx_queue * txq = & il - > txq [ txq_id ] ;
struct il_queue * q = & txq - > q ;
if ( q - > n_bd = = 0 )
return ;
while ( q - > write_ptr ! = q - > read_ptr ) {
il - > cfg - > ops - > lib - > txq_free_tfd ( il , txq ) ;
q - > read_ptr = il_queue_inc_wrap ( q - > read_ptr , q - > n_bd ) ;
}
}
EXPORT_SYMBOL ( il_tx_queue_unmap ) ;
/**
* il_tx_queue_free - Deallocate DMA queue .
* @ txq : Transmit queue to deallocate .
*
* Empty queue by removing and destroying all BD ' s .
* Free all buffers .
* 0 - fill , but do not free " txq " descriptor structure .
*/
2011-11-15 14:45:59 +01:00
void
il_tx_queue_free ( struct il_priv * il , int txq_id )
2011-11-15 13:40:15 +01:00
{
struct il_tx_queue * txq = & il - > txq [ txq_id ] ;
struct device * dev = & il - > pci_dev - > dev ;
int i ;
il_tx_queue_unmap ( il , txq_id ) ;
/* De-alloc array of command/tx buffers */
for ( i = 0 ; i < TFD_TX_CMD_SLOTS ; i + + )
kfree ( txq - > cmd [ i ] ) ;
/* De-alloc circular buffer of TFDs */
if ( txq - > q . n_bd )
2011-11-15 14:45:59 +01:00
dma_free_coherent ( dev , il - > hw_params . tfd_size * txq - > q . n_bd ,
txq - > tfds , txq - > q . dma_addr ) ;
2011-11-15 13:40:15 +01:00
/* De-alloc array of per-TFD driver data */
kfree ( txq - > txb ) ;
txq - > txb = NULL ;
/* deallocate arrays */
kfree ( txq - > cmd ) ;
kfree ( txq - > meta ) ;
txq - > cmd = NULL ;
txq - > meta = NULL ;
/* 0-fill queue descriptor structure */
memset ( txq , 0 , sizeof ( * txq ) ) ;
}
EXPORT_SYMBOL ( il_tx_queue_free ) ;
/**
* il_cmd_queue_unmap - Unmap any remaining DMA mappings from command queue
*/
2011-11-15 14:45:59 +01:00
void
il_cmd_queue_unmap ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
struct il_tx_queue * txq = & il - > txq [ il - > cmd_queue ] ;
struct il_queue * q = & txq - > q ;
int i ;
if ( q - > n_bd = = 0 )
return ;
while ( q - > read_ptr ! = q - > write_ptr ) {
i = il_get_cmd_idx ( q , q - > read_ptr , 0 ) ;
if ( txq - > meta [ i ] . flags & CMD_MAPPED ) {
pci_unmap_single ( il - > pci_dev ,
dma_unmap_addr ( & txq - > meta [ i ] , mapping ) ,
dma_unmap_len ( & txq - > meta [ i ] , len ) ,
PCI_DMA_BIDIRECTIONAL ) ;
txq - > meta [ i ] . flags = 0 ;
}
q - > read_ptr = il_queue_inc_wrap ( q - > read_ptr , q - > n_bd ) ;
}
i = q - > n_win ;
if ( txq - > meta [ i ] . flags & CMD_MAPPED ) {
pci_unmap_single ( il - > pci_dev ,
dma_unmap_addr ( & txq - > meta [ i ] , mapping ) ,
dma_unmap_len ( & txq - > meta [ i ] , len ) ,
PCI_DMA_BIDIRECTIONAL ) ;
txq - > meta [ i ] . flags = 0 ;
}
}
EXPORT_SYMBOL ( il_cmd_queue_unmap ) ;
/**
* il_cmd_queue_free - Deallocate DMA queue .
* @ txq : Transmit queue to deallocate .
*
* Empty queue by removing and destroying all BD ' s .
* Free all buffers .
* 0 - fill , but do not free " txq " descriptor structure .
*/
2011-11-15 14:45:59 +01:00
void
il_cmd_queue_free ( struct il_priv * il )
2011-11-15 13:40:15 +01:00
{
struct il_tx_queue * txq = & il - > txq [ il - > cmd_queue ] ;
struct device * dev = & il - > pci_dev - > dev ;
int i ;
il_cmd_queue_unmap ( il ) ;
/* De-alloc array of command/tx buffers */
for ( i = 0 ; i < = TFD_CMD_SLOTS ; i + + )
kfree ( txq - > cmd [ i ] ) ;
/* De-alloc circular buffer of TFDs */
if ( txq - > q . n_bd )
dma_free_coherent ( dev , il - > hw_params . tfd_size * txq - > q . n_bd ,
txq - > tfds , txq - > q . dma_addr ) ;
/* deallocate arrays */
kfree ( txq - > cmd ) ;
kfree ( txq - > meta ) ;
txq - > cmd = NULL ;
txq - > meta = NULL ;
/* 0-fill queue descriptor structure */
memset ( txq , 0 , sizeof ( * txq ) ) ;
}
EXPORT_SYMBOL ( il_cmd_queue_free ) ;
/*************** DMA-QUEUE-GENERAL-FUNCTIONS *****
* DMA services
*
* Theory of operation
*
* A Tx or Rx queue resides in host DRAM , and is comprised of a circular buffer
* of buffer descriptors , each of which points to one or more data buffers for
* the device to read from or fill . Driver and device exchange status of each
* queue via " read " and " write " pointers . Driver keeps minimum of 2 empty
* entries in each circular buffer , to protect against confusing empty and full
* queue states .
*
* The device reads or writes the data in the queues via the device ' s several
* DMA / FIFO channels . Each queue is mapped to a single DMA channel .
*
* For Tx queue , there are low mark and high mark limits . If , after queuing
* the packet for Tx , free space become < low mark , Tx queue stopped . When
* reclaiming packets ( on ' tx done IRQ ) , if free space become > high mark ,
* Tx queue resumed .
*
* See more detailed info in 4965. h .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-11-15 14:45:59 +01:00
int
il_queue_space ( const struct il_queue * q )
2011-11-15 13:40:15 +01:00
{
int s = q - > read_ptr - q - > write_ptr ;
if ( q - > read_ptr > q - > write_ptr )
s - = q - > n_bd ;
if ( s < = 0 )
s + = q - > n_win ;
/* keep some reserve to not confuse empty and full situations */
s - = 2 ;
if ( s < 0 )
s = 0 ;
return s ;
}
EXPORT_SYMBOL ( il_queue_space ) ;
/**
* il_queue_init - Initialize queue ' s high / low - water and read / write idxes
*/
2011-11-15 14:45:59 +01:00
static int
il_queue_init ( struct il_priv * il , struct il_queue * q , int count , int slots_num ,
u32 id )
2011-11-15 13:40:15 +01:00
{
q - > n_bd = count ;
q - > n_win = slots_num ;
q - > id = id ;
/* count must be power-of-two size, otherwise il_queue_inc_wrap
* and il_queue_dec_wrap are broken . */
BUG_ON ( ! is_power_of_2 ( count ) ) ;
/* slots_num must be power-of-two size, otherwise
* il_get_cmd_idx is broken . */
BUG_ON ( ! is_power_of_2 ( slots_num ) ) ;
q - > low_mark = q - > n_win / 4 ;
if ( q - > low_mark < 4 )
q - > low_mark = 4 ;
q - > high_mark = q - > n_win / 8 ;
if ( q - > high_mark < 2 )
q - > high_mark = 2 ;
q - > write_ptr = q - > read_ptr = 0 ;
return 0 ;
}
/**
* il_tx_queue_alloc - Alloc driver data and TFD CB for one Tx / cmd queue
*/
2011-11-15 14:45:59 +01:00
static int
il_tx_queue_alloc ( struct il_priv * il , struct il_tx_queue * txq , u32 id )
2011-11-15 13:40:15 +01:00
{
struct device * dev = & il - > pci_dev - > dev ;
size_t tfd_sz = il - > hw_params . tfd_size * TFD_QUEUE_SIZE_MAX ;
/* Driver ilate data, only for Tx (not command) queues,
* not shared with device . */
if ( id ! = il - > cmd_queue ) {
2011-11-29 22:08:00 +01:00
txq - > txb = kcalloc ( TFD_QUEUE_SIZE_MAX , sizeof ( txq - > txb [ 0 ] ) ,
GFP_KERNEL ) ;
2011-11-15 13:40:15 +01:00
if ( ! txq - > txb ) {
IL_ERR ( " kmalloc for auxiliary BD "
2011-11-15 14:45:59 +01:00
" structures failed \n " ) ;
2011-11-15 13:40:15 +01:00
goto error ;
}
} else {
txq - > txb = NULL ;
}
/* Circular buffer of transmit frame descriptors (TFDs),
* shared with device */
2011-11-15 14:45:59 +01:00
txq - > tfds =
dma_alloc_coherent ( dev , tfd_sz , & txq - > q . dma_addr , GFP_KERNEL ) ;
2011-11-15 13:40:15 +01:00
if ( ! txq - > tfds ) {
IL_ERR ( " pci_alloc_consistent(%zd) failed \n " , tfd_sz ) ;
goto error ;
}
txq - > q . id = id ;
return 0 ;
2011-11-15 14:45:59 +01:00
error :
2011-11-15 13:40:15 +01:00
kfree ( txq - > txb ) ;
txq - > txb = NULL ;
return - ENOMEM ;
}
/**
* il_tx_queue_init - Allocate and initialize one tx / cmd queue
*/
2011-11-15 14:45:59 +01:00
int
il_tx_queue_init ( struct il_priv * il , struct il_tx_queue * txq , int slots_num ,
u32 txq_id )
2011-11-15 13:40:15 +01:00
{
int i , len ;
int ret ;
int actual_slots = slots_num ;
/*
* Alloc buffer array for commands ( Tx or other types of commands ) .
* For the command queue ( # 4 / # 9 ) , allocate command space + one big
* command for scan , since scan command is very huge ; the system will
* not have two scans at the same time , so only one is needed .
* For normal Tx queues ( all other queues ) , no super - size command
* space is needed .
*/
if ( txq_id = = il - > cmd_queue )
actual_slots + + ;
2011-11-15 14:45:59 +01:00
txq - > meta =
kzalloc ( sizeof ( struct il_cmd_meta ) * actual_slots , GFP_KERNEL ) ;
txq - > cmd =
kzalloc ( sizeof ( struct il_device_cmd * ) * actual_slots , GFP_KERNEL ) ;
2011-11-15 13:40:15 +01:00
if ( ! txq - > meta | | ! txq - > cmd )
goto out_free_arrays ;
len = sizeof ( struct il_device_cmd ) ;
for ( i = 0 ; i < actual_slots ; i + + ) {
/* only happens for cmd queue */
if ( i = = slots_num )
len = IL_MAX_CMD_SIZE ;
txq - > cmd [ i ] = kmalloc ( len , GFP_KERNEL ) ;
if ( ! txq - > cmd [ i ] )
goto err ;
}
/* Alloc driver data array and TFD circular buffer */
ret = il_tx_queue_alloc ( il , txq , txq_id ) ;
if ( ret )
goto err ;
txq - > need_update = 0 ;
/*
* For the default queues 0 - 3 , set up the swq_id
* already - - all others need to get one later
* ( if they need one at all ) .
*/
if ( txq_id < 4 )
il_set_swq_id ( txq , txq_id , txq_id ) ;
/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
* il_queue_inc_wrap and il_queue_dec_wrap are broken . */
BUILD_BUG_ON ( TFD_QUEUE_SIZE_MAX & ( TFD_QUEUE_SIZE_MAX - 1 ) ) ;
/* Initialize queue's high/low-water marks, and head/tail idxes */
2011-11-15 14:45:59 +01:00
il_queue_init ( il , & txq - > q , TFD_QUEUE_SIZE_MAX , slots_num , txq_id ) ;
2011-11-15 13:40:15 +01:00
/* Tell device where to find queue */
il - > cfg - > ops - > lib - > txq_init ( il , txq ) ;
return 0 ;
err :
for ( i = 0 ; i < actual_slots ; i + + )
kfree ( txq - > cmd [ i ] ) ;
out_free_arrays :
kfree ( txq - > meta ) ;
kfree ( txq - > cmd ) ;
return - ENOMEM ;
}
EXPORT_SYMBOL ( il_tx_queue_init ) ;
2011-11-15 14:45:59 +01:00
void
il_tx_queue_reset ( struct il_priv * il , struct il_tx_queue * txq , int slots_num ,
u32 txq_id )
2011-11-15 13:40:15 +01:00
{
int actual_slots = slots_num ;
if ( txq_id = = il - > cmd_queue )
actual_slots + + ;
memset ( txq - > meta , 0 , sizeof ( struct il_cmd_meta ) * actual_slots ) ;
txq - > need_update = 0 ;
/* Initialize queue's high/low-water marks, and head/tail idxes */
2011-11-15 14:45:59 +01:00
il_queue_init ( il , & txq - > q , TFD_QUEUE_SIZE_MAX , slots_num , txq_id ) ;
2011-11-15 13:40:15 +01:00
/* Tell device where to find queue */
il - > cfg - > ops - > lib - > txq_init ( il , txq ) ;
}
EXPORT_SYMBOL ( il_tx_queue_reset ) ;
/*************** HOST COMMAND QUEUE FUNCTIONS *****/
/**
* il_enqueue_hcmd - enqueue a uCode command
* @ il : device ilate data point
* @ cmd : a point to the ucode command structure
*
* The function returns < 0 values to indicate the operation is
* failed . On success , it turns the idx ( > 0 ) of command in the
* command queue .
*/
2011-11-15 14:45:59 +01:00
int
il_enqueue_hcmd ( struct il_priv * il , struct il_host_cmd * cmd )
2011-11-15 13:40:15 +01:00
{
struct il_tx_queue * txq = & il - > txq [ il - > cmd_queue ] ;
struct il_queue * q = & txq - > q ;
struct il_device_cmd * out_cmd ;
struct il_cmd_meta * out_meta ;
dma_addr_t phys_addr ;
unsigned long flags ;
int len ;
u32 idx ;
u16 fix_size ;
cmd - > len = il - > cfg - > ops - > utils - > get_hcmd_size ( cmd - > id , cmd - > len ) ;
2011-11-15 14:45:59 +01:00
fix_size = ( u16 ) ( cmd - > len + sizeof ( out_cmd - > hdr ) ) ;
2011-11-15 13:40:15 +01:00
/* If any of the command structures end up being larger than
* the TFD_MAX_PAYLOAD_SIZE , and it sent as a ' small ' command then
* we will need to increase the size of the TFD entries
* Also , check to see if command buffer should not exceed the size
* of device_cmd and max_cmd_size . */
BUG_ON ( ( fix_size > TFD_MAX_PAYLOAD_SIZE ) & &
! ( cmd - > flags & CMD_SIZE_HUGE ) ) ;
BUG_ON ( fix_size > IL_MAX_CMD_SIZE ) ;
if ( il_is_rfkill ( il ) | | il_is_ctkill ( il ) ) {
IL_WARN ( " Not sending command - %s KILL \n " ,
2011-11-15 14:45:59 +01:00
il_is_rfkill ( il ) ? " RF " : " CT " ) ;
2011-11-15 13:40:15 +01:00
return - EIO ;
}
spin_lock_irqsave ( & il - > hcmd_lock , flags ) ;
if ( il_queue_space ( q ) < ( ( cmd - > flags & CMD_ASYNC ) ? 2 : 1 ) ) {
spin_unlock_irqrestore ( & il - > hcmd_lock , flags ) ;
IL_ERR ( " Restarting adapter due to command queue full \n " ) ;
queue_work ( il - > workqueue , & il - > restart ) ;
return - ENOSPC ;
}
idx = il_get_cmd_idx ( q , q - > write_ptr , cmd - > flags & CMD_SIZE_HUGE ) ;
out_cmd = txq - > cmd [ idx ] ;
out_meta = & txq - > meta [ idx ] ;
if ( WARN_ON ( out_meta - > flags & CMD_MAPPED ) ) {
spin_unlock_irqrestore ( & il - > hcmd_lock , flags ) ;
return - ENOSPC ;
}
memset ( out_meta , 0 , sizeof ( * out_meta ) ) ; /* re-initialize to NULL */
out_meta - > flags = cmd - > flags | CMD_MAPPED ;
if ( cmd - > flags & CMD_WANT_SKB )
out_meta - > source = cmd ;
if ( cmd - > flags & CMD_ASYNC )
out_meta - > callback = cmd - > callback ;
out_cmd - > hdr . cmd = cmd - > id ;
memcpy ( & out_cmd - > cmd . payload , cmd - > data , cmd - > len ) ;
/* At this point, the out_cmd now has all of the incoming cmd
* information */
out_cmd - > hdr . flags = 0 ;
2011-11-15 14:45:59 +01:00
out_cmd - > hdr . sequence =
cpu_to_le16 ( QUEUE_TO_SEQ ( il - > cmd_queue ) | IDX_TO_SEQ ( q - > write_ptr ) ) ;
2011-11-15 13:40:15 +01:00
if ( cmd - > flags & CMD_SIZE_HUGE )
out_cmd - > hdr . sequence | = SEQ_HUGE_FRAME ;
len = sizeof ( struct il_device_cmd ) ;
if ( idx = = TFD_CMD_SLOTS )
len = IL_MAX_CMD_SIZE ;
# ifdef CONFIG_IWLEGACY_DEBUG
switch ( out_cmd - > hdr . cmd ) {
case C_TX_LINK_QUALITY_CMD :
case C_SENSITIVITY :
2011-11-15 14:45:59 +01:00
D_HC_DUMP ( " Sending command %s (#%x), seq: 0x%04X, "
" %d bytes at %d[%d]:%d \n " ,
il_get_cmd_string ( out_cmd - > hdr . cmd ) , out_cmd - > hdr . cmd ,
le16_to_cpu ( out_cmd - > hdr . sequence ) , fix_size ,
q - > write_ptr , idx , il - > cmd_queue ) ;
2011-11-15 13:40:15 +01:00
break ;
default :
D_HC ( " Sending command %s (#%x), seq: 0x%04X, "
2011-11-15 14:45:59 +01:00
" %d bytes at %d[%d]:%d \n " ,
il_get_cmd_string ( out_cmd - > hdr . cmd ) , out_cmd - > hdr . cmd ,
le16_to_cpu ( out_cmd - > hdr . sequence ) , fix_size , q - > write_ptr ,
idx , il - > cmd_queue ) ;
2011-11-15 13:40:15 +01:00
}
# endif
txq - > need_update = 1 ;
if ( il - > cfg - > ops - > lib - > txq_update_byte_cnt_tbl )
/* Set up entry in queue's byte count circular buffer */
il - > cfg - > ops - > lib - > txq_update_byte_cnt_tbl ( il , txq , 0 ) ;
2011-11-15 14:45:59 +01:00
phys_addr =
pci_map_single ( il - > pci_dev , & out_cmd - > hdr , fix_size ,
PCI_DMA_BIDIRECTIONAL ) ;
2011-11-15 13:40:15 +01:00
dma_unmap_addr_set ( out_meta , mapping , phys_addr ) ;
dma_unmap_len_set ( out_meta , len , fix_size ) ;
2011-11-15 14:45:59 +01:00
il - > cfg - > ops - > lib - > txq_attach_buf_to_tfd ( il , txq , phys_addr , fix_size ,
1 , U32_PAD ( cmd - > len ) ) ;
2011-11-15 13:40:15 +01:00
/* Increment and update queue's write idx */
q - > write_ptr = il_queue_inc_wrap ( q - > write_ptr , q - > n_bd ) ;
il_txq_update_write_ptr ( il , txq ) ;
spin_unlock_irqrestore ( & il - > hcmd_lock , flags ) ;
return idx ;
}
/**
* il_hcmd_queue_reclaim - Reclaim TX command queue entries already Tx ' d
*
* When FW advances ' R ' idx , all entries between old and new ' R ' idx
* need to be reclaimed . As result , some free space forms . If there is
* enough free space ( > low mark ) , wake the stack that feeds us .
*/
2011-11-15 14:45:59 +01:00
static void
il_hcmd_queue_reclaim ( struct il_priv * il , int txq_id , int idx , int cmd_idx )
2011-11-15 13:40:15 +01:00
{
struct il_tx_queue * txq = & il - > txq [ txq_id ] ;
struct il_queue * q = & txq - > q ;
int nfreed = 0 ;
if ( idx > = q - > n_bd | | il_queue_used ( q , idx ) = = 0 ) {
IL_ERR ( " Read idx for DMA queue txq id (%d), idx %d, "
2011-11-15 14:45:59 +01:00
" is out of range [0-%d] %d %d. \n " , txq_id , idx , q - > n_bd ,
q - > write_ptr , q - > read_ptr ) ;
2011-11-15 13:40:15 +01:00
return ;
}
for ( idx = il_queue_inc_wrap ( idx , q - > n_bd ) ; q - > read_ptr ! = idx ;
q - > read_ptr = il_queue_inc_wrap ( q - > read_ptr , q - > n_bd ) ) {
if ( nfreed + + > 0 ) {
IL_ERR ( " HCMD skipped: idx (%d) %d %d \n " , idx ,
2011-11-15 14:45:59 +01:00
q - > write_ptr , q - > read_ptr ) ;
2011-11-15 13:40:15 +01:00
queue_work ( il - > workqueue , & il - > restart ) ;
}
}
}
/**
* il_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
* @ rxb : Rx buffer to reclaim
*
* If an Rx buffer has an async callback associated with it the callback
* will be executed . The attached skb ( if present ) will only be freed
* if the callback returns 1
*/
void
il_tx_cmd_complete ( struct il_priv * il , struct il_rx_buf * rxb )
{
struct il_rx_pkt * pkt = rxb_addr ( rxb ) ;
u16 sequence = le16_to_cpu ( pkt - > hdr . sequence ) ;
int txq_id = SEQ_TO_QUEUE ( sequence ) ;
int idx = SEQ_TO_IDX ( sequence ) ;
int cmd_idx ;
bool huge = ! ! ( pkt - > hdr . sequence & SEQ_HUGE_FRAME ) ;
struct il_device_cmd * cmd ;
struct il_cmd_meta * meta ;
struct il_tx_queue * txq = & il - > txq [ il - > cmd_queue ] ;
unsigned long flags ;
/* If a Tx command is being handled and it isn't in the actual
* command queue then there a command routing bug has been introduced
* in the queue management code . */
2011-11-15 14:45:59 +01:00
if ( WARN
( txq_id ! = il - > cmd_queue ,
" wrong command queue %d (should be %d), sequence 0x%X readp=%d writep=%d \n " ,
txq_id , il - > cmd_queue , sequence , il - > txq [ il - > cmd_queue ] . q . read_ptr ,
il - > txq [ il - > cmd_queue ] . q . write_ptr ) ) {
2011-11-15 13:40:15 +01:00
il_print_hex_error ( il , pkt , 32 ) ;
return ;
}
cmd_idx = il_get_cmd_idx ( & txq - > q , idx , huge ) ;
cmd = txq - > cmd [ cmd_idx ] ;
meta = & txq - > meta [ cmd_idx ] ;
txq - > time_stamp = jiffies ;
2011-11-15 14:45:59 +01:00
pci_unmap_single ( il - > pci_dev , dma_unmap_addr ( meta , mapping ) ,
dma_unmap_len ( meta , len ) , PCI_DMA_BIDIRECTIONAL ) ;
2011-11-15 13:40:15 +01:00
/* Input error checking is done when commands are added to queue. */
if ( meta - > flags & CMD_WANT_SKB ) {
meta - > source - > reply_page = ( unsigned long ) rxb_addr ( rxb ) ;
rxb - > page = NULL ;
} else if ( meta - > callback )
meta - > callback ( il , cmd , pkt ) ;
spin_lock_irqsave ( & il - > hcmd_lock , flags ) ;
il_hcmd_queue_reclaim ( il , txq_id , idx , cmd_idx ) ;
if ( ! ( meta - > flags & CMD_ASYNC ) ) {
clear_bit ( S_HCMD_ACTIVE , & il - > status ) ;
D_INFO ( " Clearing HCMD_ACTIVE for command %s \n " ,
2011-11-15 14:45:59 +01:00
il_get_cmd_string ( cmd - > hdr . cmd ) ) ;
2011-11-15 13:40:15 +01:00
wake_up ( & il - > wait_command_queue ) ;
}
/* Mark as unmapped */
meta - > flags = 0 ;
spin_unlock_irqrestore ( & il - > hcmd_lock , flags ) ;
}
EXPORT_SYMBOL ( il_tx_cmd_complete ) ;
2011-02-21 11:27:26 -08:00
MODULE_DESCRIPTION ( " iwl-legacy: common functions for 3945 and 4965 " ) ;
MODULE_VERSION ( IWLWIFI_VERSION ) ;
MODULE_AUTHOR ( DRV_COPYRIGHT " " DRV_AUTHOR ) ;
MODULE_LICENSE ( " GPL " ) ;
/*
* set bt_coex_active to true , uCode will do kill / defer
* every time the priority line is asserted ( BT is sending signals on the
* priority line in the PCIx ) .
* set bt_coex_active to false , uCode will ignore the BT activity and
* perform the normal operation
*
* User might experience transmit issue on some platform due to WiFi / BT
* co - exist problem . The possible behaviors are :
* Able to scan and finding all the available AP
* Not able to associate with any AP
* On those platforms , WiFi communication can be restored by set
* " bt_coex_active " module parameter to " false "
*
* default : bt_coex_active = true ( BT_COEX_ENABLE )
*/
2011-02-25 15:51:01 -05:00
static bool bt_coex_active = true ;
2011-02-21 11:27:26 -08:00
module_param ( bt_coex_active , bool , S_IRUGO ) ;
MODULE_PARM_DESC ( bt_coex_active , " enable wifi/bluetooth co-exist " ) ;
2011-08-16 14:17:04 +02:00
u32 il_debug_level ;
EXPORT_SYMBOL ( il_debug_level ) ;
2011-02-21 11:27:26 -08:00
2011-08-16 14:17:04 +02:00
const u8 il_bcast_addr [ ETH_ALEN ] = { 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ;
2011-11-15 14:45:59 +01:00
EXPORT_SYMBOL ( il_bcast_addr ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
/* This function both allocates and initializes hw and il. */
2011-11-15 14:45:59 +01:00
struct ieee80211_hw *
il_alloc_all ( struct il_cfg * cfg )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
struct il_priv * il ;
2011-02-21 11:27:26 -08:00
/* mac80211 allocates memory for this device instance, including
2011-10-24 16:49:25 +02:00
* space for this driver ' s ilate structure */
2011-02-21 11:27:26 -08:00
struct ieee80211_hw * hw ;
2011-10-24 15:41:30 +02:00
hw = ieee80211_alloc_hw ( sizeof ( struct il_priv ) ,
2011-02-21 11:27:26 -08:00
cfg - > ops - > ieee80211_ops ) ;
if ( hw = = NULL ) {
2011-11-15 14:45:59 +01:00
pr_err ( " %s: Can not allocate network device \n " , cfg - > name ) ;
2011-02-21 11:27:26 -08:00
goto out ;
}
2011-10-24 16:49:25 +02:00
il = hw - > priv ;
il - > hw = hw ;
2011-02-21 11:27:26 -08:00
out :
return hw ;
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_alloc_all ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
# define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
# define MAX_BIT_RATE_20_MHZ 72 /* Mbps */
static void
il_init_ht_hw_capab ( const struct il_priv * il ,
struct ieee80211_sta_ht_cap * ht_info ,
enum ieee80211_band band )
2011-02-21 11:27:26 -08:00
{
u16 max_bit_rate = 0 ;
2011-10-24 16:49:25 +02:00
u8 rx_chains_num = il - > hw_params . rx_chains_num ;
u8 tx_chains_num = il - > hw_params . tx_chains_num ;
2011-02-21 11:27:26 -08:00
ht_info - > cap = 0 ;
memset ( & ht_info - > mcs , 0 , sizeof ( ht_info - > mcs ) ) ;
ht_info - > ht_supported = true ;
ht_info - > cap | = IEEE80211_HT_CAP_SGI_20 ;
max_bit_rate = MAX_BIT_RATE_20_MHZ ;
2011-10-24 16:49:25 +02:00
if ( il - > hw_params . ht40_channel & BIT ( band ) ) {
2011-02-21 11:27:26 -08:00
ht_info - > cap | = IEEE80211_HT_CAP_SUP_WIDTH_20_40 ;
ht_info - > cap | = IEEE80211_HT_CAP_SGI_40 ;
ht_info - > mcs . rx_mask [ 4 ] = 0x01 ;
max_bit_rate = MAX_BIT_RATE_40_MHZ ;
}
2011-10-24 16:49:25 +02:00
if ( il - > cfg - > mod_params - > amsdu_size_8K )
2011-02-21 11:27:26 -08:00
ht_info - > cap | = IEEE80211_HT_CAP_MAX_AMSDU ;
ht_info - > ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF ;
ht_info - > ampdu_density = CFG_HT_MPDU_DENSITY_DEF ;
ht_info - > mcs . rx_mask [ 0 ] = 0xFF ;
if ( rx_chains_num > = 2 )
ht_info - > mcs . rx_mask [ 1 ] = 0xFF ;
if ( rx_chains_num > = 3 )
ht_info - > mcs . rx_mask [ 2 ] = 0xFF ;
/* Highest supported Rx data rate */
max_bit_rate * = rx_chains_num ;
WARN_ON ( max_bit_rate & ~ IEEE80211_HT_MCS_RX_HIGHEST_MASK ) ;
ht_info - > mcs . rx_highest = cpu_to_le16 ( max_bit_rate ) ;
/* Tx MCS capabilities */
ht_info - > mcs . tx_params = IEEE80211_HT_MCS_TX_DEFINED ;
if ( tx_chains_num ! = rx_chains_num ) {
ht_info - > mcs . tx_params | = IEEE80211_HT_MCS_TX_RX_DIFF ;
2011-11-15 14:45:59 +01:00
ht_info - > mcs . tx_params | =
( ( tx_chains_num -
1 ) < < IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT ) ;
2011-02-21 11:27:26 -08:00
}
}
/**
2011-10-24 15:41:30 +02:00
* il_init_geos - Initialize mac80211 ' s geo / channel info based from eeprom
2011-02-21 11:27:26 -08:00
*/
2011-11-15 14:45:59 +01:00
int
il_init_geos ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
2011-10-24 15:41:30 +02:00
struct il_channel_info * ch ;
2011-02-21 11:27:26 -08:00
struct ieee80211_supported_band * sband ;
struct ieee80211_channel * channels ;
struct ieee80211_channel * geo_ch ;
struct ieee80211_rate * rates ;
int i = 0 ;
2011-04-13 10:56:51 +02:00
s8 max_tx_power = 0 ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
if ( il - > bands [ IEEE80211_BAND_2GHZ ] . n_bitrates | |
il - > bands [ IEEE80211_BAND_5GHZ ] . n_bitrates ) {
2011-11-15 11:21:01 +01:00
D_INFO ( " Geography modes already initialized. \n " ) ;
2011-11-15 13:09:01 +01:00
set_bit ( S_GEO_CONFIGURED , & il - > status ) ;
2011-02-21 11:27:26 -08:00
return 0 ;
}
2011-11-15 14:45:59 +01:00
channels =
kzalloc ( sizeof ( struct ieee80211_channel ) * il - > channel_count ,
GFP_KERNEL ) ;
2011-02-21 11:27:26 -08:00
if ( ! channels )
return - ENOMEM ;
2011-11-15 14:45:59 +01:00
rates =
kzalloc ( ( sizeof ( struct ieee80211_rate ) * RATE_COUNT_LEGACY ) ,
GFP_KERNEL ) ;
2011-02-21 11:27:26 -08:00
if ( ! rates ) {
kfree ( channels ) ;
return - ENOMEM ;
}
/* 5.2GHz channels start after the 2.4GHz channels */
2011-10-24 16:49:25 +02:00
sband = & il - > bands [ IEEE80211_BAND_5GHZ ] ;
2011-08-16 14:17:04 +02:00
sband - > channels = & channels [ ARRAY_SIZE ( il_eeprom_band_1 ) ] ;
2011-02-21 11:27:26 -08:00
/* just OFDM */
2011-10-24 15:41:30 +02:00
sband - > bitrates = & rates [ IL_FIRST_OFDM_RATE ] ;
2011-08-26 16:07:43 +02:00
sband - > n_bitrates = RATE_COUNT_LEGACY - IL_FIRST_OFDM_RATE ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
if ( il - > cfg - > sku & IL_SKU_N )
2011-11-15 14:45:59 +01:00
il_init_ht_hw_capab ( il , & sband - > ht_cap , IEEE80211_BAND_5GHZ ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
sband = & il - > bands [ IEEE80211_BAND_2GHZ ] ;
2011-02-21 11:27:26 -08:00
sband - > channels = channels ;
/* OFDM & CCK */
sband - > bitrates = rates ;
2011-08-26 16:07:43 +02:00
sband - > n_bitrates = RATE_COUNT_LEGACY ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
if ( il - > cfg - > sku & IL_SKU_N )
2011-11-15 14:45:59 +01:00
il_init_ht_hw_capab ( il , & sband - > ht_cap , IEEE80211_BAND_2GHZ ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
il - > ieee_channels = channels ;
il - > ieee_rates = rates ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
for ( i = 0 ; i < il - > channel_count ; i + + ) {
2011-10-24 16:49:25 +02:00
ch = & il - > channel_info [ i ] ;
2011-02-21 11:27:26 -08:00
2011-10-24 15:41:30 +02:00
if ( ! il_is_channel_valid ( ch ) )
2011-02-21 11:27:26 -08:00
continue ;
2011-10-24 16:49:25 +02:00
sband = & il - > bands [ ch - > band ] ;
2011-02-21 11:27:26 -08:00
geo_ch = & sband - > channels [ sband - > n_channels + + ] ;
geo_ch - > center_freq =
2011-11-15 14:45:59 +01:00
ieee80211_channel_to_frequency ( ch - > channel , ch - > band ) ;
2011-02-21 11:27:26 -08:00
geo_ch - > max_power = ch - > max_power_avg ;
geo_ch - > max_antenna_gain = 0xff ;
geo_ch - > hw_value = ch - > channel ;
2011-10-24 15:41:30 +02:00
if ( il_is_channel_valid ( ch ) ) {
2011-02-21 11:27:26 -08:00
if ( ! ( ch - > flags & EEPROM_CHANNEL_IBSS ) )
geo_ch - > flags | = IEEE80211_CHAN_NO_IBSS ;
if ( ! ( ch - > flags & EEPROM_CHANNEL_ACTIVE ) )
geo_ch - > flags | = IEEE80211_CHAN_PASSIVE_SCAN ;
if ( ch - > flags & EEPROM_CHANNEL_RADAR )
geo_ch - > flags | = IEEE80211_CHAN_RADAR ;
geo_ch - > flags | = ch - > ht40_extension_channel ;
2011-04-13 10:56:51 +02:00
if ( ch - > max_power_avg > max_tx_power )
max_tx_power = ch - > max_power_avg ;
2011-02-21 11:27:26 -08:00
} else {
geo_ch - > flags | = IEEE80211_CHAN_DISABLED ;
}
2011-11-15 14:45:59 +01:00
D_INFO ( " Channel %d Freq=%d[%sGHz] %s flag=0x%X \n " , ch - > channel ,
geo_ch - > center_freq ,
il_is_channel_a_band ( ch ) ? " 5.2 " : " 2.4 " ,
geo_ch - >
flags & IEEE80211_CHAN_DISABLED ? " restricted " : " valid " ,
geo_ch - > flags ) ;
2011-02-21 11:27:26 -08:00
}
2011-10-24 16:49:25 +02:00
il - > tx_power_device_lmt = max_tx_power ;
il - > tx_power_user_lmt = max_tx_power ;
il - > tx_power_next = max_tx_power ;
2011-04-13 10:56:51 +02:00
2011-08-26 10:45:16 +02:00
if ( il - > bands [ IEEE80211_BAND_5GHZ ] . n_channels = = 0 & &
( il - > cfg - > sku & IL_SKU_A ) ) {
2011-08-18 22:07:57 +02:00
IL_INFO ( " Incorrectly detected BG card as ABG. "
2011-02-21 11:27:26 -08:00
" Please send your PCI ID 0x%04X:0x%04X to maintainer. \n " ,
2011-11-15 14:45:59 +01:00
il - > pci_dev - > device , il - > pci_dev - > subsystem_device ) ;
2011-10-24 16:49:25 +02:00
il - > cfg - > sku & = ~ IL_SKU_A ;
2011-02-21 11:27:26 -08:00
}
2011-08-18 22:07:57 +02:00
IL_INFO ( " Tunable channels: %d 802.11bg, %d 802.11a channels \n " ,
2011-11-15 14:45:59 +01:00
il - > bands [ IEEE80211_BAND_2GHZ ] . n_channels ,
il - > bands [ IEEE80211_BAND_5GHZ ] . n_channels ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 13:09:01 +01:00
set_bit ( S_GEO_CONFIGURED , & il - > status ) ;
2011-02-21 11:27:26 -08:00
return 0 ;
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_init_geos ) ;
2011-02-21 11:27:26 -08:00
/*
2011-10-24 15:41:30 +02:00
* il_free_geos - undo allocations in il_init_geos
2011-02-21 11:27:26 -08:00
*/
2011-11-15 14:45:59 +01:00
void
il_free_geos ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
kfree ( il - > ieee_channels ) ;
kfree ( il - > ieee_rates ) ;
2011-11-15 13:09:01 +01:00
clear_bit ( S_GEO_CONFIGURED , & il - > status ) ;
2011-02-21 11:27:26 -08:00
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_free_geos ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
static bool
il_is_channel_extension ( struct il_priv * il , enum ieee80211_band band ,
u16 channel , u8 extension_chan_offset )
2011-02-21 11:27:26 -08:00
{
2011-10-24 15:41:30 +02:00
const struct il_channel_info * ch_info ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
ch_info = il_get_channel_info ( il , band , channel ) ;
2011-10-24 15:41:30 +02:00
if ( ! il_is_channel_valid ( ch_info ) )
2011-02-21 11:27:26 -08:00
return false ;
if ( extension_chan_offset = = IEEE80211_HT_PARAM_CHA_SEC_ABOVE )
2011-11-15 14:45:59 +01:00
return ! ( ch_info - >
ht40_extension_channel & IEEE80211_CHAN_NO_HT40PLUS ) ;
2011-02-21 11:27:26 -08:00
else if ( extension_chan_offset = = IEEE80211_HT_PARAM_CHA_SEC_BELOW )
2011-11-15 14:45:59 +01:00
return ! ( ch_info - >
ht40_extension_channel & IEEE80211_CHAN_NO_HT40MINUS ) ;
2011-02-21 11:27:26 -08:00
return false ;
}
2011-11-15 14:45:59 +01:00
bool
2012-02-03 17:31:57 +01:00
il_is_ht40_tx_allowed ( struct il_priv * il , struct ieee80211_sta_ht_cap * ht_cap )
2011-02-21 11:27:26 -08:00
{
2012-02-03 17:31:52 +01:00
if ( ! il - > ht . enabled | | ! il - > ht . is_40mhz )
2011-02-21 11:27:26 -08:00
return false ;
/*
* We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40
* the bit will not set if it is pure 40 MHz case
*/
if ( ht_cap & & ! ht_cap - > ht_supported )
return false ;
2011-11-15 11:25:42 +01:00
# ifdef CONFIG_IWLEGACY_DEBUGFS
2011-10-24 16:49:25 +02:00
if ( il - > disable_ht40 )
2011-02-21 11:27:26 -08:00
return false ;
# endif
2011-10-24 16:49:25 +02:00
return il_is_channel_extension ( il , il - > band ,
2012-02-03 17:31:37 +01:00
le16_to_cpu ( il - > staging . channel ) ,
2012-02-03 17:31:52 +01:00
il - > ht . extension_chan_offset ) ;
2011-02-21 11:27:26 -08:00
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_is_ht40_tx_allowed ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
static u16
il_adjust_beacon_interval ( u16 beacon_val , u16 max_beacon_val )
2011-02-21 11:27:26 -08:00
{
u16 new_val ;
u16 beacon_factor ;
/*
* If mac80211 hasn ' t given us a beacon interval , program
* the default into the device .
*/
if ( ! beacon_val )
return DEFAULT_BEACON_INTERVAL ;
/*
* If the beacon interval we obtained from the peer
* is too large , we ' ll have to wake up more often
* ( and in IBSS case , we ' ll beacon too much )
*
* For example , if max_beacon_val is 4096 , and the
* requested beacon interval is 7000 , we ' ll have to
* use 3500 to be able to wake up on the beacons .
*
* This could badly influence beacon detection stats .
*/
beacon_factor = ( beacon_val + max_beacon_val ) / max_beacon_val ;
new_val = beacon_val / beacon_factor ;
if ( ! new_val )
new_val = max_beacon_val ;
return new_val ;
}
int
2012-02-03 17:31:57 +01:00
il_send_rxon_timing ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
u64 tsf ;
s32 interval_tm , rem ;
struct ieee80211_conf * conf = NULL ;
u16 beacon_int ;
2012-02-03 17:31:57 +01:00
struct ieee80211_vif * vif = il - > vif ;
2011-02-21 11:27:26 -08:00
2011-08-31 11:13:05 +02:00
conf = & il - > hw - > conf ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
lockdep_assert_held ( & il - > mutex ) ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:37 +01:00
memset ( & il - > timing , 0 , sizeof ( struct il_rxon_time_cmd ) ) ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:37 +01:00
il - > timing . timestamp = cpu_to_le64 ( il - > timestamp ) ;
il - > timing . listen_interval = cpu_to_le16 ( conf - > listen_interval ) ;
2011-02-21 11:27:26 -08:00
beacon_int = vif ? vif - > bss_conf . beacon_int : 0 ;
/*
2011-08-26 15:49:28 +02:00
* TODO : For IBSS we need to get atim_win from mac80211 ,
2011-11-15 14:45:59 +01:00
* for now just always use 0
2011-02-21 11:27:26 -08:00
*/
2012-02-03 17:31:37 +01:00
il - > timing . atim_win = 0 ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
beacon_int =
il_adjust_beacon_interval ( beacon_int ,
il - > hw_params . max_beacon_itrvl *
TIME_UNIT ) ;
2012-02-03 17:31:37 +01:00
il - > timing . beacon_interval = cpu_to_le16 ( beacon_int ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
tsf = il - > timestamp ; /* tsf is modifed by do_div: copy it */
2011-02-21 11:27:26 -08:00
interval_tm = beacon_int * TIME_UNIT ;
rem = do_div ( tsf , interval_tm ) ;
2012-02-03 17:31:37 +01:00
il - > timing . beacon_init_val = cpu_to_le32 ( interval_tm - rem ) ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:37 +01:00
il - > timing . dtim_period = vif ? ( vif - > bss_conf . dtim_period ? : 1 ) : 1 ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
D_ASSOC ( " beacon interval %d beacon timer %d beacon tim %d \n " ,
2012-02-03 17:31:37 +01:00
le16_to_cpu ( il - > timing . beacon_interval ) ,
le32_to_cpu ( il - > timing . beacon_init_val ) ,
le16_to_cpu ( il - > timing . atim_win ) ) ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:39 +01:00
return il_send_cmd_pdu ( il , C_RXON_TIMING , sizeof ( il - > timing ) ,
2012-02-03 17:31:37 +01:00
& il - > timing ) ;
2011-02-21 11:27:26 -08:00
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_send_rxon_timing ) ;
2011-02-21 11:27:26 -08:00
void
2012-02-03 17:31:57 +01:00
il_set_rxon_hwcrypto ( struct il_priv * il , int hw_decrypt )
2011-02-21 11:27:26 -08:00
{
2012-02-03 17:31:37 +01:00
struct il_rxon_cmd * rxon = & il - > staging ;
2011-02-21 11:27:26 -08:00
if ( hw_decrypt )
rxon - > filter_flags & = ~ RXON_FILTER_DIS_DECRYPT_MSK ;
else
rxon - > filter_flags | = RXON_FILTER_DIS_DECRYPT_MSK ;
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_set_rxon_hwcrypto ) ;
2011-02-21 11:27:26 -08:00
/* validate RXON structure is valid */
int
2012-02-03 17:31:57 +01:00
il_check_rxon_cmd ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
2012-02-03 17:31:37 +01:00
struct il_rxon_cmd * rxon = & il - > staging ;
2011-02-21 11:27:26 -08:00
bool error = false ;
if ( rxon - > flags & RXON_FLG_BAND_24G_MSK ) {
if ( rxon - > flags & RXON_FLG_TGJ_NARROW_BAND_MSK ) {
2011-08-18 22:07:57 +02:00
IL_WARN ( " check 2.4G: wrong narrow \n " ) ;
2011-02-21 11:27:26 -08:00
error = true ;
}
if ( rxon - > flags & RXON_FLG_RADAR_DETECT_MSK ) {
2011-08-18 22:07:57 +02:00
IL_WARN ( " check 2.4G: wrong radar \n " ) ;
2011-02-21 11:27:26 -08:00
error = true ;
}
} else {
if ( ! ( rxon - > flags & RXON_FLG_SHORT_SLOT_MSK ) ) {
2011-08-18 22:07:57 +02:00
IL_WARN ( " check 5.2G: not short slot! \n " ) ;
2011-02-21 11:27:26 -08:00
error = true ;
}
if ( rxon - > flags & RXON_FLG_CCK_MSK ) {
2011-08-18 22:07:57 +02:00
IL_WARN ( " check 5.2G: CCK! \n " ) ;
2011-02-21 11:27:26 -08:00
error = true ;
}
}
if ( ( rxon - > node_addr [ 0 ] | rxon - > bssid_addr [ 0 ] ) & 0x1 ) {
2011-08-18 22:07:57 +02:00
IL_WARN ( " mac/bssid mcast! \n " ) ;
2011-02-21 11:27:26 -08:00
error = true ;
}
/* make sure basic rates 6Mbps and 1Mbps are supported */
2011-08-26 16:07:43 +02:00
if ( ( rxon - > ofdm_basic_rates & RATE_6M_MASK ) = = 0 & &
( rxon - > cck_basic_rates & RATE_1M_MASK ) = = 0 ) {
2011-08-18 22:07:57 +02:00
IL_WARN ( " neither 1 nor 6 are basic \n " ) ;
2011-02-21 11:27:26 -08:00
error = true ;
}
if ( le16_to_cpu ( rxon - > assoc_id ) > 2007 ) {
2011-08-18 22:07:57 +02:00
IL_WARN ( " aid > 2007 \n " ) ;
2011-02-21 11:27:26 -08:00
error = true ;
}
2011-11-15 14:45:59 +01:00
if ( ( rxon - > flags & ( RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK ) ) = =
( RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK ) ) {
2011-08-18 22:07:57 +02:00
IL_WARN ( " CCK and short slot \n " ) ;
2011-02-21 11:27:26 -08:00
error = true ;
}
2011-11-15 14:45:59 +01:00
if ( ( rxon - > flags & ( RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK ) ) = =
( RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK ) ) {
2011-08-18 22:07:57 +02:00
IL_WARN ( " CCK and auto detect " ) ;
2011-02-21 11:27:26 -08:00
error = true ;
}
2011-11-15 14:45:59 +01:00
if ( ( rxon - >
flags & ( RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK ) ) = =
RXON_FLG_TGG_PROTECT_MSK ) {
2011-08-18 22:07:57 +02:00
IL_WARN ( " TGg but no auto-detect \n " ) ;
2011-02-21 11:27:26 -08:00
error = true ;
}
if ( error )
2011-11-15 14:45:59 +01:00
IL_WARN ( " Tuning to channel %d \n " , le16_to_cpu ( rxon - > channel ) ) ;
2011-02-21 11:27:26 -08:00
if ( error ) {
2011-08-18 22:07:57 +02:00
IL_ERR ( " Invalid RXON \n " ) ;
2011-02-21 11:27:26 -08:00
return - EINVAL ;
}
return 0 ;
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_check_rxon_cmd ) ;
2011-02-21 11:27:26 -08:00
/**
2011-10-24 15:41:30 +02:00
* il_full_rxon_required - check if full RXON ( vs RXON_ASSOC ) cmd is needed
2011-10-24 16:49:25 +02:00
* @ il : staging_rxon is compared to active_rxon
2011-02-21 11:27:26 -08:00
*
* If the RXON structure is changing enough to require a new tune ,
* or is clearing the RXON_FILTER_ASSOC_MSK , then return 1 to indicate that
* a new tune ( full RXON command , rather than RXON_ASSOC cmd ) is required .
*/
2011-11-15 14:45:59 +01:00
int
2012-02-03 17:31:57 +01:00
il_full_rxon_required ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
2012-02-03 17:31:37 +01:00
const struct il_rxon_cmd * staging = & il - > staging ;
const struct il_rxon_cmd * active = & il - > active ;
2011-02-21 11:27:26 -08:00
# define CHK(cond) \
if ( ( cond ) ) { \
2011-11-15 11:21:01 +01:00
D_INFO ( " need full RXON - " # cond " \n " ) ; \
2011-02-21 11:27:26 -08:00
return 1 ; \
}
# define CHK_NEQ(c1, c2) \
if ( ( c1 ) ! = ( c2 ) ) { \
2011-11-15 11:21:01 +01:00
D_INFO ( " need full RXON - " \
2011-02-21 11:27:26 -08:00
# c1 " != " #c2 " - %d != %d\n", \
( c1 ) , ( c2 ) ) ; \
return 1 ; \
}
/* These items are only settable from the full RXON command */
2012-02-03 17:31:37 +01:00
CHK ( ! il_is_associated ( il ) ) ;
2011-02-21 11:27:26 -08:00
CHK ( compare_ether_addr ( staging - > bssid_addr , active - > bssid_addr ) ) ;
CHK ( compare_ether_addr ( staging - > node_addr , active - > node_addr ) ) ;
2011-11-15 14:45:59 +01:00
CHK ( compare_ether_addr
( staging - > wlap_bssid_addr , active - > wlap_bssid_addr ) ) ;
2011-02-21 11:27:26 -08:00
CHK_NEQ ( staging - > dev_type , active - > dev_type ) ;
CHK_NEQ ( staging - > channel , active - > channel ) ;
CHK_NEQ ( staging - > air_propagation , active - > air_propagation ) ;
CHK_NEQ ( staging - > ofdm_ht_single_stream_basic_rates ,
active - > ofdm_ht_single_stream_basic_rates ) ;
CHK_NEQ ( staging - > ofdm_ht_dual_stream_basic_rates ,
active - > ofdm_ht_dual_stream_basic_rates ) ;
CHK_NEQ ( staging - > assoc_id , active - > assoc_id ) ;
/* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can
* be updated with the RXON_ASSOC command - - however only some
* flag transitions are allowed using RXON_ASSOC */
/* Check if we are not switching bands */
CHK_NEQ ( staging - > flags & RXON_FLG_BAND_24G_MSK ,
active - > flags & RXON_FLG_BAND_24G_MSK ) ;
/* Check if we are switching association toggle */
CHK_NEQ ( staging - > filter_flags & RXON_FILTER_ASSOC_MSK ,
active - > filter_flags & RXON_FILTER_ASSOC_MSK ) ;
# undef CHK
# undef CHK_NEQ
return 0 ;
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_full_rxon_required ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
u8
2012-02-03 17:31:57 +01:00
il_get_lowest_plcp ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
/*
* Assign the lowest rate - - should really get this from
* the beacon skb from mac80211 .
*/
2012-02-03 17:31:37 +01:00
if ( il - > staging . flags & RXON_FLG_BAND_24G_MSK )
2011-08-26 16:07:43 +02:00
return RATE_1M_PLCP ;
2011-02-21 11:27:26 -08:00
else
2011-08-26 16:07:43 +02:00
return RATE_6M_PLCP ;
2011-02-21 11:27:26 -08:00
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_get_lowest_plcp ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
static void
2012-02-03 17:31:57 +01:00
_il_set_rxon_ht ( struct il_priv * il , struct il_ht_config * ht_conf )
2011-02-21 11:27:26 -08:00
{
2012-02-03 17:31:37 +01:00
struct il_rxon_cmd * rxon = & il - > staging ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:52 +01:00
if ( ! il - > ht . enabled ) {
2011-11-15 14:45:59 +01:00
rxon - > flags & =
~ ( RXON_FLG_CHANNEL_MODE_MSK |
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | RXON_FLG_HT40_PROT_MSK
| RXON_FLG_HT_PROT_MSK ) ;
2011-02-21 11:27:26 -08:00
return ;
}
2011-11-15 14:45:59 +01:00
rxon - > flags | =
2012-02-03 17:31:52 +01:00
cpu_to_le32 ( il - > ht . protection < < RXON_FLG_HT_OPERATING_MODE_POS ) ;
2011-02-21 11:27:26 -08:00
/* Set up channel bandwidth:
* 20 MHz only , 20 / 40 mixed or pure 40 if ht40 ok */
/* clear the HT channel mode before set the mode */
2011-11-15 14:45:59 +01:00
rxon - > flags & =
~ ( RXON_FLG_CHANNEL_MODE_MSK | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK ) ;
2012-02-03 17:31:57 +01:00
if ( il_is_ht40_tx_allowed ( il , NULL ) ) {
2011-02-21 11:27:26 -08:00
/* pure ht40 */
2012-02-03 17:31:52 +01:00
if ( il - > ht . protection = = IEEE80211_HT_OP_MODE_PROTECTION_20MHZ ) {
2011-02-21 11:27:26 -08:00
rxon - > flags | = RXON_FLG_CHANNEL_MODE_PURE_40 ;
/* Note: control channel is opposite of extension channel */
2012-02-03 17:31:52 +01:00
switch ( il - > ht . extension_chan_offset ) {
2011-02-21 11:27:26 -08:00
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE :
rxon - > flags & =
2011-11-15 14:45:59 +01:00
~ RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK ;
2011-02-21 11:27:26 -08:00
break ;
case IEEE80211_HT_PARAM_CHA_SEC_BELOW :
2011-11-15 14:45:59 +01:00
rxon - > flags | = RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK ;
2011-02-21 11:27:26 -08:00
break ;
}
} else {
/* Note: control channel is opposite of extension channel */
2012-02-03 17:31:52 +01:00
switch ( il - > ht . extension_chan_offset ) {
2011-02-21 11:27:26 -08:00
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE :
rxon - > flags & =
2011-11-15 14:45:59 +01:00
~ ( RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK ) ;
2011-02-21 11:27:26 -08:00
rxon - > flags | = RXON_FLG_CHANNEL_MODE_MIXED ;
break ;
case IEEE80211_HT_PARAM_CHA_SEC_BELOW :
2011-11-15 14:45:59 +01:00
rxon - > flags | = RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK ;
2011-02-21 11:27:26 -08:00
rxon - > flags | = RXON_FLG_CHANNEL_MODE_MIXED ;
break ;
case IEEE80211_HT_PARAM_CHA_SEC_NONE :
default :
/* channel location only valid if in Mixed mode */
2011-11-15 14:45:59 +01:00
IL_ERR ( " invalid extension channel offset \n " ) ;
2011-02-21 11:27:26 -08:00
break ;
}
}
} else {
rxon - > flags | = RXON_FLG_CHANNEL_MODE_LEGACY ;
}
2011-10-24 16:49:25 +02:00
if ( il - > cfg - > ops - > hcmd - > set_rxon_chain )
2012-02-03 17:31:57 +01:00
il - > cfg - > ops - > hcmd - > set_rxon_chain ( il ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 11:21:01 +01:00
D_ASSOC ( " rxon flags 0x%X operation mode :0x%X "
2011-11-15 14:45:59 +01:00
" extension channel offset 0x%x \n " , le32_to_cpu ( rxon - > flags ) ,
2012-02-03 17:31:52 +01:00
il - > ht . protection , il - > ht . extension_chan_offset ) ;
2011-02-21 11:27:26 -08:00
}
2011-11-15 14:45:59 +01:00
void
il_set_rxon_ht ( struct il_priv * il , struct il_ht_config * ht_conf )
2011-02-21 11:27:26 -08:00
{
2012-02-03 17:31:57 +01:00
_il_set_rxon_ht ( il , ht_conf ) ;
2011-02-21 11:27:26 -08:00
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_set_rxon_ht ) ;
2011-02-21 11:27:26 -08:00
/* Return valid, unused, channel for a passive scan to reset the RF */
2011-11-15 14:45:59 +01:00
u8
il_get_single_channel_number ( struct il_priv * il , enum ieee80211_band band )
2011-02-21 11:27:26 -08:00
{
2011-10-24 15:41:30 +02:00
const struct il_channel_info * ch_info ;
2011-02-21 11:27:26 -08:00
int i ;
u8 channel = 0 ;
u8 min , max ;
if ( band = = IEEE80211_BAND_5GHZ ) {
min = 14 ;
2011-10-24 16:49:25 +02:00
max = il - > channel_count ;
2011-02-21 11:27:26 -08:00
} else {
min = 0 ;
max = 14 ;
}
for ( i = min ; i < max ; i + + ) {
2011-08-29 12:52:20 +02:00
channel = il - > channel_info [ i ] . channel ;
2012-02-03 17:31:37 +01:00
if ( channel = = le16_to_cpu ( il - > staging . channel ) )
2011-02-21 11:27:26 -08:00
continue ;
2011-10-24 16:49:25 +02:00
ch_info = il_get_channel_info ( il , band , channel ) ;
2011-10-24 15:41:30 +02:00
if ( il_is_channel_valid ( ch_info ) )
2011-02-21 11:27:26 -08:00
break ;
}
return channel ;
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_get_single_channel_number ) ;
2011-02-21 11:27:26 -08:00
/**
2011-10-24 15:41:30 +02:00
* il_set_rxon_channel - Set the band and channel values in staging RXON
2011-02-21 11:27:26 -08:00
* @ ch : requested channel as a pointer to struct ieee80211_channel
* NOTE : Does not commit to the hardware ; it sets appropriate bit fields
* in the staging RXON flag structure based on the ch - > band
*/
int
2012-02-03 17:31:57 +01:00
il_set_rxon_channel ( struct il_priv * il , struct ieee80211_channel * ch )
2011-02-21 11:27:26 -08:00
{
enum ieee80211_band band = ch - > band ;
u16 channel = ch - > hw_value ;
2012-02-03 17:31:37 +01:00
if ( le16_to_cpu ( il - > staging . channel ) = = channel & & il - > band = = band )
2011-02-21 11:27:26 -08:00
return 0 ;
2012-02-03 17:31:37 +01:00
il - > staging . channel = cpu_to_le16 ( channel ) ;
2011-02-21 11:27:26 -08:00
if ( band = = IEEE80211_BAND_5GHZ )
2012-02-03 17:31:37 +01:00
il - > staging . flags & = ~ RXON_FLG_BAND_24G_MSK ;
2011-02-21 11:27:26 -08:00
else
2012-02-03 17:31:37 +01:00
il - > staging . flags | = RXON_FLG_BAND_24G_MSK ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
il - > band = band ;
2011-02-21 11:27:26 -08:00
2011-11-15 11:21:01 +01:00
D_INFO ( " Staging channel set to %d [%d] \n " , channel , band ) ;
2011-02-21 11:27:26 -08:00
return 0 ;
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_set_rxon_channel ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
void
2012-02-03 17:31:57 +01:00
il_set_flags_for_band ( struct il_priv * il , enum ieee80211_band band ,
struct ieee80211_vif * vif )
2011-02-21 11:27:26 -08:00
{
if ( band = = IEEE80211_BAND_5GHZ ) {
2012-02-03 17:31:37 +01:00
il - > staging . flags & =
2011-11-15 14:45:59 +01:00
~ ( RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK |
RXON_FLG_CCK_MSK ) ;
2012-02-03 17:31:37 +01:00
il - > staging . flags | = RXON_FLG_SHORT_SLOT_MSK ;
2011-02-21 11:27:26 -08:00
} else {
2011-10-24 15:41:30 +02:00
/* Copied from il_post_associate() */
2011-02-21 11:27:26 -08:00
if ( vif & & vif - > bss_conf . use_short_slot )
2012-02-03 17:31:37 +01:00
il - > staging . flags | = RXON_FLG_SHORT_SLOT_MSK ;
2011-02-21 11:27:26 -08:00
else
2012-02-03 17:31:37 +01:00
il - > staging . flags & = ~ RXON_FLG_SHORT_SLOT_MSK ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:37 +01:00
il - > staging . flags | = RXON_FLG_BAND_24G_MSK ;
il - > staging . flags | = RXON_FLG_AUTO_DETECT_MSK ;
il - > staging . flags & = ~ RXON_FLG_CCK_MSK ;
2011-02-21 11:27:26 -08:00
}
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_set_flags_for_band ) ;
2011-02-21 11:27:26 -08:00
/*
* initialize rxon structure with default values from eeprom
*/
2011-11-15 14:45:59 +01:00
void
2012-02-03 17:31:57 +01:00
il_connection_init_rx_config ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
2011-10-24 15:41:30 +02:00
const struct il_channel_info * ch_info ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:37 +01:00
memset ( & il - > staging , 0 , sizeof ( il - > staging ) ) ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:57 +01:00
if ( ! il - > vif ) {
2012-02-03 17:31:45 +01:00
il - > staging . dev_type = RXON_DEV_TYPE_ESS ;
2012-02-03 17:31:57 +01:00
} else if ( il - > vif - > type = = NL80211_IFTYPE_STATION ) {
il - > staging . dev_type = RXON_DEV_TYPE_ESS ;
il - > staging . filter_flags = RXON_FILTER_ACCEPT_GRP_MSK ;
} else if ( il - > vif - > type = = NL80211_IFTYPE_ADHOC ) {
il - > staging . dev_type = RXON_DEV_TYPE_IBSS ;
il - > staging . flags = RXON_FLG_SHORT_PREAMBLE_MSK ;
il - > staging . filter_flags =
RXON_FILTER_BCON_AWARE_MSK | RXON_FILTER_ACCEPT_GRP_MSK ;
} else {
IL_ERR ( " Unsupported interface type %d \n " , il - > vif - > type ) ;
return ;
}
2011-02-21 11:27:26 -08:00
#if 0
/* TODO: Figure out when short_preamble would be set and cache from
* that */
2011-10-24 16:49:25 +02:00
if ( ! hw_to_local ( il - > hw ) - > short_preamble )
2012-02-03 17:31:37 +01:00
il - > staging . flags & = ~ RXON_FLG_SHORT_PREAMBLE_MSK ;
2011-02-21 11:27:26 -08:00
else
2012-02-03 17:31:37 +01:00
il - > staging . flags | = RXON_FLG_SHORT_PREAMBLE_MSK ;
2011-02-21 11:27:26 -08:00
# endif
2011-11-15 14:45:59 +01:00
ch_info =
2012-02-03 17:31:37 +01:00
il_get_channel_info ( il , il - > band , le16_to_cpu ( il - > active . channel ) ) ;
2011-02-21 11:27:26 -08:00
if ( ! ch_info )
2011-10-24 16:49:25 +02:00
ch_info = & il - > channel_info [ 0 ] ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:37 +01:00
il - > staging . channel = cpu_to_le16 ( ch_info - > channel ) ;
2011-10-24 16:49:25 +02:00
il - > band = ch_info - > band ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:57 +01:00
il_set_flags_for_band ( il , il - > band , il - > vif ) ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:37 +01:00
il - > staging . ofdm_basic_rates =
2011-10-24 15:41:30 +02:00
( IL_OFDM_RATES_MASK > > IL_FIRST_OFDM_RATE ) & 0xFF ;
2012-02-03 17:31:37 +01:00
il - > staging . cck_basic_rates =
2011-10-24 15:41:30 +02:00
( IL_CCK_RATES_MASK > > IL_FIRST_CCK_RATE ) & 0xF ;
2011-02-21 11:27:26 -08:00
/* clear both MIX and PURE40 mode flag */
2012-02-03 17:31:37 +01:00
il - > staging . flags & =
2011-11-15 14:45:59 +01:00
~ ( RXON_FLG_CHANNEL_MODE_MIXED | RXON_FLG_CHANNEL_MODE_PURE_40 ) ;
2012-02-03 17:31:57 +01:00
if ( il - > vif )
memcpy ( il - > staging . node_addr , il - > vif - > addr , ETH_ALEN ) ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:37 +01:00
il - > staging . ofdm_ht_single_stream_basic_rates = 0xff ;
il - > staging . ofdm_ht_dual_stream_basic_rates = 0xff ;
2011-02-21 11:27:26 -08:00
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_connection_init_rx_config ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
void
il_set_rate ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
const struct ieee80211_supported_band * hw = NULL ;
struct ieee80211_rate * rate ;
int i ;
2011-10-24 16:49:25 +02:00
hw = il_get_hw_mode ( il , il - > band ) ;
2011-02-21 11:27:26 -08:00
if ( ! hw ) {
2011-08-18 22:07:57 +02:00
IL_ERR ( " Failed to set rate: unable to get hw mode \n " ) ;
2011-02-21 11:27:26 -08:00
return ;
}
2011-10-24 16:49:25 +02:00
il - > active_rate = 0 ;
2011-02-21 11:27:26 -08:00
for ( i = 0 ; i < hw - > n_bitrates ; i + + ) {
rate = & ( hw - > bitrates [ i ] ) ;
2011-08-26 16:07:43 +02:00
if ( rate - > hw_value < RATE_COUNT_LEGACY )
2011-10-24 16:49:25 +02:00
il - > active_rate | = ( 1 < < rate - > hw_value ) ;
2011-02-21 11:27:26 -08:00
}
2011-11-15 11:21:01 +01:00
D_RATE ( " Set active_rate = %0x \n " , il - > active_rate ) ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:37 +01:00
il - > staging . cck_basic_rates =
2011-11-15 14:45:59 +01:00
( IL_CCK_BASIC_RATES_MASK > > IL_FIRST_CCK_RATE ) & 0xF ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:37 +01:00
il - > staging . ofdm_basic_rates =
2011-11-15 14:45:59 +01:00
( IL_OFDM_BASIC_RATES_MASK > > IL_FIRST_OFDM_RATE ) & 0xFF ;
2011-02-21 11:27:26 -08:00
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_set_rate ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
void
il_chswitch_done ( struct il_priv * il , bool is_success )
2011-02-21 11:27:26 -08:00
{
2011-11-15 13:09:01 +01:00
if ( test_bit ( S_EXIT_PENDING , & il - > status ) )
2011-02-21 11:27:26 -08:00
return ;
2011-11-15 13:09:01 +01:00
if ( test_and_clear_bit ( S_CHANNEL_SWITCH_PENDING , & il - > status ) )
2012-02-03 17:31:57 +01:00
ieee80211_chswitch_done ( il - > vif , is_success ) ;
2011-02-21 11:27:26 -08:00
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_chswitch_done ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
void
il_hdl_csa ( struct il_priv * il , struct il_rx_buf * rxb )
2011-02-21 11:27:26 -08:00
{
2011-08-26 14:36:21 +02:00
struct il_rx_pkt * pkt = rxb_addr ( rxb ) ;
2011-10-24 15:41:30 +02:00
struct il_csa_notification * csa = & ( pkt - > u . csa_notif ) ;
2012-02-03 17:31:37 +01:00
struct il_rxon_cmd * rxon = ( void * ) & il - > active ;
2011-02-21 11:27:26 -08:00
2011-11-15 13:09:01 +01:00
if ( ! test_bit ( S_CHANNEL_SWITCH_PENDING , & il - > status ) )
2011-06-08 15:26:31 +02:00
return ;
2011-10-24 16:49:25 +02:00
if ( ! le32_to_cpu ( csa - > status ) & & csa - > channel = = il - > switch_channel ) {
2011-06-08 15:26:31 +02:00
rxon - > channel = csa - > channel ;
2012-02-03 17:31:37 +01:00
il - > staging . channel = csa - > channel ;
2011-11-15 14:45:59 +01:00
D_11H ( " CSA notif: channel %d \n " , le16_to_cpu ( csa - > channel ) ) ;
2011-10-24 16:49:25 +02:00
il_chswitch_done ( il , true ) ;
2011-06-08 15:26:31 +02:00
} else {
2011-08-18 22:07:57 +02:00
IL_ERR ( " CSA notif (fail) : channel %d \n " ,
2011-11-15 14:45:59 +01:00
le16_to_cpu ( csa - > channel ) ) ;
2011-10-24 16:49:25 +02:00
il_chswitch_done ( il , false ) ;
2011-02-21 11:27:26 -08:00
}
}
2011-11-15 13:16:38 +01:00
EXPORT_SYMBOL ( il_hdl_csa ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 11:25:42 +01:00
# ifdef CONFIG_IWLEGACY_DEBUG
2011-11-15 14:45:59 +01:00
void
2012-02-03 17:31:57 +01:00
il_print_rx_config_cmd ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
2012-02-03 17:31:37 +01:00
struct il_rxon_cmd * rxon = & il - > staging ;
2011-02-21 11:27:26 -08:00
2011-11-15 11:21:01 +01:00
D_RADIO ( " RX CONFIG: \n " ) ;
2011-10-24 16:49:25 +02:00
il_print_hex_dump ( il , IL_DL_RADIO , ( u8 * ) rxon , sizeof ( * rxon ) ) ;
2011-11-15 14:45:59 +01:00
D_RADIO ( " u16 channel: 0x%x \n " , le16_to_cpu ( rxon - > channel ) ) ;
2011-11-15 11:21:01 +01:00
D_RADIO ( " u32 flags: 0x%08X \n " , le32_to_cpu ( rxon - > flags ) ) ;
2011-11-15 14:45:59 +01:00
D_RADIO ( " u32 filter_flags: 0x%08x \n " , le32_to_cpu ( rxon - > filter_flags ) ) ;
2011-11-15 11:21:01 +01:00
D_RADIO ( " u8 dev_type: 0x%x \n " , rxon - > dev_type ) ;
2011-11-15 14:45:59 +01:00
D_RADIO ( " u8 ofdm_basic_rates: 0x%02x \n " , rxon - > ofdm_basic_rates ) ;
D_RADIO ( " u8 cck_basic_rates: 0x%02x \n " , rxon - > cck_basic_rates ) ;
2011-11-15 11:21:01 +01:00
D_RADIO ( " u8[6] node_addr: %pM \n " , rxon - > node_addr ) ;
D_RADIO ( " u8[6] bssid_addr: %pM \n " , rxon - > bssid_addr ) ;
2011-11-15 14:45:59 +01:00
D_RADIO ( " u16 assoc_id: 0x%x \n " , le16_to_cpu ( rxon - > assoc_id ) ) ;
2011-02-21 11:27:26 -08:00
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_print_rx_config_cmd ) ;
2011-02-21 11:27:26 -08:00
# endif
/**
2011-10-24 15:41:30 +02:00
* il_irq_handle_error - called for HW or SW error interrupt from card
2011-02-21 11:27:26 -08:00
*/
2011-11-15 14:45:59 +01:00
void
il_irq_handle_error ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
2011-10-24 15:41:30 +02:00
/* Set the FW error flag -- cleared on il_down */
2011-11-15 13:09:01 +01:00
set_bit ( S_FW_ERROR , & il - > status ) ;
2011-02-21 11:27:26 -08:00
/* Cancel currently queued command. */
2011-11-15 13:09:01 +01:00
clear_bit ( S_HCMD_ACTIVE , & il - > status ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
IL_ERR ( " Loaded firmware version: %s \n " , il - > hw - > wiphy - > fw_version ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
il - > cfg - > ops - > lib - > dump_nic_error_log ( il ) ;
if ( il - > cfg - > ops - > lib - > dump_fh )
il - > cfg - > ops - > lib - > dump_fh ( il , NULL , false ) ;
2011-11-15 11:25:42 +01:00
# ifdef CONFIG_IWLEGACY_DEBUG
2011-10-24 16:49:25 +02:00
if ( il_get_debug_level ( il ) & IL_DL_FW_ERRORS )
2012-02-03 17:31:57 +01:00
il_print_rx_config_cmd ( il ) ;
2011-02-21 11:27:26 -08:00
# endif
2011-10-24 16:49:25 +02:00
wake_up ( & il - > wait_command_queue ) ;
2011-02-21 11:27:26 -08:00
/* Keep the restart process from trying to send host
* commands by clearing the INIT status bit */
2011-11-15 13:09:01 +01:00
clear_bit ( S_READY , & il - > status ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 13:09:01 +01:00
if ( ! test_bit ( S_EXIT_PENDING , & il - > status ) ) {
2011-11-15 11:21:01 +01:00
IL_DBG ( IL_DL_FW_ERRORS ,
2011-11-15 14:45:59 +01:00
" Restarting adapter due to uCode error. \n " ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
if ( il - > cfg - > mod_params - > restart_fw )
queue_work ( il - > workqueue , & il - > restart ) ;
2011-02-21 11:27:26 -08:00
}
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_irq_handle_error ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
static int
il_apm_stop_master ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
int ret = 0 ;
/* stop device's busmaster DMA activity */
2011-10-24 16:49:25 +02:00
il_set_bit ( il , CSR_RESET , CSR_RESET_REG_FLAG_STOP_MASTER ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
ret =
_il_poll_bit ( il , CSR_RESET , CSR_RESET_REG_FLAG_MASTER_DISABLED ,
CSR_RESET_REG_FLAG_MASTER_DISABLED , 100 ) ;
2011-02-21 11:27:26 -08:00
if ( ret )
2011-08-18 22:07:57 +02:00
IL_WARN ( " Master Disable Timed Out, 100 usec \n " ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 11:21:01 +01:00
D_INFO ( " stop master \n " ) ;
2011-02-21 11:27:26 -08:00
return ret ;
}
2011-11-15 14:45:59 +01:00
void
il_apm_stop ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
2011-11-15 11:21:01 +01:00
D_INFO ( " Stop card, put in low power state \n " ) ;
2011-02-21 11:27:26 -08:00
/* Stop device's DMA activity */
2011-10-24 16:49:25 +02:00
il_apm_stop_master ( il ) ;
2011-02-21 11:27:26 -08:00
/* Reset the entire device */
2011-10-24 16:49:25 +02:00
il_set_bit ( il , CSR_RESET , CSR_RESET_REG_FLAG_SW_RESET ) ;
2011-02-21 11:27:26 -08:00
udelay ( 10 ) ;
/*
* Clear " initialization complete " bit to move adapter from
* D0A * ( powered - up Active ) - - > D0U * ( Uninitialized ) state .
*/
2011-11-15 14:45:59 +01:00
il_clear_bit ( il , CSR_GP_CNTRL , CSR_GP_CNTRL_REG_FLAG_INIT_DONE ) ;
2011-02-21 11:27:26 -08:00
}
2011-11-15 14:45:59 +01:00
EXPORT_SYMBOL ( il_apm_stop ) ;
2011-02-21 11:27:26 -08:00
/*
* Start up NIC ' s basic functionality after it has been reset
2011-10-24 15:41:30 +02:00
* ( e . g . after platform boot , or shutdown via il_apm_stop ( ) )
2011-02-21 11:27:26 -08:00
* NOTE : This does not load uCode nor start the embedded processor
*/
2011-11-15 14:45:59 +01:00
int
il_apm_init ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
int ret = 0 ;
u16 lctl ;
2011-11-15 11:21:01 +01:00
D_INFO ( " Init card's basic functions \n " ) ;
2011-02-21 11:27:26 -08:00
/*
* Use " set_bit " below rather than " write " , to preserve any hardware
* bits already set by default after reset .
*/
/* Disable L0S exit timer (platform NMI Work/Around) */
2011-10-24 16:49:25 +02:00
il_set_bit ( il , CSR_GIO_CHICKEN_BITS ,
2011-11-15 14:45:59 +01:00
CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER ) ;
2011-02-21 11:27:26 -08:00
/*
* Disable L0s without affecting L1 ;
* don ' t wait for ICH L0s ( ICH bug W / A )
*/
2011-10-24 16:49:25 +02:00
il_set_bit ( il , CSR_GIO_CHICKEN_BITS ,
2011-11-15 14:45:59 +01:00
CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX ) ;
2011-02-21 11:27:26 -08:00
/* Set FH wait threshold to maximum (HW error during stress W/A) */
2011-11-15 14:45:59 +01:00
il_set_bit ( il , CSR_DBG_HPET_MEM_REG , CSR_DBG_HPET_MEM_REG_VAL ) ;
2011-02-21 11:27:26 -08:00
/*
* Enable HAP INTA ( interrupt from management bus ) to
* wake device ' s PCI Express link L1a - > L0s
2011-03-30 22:57:33 -03:00
* NOTE : This is no - op for 3945 ( non - existent bit )
2011-02-21 11:27:26 -08:00
*/
2011-10-24 16:49:25 +02:00
il_set_bit ( il , CSR_HW_IF_CONFIG_REG ,
2011-11-15 14:45:59 +01:00
CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A ) ;
2011-02-21 11:27:26 -08:00
/*
* HW bug W / A for instability in PCIe bus L0 - > L0S - > L1 transition .
* Check if BIOS ( or OS ) enabled L1 - ASPM on this device .
* If so ( likely ) , disable L0S , so device moves directly L0 - > L1 ;
* costs negligible amount of power savings .
* If not ( unlikely ) , enable L0S , so there is at least some
* power savings , even without L1 .
*/
2011-10-24 16:49:25 +02:00
if ( il - > cfg - > base_params - > set_l0s ) {
lctl = il_pcie_link_ctl ( il ) ;
2011-02-21 11:27:26 -08:00
if ( ( lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN ) = =
2011-11-15 14:45:59 +01:00
PCI_CFG_LINK_CTRL_VAL_L1_EN ) {
2011-02-21 11:27:26 -08:00
/* L1-ASPM enabled; disable(!) L0S */
2011-10-24 16:49:25 +02:00
il_set_bit ( il , CSR_GIO_REG ,
2011-11-15 14:45:59 +01:00
CSR_GIO_REG_VAL_L0S_ENABLED ) ;
2011-11-15 11:21:01 +01:00
D_POWER ( " L1 Enabled; Disabling L0S \n " ) ;
2011-02-21 11:27:26 -08:00
} else {
/* L1-ASPM disabled; enable(!) L0S */
2011-10-24 16:49:25 +02:00
il_clear_bit ( il , CSR_GIO_REG ,
2011-11-15 14:45:59 +01:00
CSR_GIO_REG_VAL_L0S_ENABLED ) ;
2011-11-15 11:21:01 +01:00
D_POWER ( " L1 Disabled; Enabling L0S \n " ) ;
2011-02-21 11:27:26 -08:00
}
}
/* Configure analog phase-lock-loop before activating to D0A */
2011-10-24 16:49:25 +02:00
if ( il - > cfg - > base_params - > pll_cfg_val )
il_set_bit ( il , CSR_ANA_PLL_CFG ,
2011-11-15 14:45:59 +01:00
il - > cfg - > base_params - > pll_cfg_val ) ;
2011-02-21 11:27:26 -08:00
/*
* Set " initialization complete " bit to move adapter from
* D0U * - - > D0A * ( powered - up active ) state .
*/
2011-10-24 16:49:25 +02:00
il_set_bit ( il , CSR_GP_CNTRL , CSR_GP_CNTRL_REG_FLAG_INIT_DONE ) ;
2011-02-21 11:27:26 -08:00
/*
* Wait for clock stabilization ; once stabilized , access to
2011-08-24 21:06:33 +02:00
* device - internal resources is supported , e . g . il_wr_prph ( )
2011-02-21 11:27:26 -08:00
* and accesses to uCode SRAM .
*/
2011-11-15 14:45:59 +01:00
ret =
_il_poll_bit ( il , CSR_GP_CNTRL ,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY ,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY , 25000 ) ;
2011-02-21 11:27:26 -08:00
if ( ret < 0 ) {
2011-11-15 11:21:01 +01:00
D_INFO ( " Failed to init the card \n " ) ;
2011-02-21 11:27:26 -08:00
goto out ;
}
/*
* Enable DMA and BSM ( if used ) clocks , wait for them to stabilize .
* BSM ( Boostrap State Machine ) is only in 3945 and 4965.
*
* Write to " CLK_EN_REG " ; " 1 " bits enable clocks , while " 0 " bits
* do not disable clocks . This preserves any hardware bits already
* set by default in " CLK_CTRL_REG " after reset .
*/
2011-10-24 16:49:25 +02:00
if ( il - > cfg - > base_params - > use_bsm )
2011-08-24 21:06:33 +02:00
il_wr_prph ( il , APMG_CLK_EN_REG ,
2011-11-15 14:45:59 +01:00
APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT ) ;
2011-02-21 11:27:26 -08:00
else
2011-11-15 14:45:59 +01:00
il_wr_prph ( il , APMG_CLK_EN_REG , APMG_CLK_VAL_DMA_CLK_RQT ) ;
2011-02-21 11:27:26 -08:00
udelay ( 20 ) ;
/* Disable L1-Active */
2011-10-24 16:49:25 +02:00
il_set_bits_prph ( il , APMG_PCIDEV_STT_REG ,
2011-11-15 14:45:59 +01:00
APMG_PCIDEV_STT_VAL_L1_ACT_DIS ) ;
2011-02-21 11:27:26 -08:00
out :
return ret ;
}
2011-11-15 14:45:59 +01:00
EXPORT_SYMBOL ( il_apm_init ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
int
il_set_tx_power ( struct il_priv * il , s8 tx_power , bool force )
2011-02-21 11:27:26 -08:00
{
int ret ;
s8 prev_tx_power ;
2011-02-24 14:23:55 +01:00
bool defer ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
lockdep_assert_held ( & il - > mutex ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
if ( il - > tx_power_user_lmt = = tx_power & & ! force )
2011-02-21 11:27:26 -08:00
return 0 ;
2011-10-24 16:49:25 +02:00
if ( ! il - > cfg - > ops - > lib - > send_tx_power )
2011-02-21 11:27:26 -08:00
return - EOPNOTSUPP ;
2011-04-13 10:56:51 +02:00
/* 0 dBm mean 1 milliwatt */
if ( tx_power < 0 ) {
2011-11-15 14:45:59 +01:00
IL_WARN ( " Requested user TXPOWER %d below 1 mW. \n " , tx_power ) ;
2011-02-21 11:27:26 -08:00
return - EINVAL ;
}
2011-10-24 16:49:25 +02:00
if ( tx_power > il - > tx_power_device_lmt ) {
2011-11-15 14:45:59 +01:00
IL_WARN ( " Requested user TXPOWER %d above upper limit %d. \n " ,
tx_power , il - > tx_power_device_lmt ) ;
2011-02-21 11:27:26 -08:00
return - EINVAL ;
}
2011-10-24 16:49:25 +02:00
if ( ! il_is_ready_rf ( il ) )
2011-02-21 11:27:26 -08:00
return - EIO ;
2011-02-24 14:23:55 +01:00
/* scan complete and commit_rxon use tx_power_next value,
* it always need to be updated for newest request */
2011-10-24 16:49:25 +02:00
il - > tx_power_next = tx_power ;
2011-02-24 14:23:55 +01:00
/* do not set tx power when scanning or channel changing */
2011-11-15 13:09:01 +01:00
defer = test_bit ( S_SCANNING , & il - > status ) | |
2012-02-03 17:31:37 +01:00
memcmp ( & il - > active , & il - > staging , sizeof ( il - > staging ) ) ;
2011-02-24 14:23:55 +01:00
if ( defer & & ! force ) {
2011-11-15 11:21:01 +01:00
D_INFO ( " Deferring tx power set \n " ) ;
2011-02-21 11:27:26 -08:00
return 0 ;
}
2011-10-24 16:49:25 +02:00
prev_tx_power = il - > tx_power_user_lmt ;
il - > tx_power_user_lmt = tx_power ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
ret = il - > cfg - > ops - > lib - > send_tx_power ( il ) ;
2011-02-21 11:27:26 -08:00
/* if fail to set tx_power, restore the orig. tx power */
if ( ret ) {
2011-10-24 16:49:25 +02:00
il - > tx_power_user_lmt = prev_tx_power ;
il - > tx_power_next = prev_tx_power ;
2011-02-21 11:27:26 -08:00
}
return ret ;
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_set_tx_power ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
void
il_send_bt_config ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
2011-10-24 15:41:30 +02:00
struct il_bt_cmd bt_cmd = {
2011-02-21 11:27:26 -08:00
. lead_time = BT_LEAD_TIME_DEF ,
. max_kill = BT_MAX_KILL_DEF ,
. kill_ack_mask = 0 ,
. kill_cts_mask = 0 ,
} ;
if ( ! bt_coex_active )
bt_cmd . flags = BT_COEX_DISABLE ;
else
bt_cmd . flags = BT_COEX_ENABLE ;
2011-11-15 11:21:01 +01:00
D_INFO ( " BT coex %s \n " ,
2011-11-15 14:45:59 +01:00
( bt_cmd . flags = = BT_COEX_DISABLE ) ? " disable " : " active " ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
if ( il_send_cmd_pdu ( il , C_BT_CONFIG , sizeof ( struct il_bt_cmd ) , & bt_cmd ) )
2011-08-18 22:07:57 +02:00
IL_ERR ( " failed to send BT Coex Config \n " ) ;
2011-02-21 11:27:26 -08:00
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_send_bt_config ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
int
il_send_stats_request ( struct il_priv * il , u8 flags , bool clear )
2011-02-21 11:27:26 -08:00
{
2011-08-26 15:43:47 +02:00
struct il_stats_cmd stats_cmd = {
2011-11-15 14:45:59 +01:00
. configuration_flags = clear ? IL_STATS_CONF_CLEAR_STATS : 0 ,
2011-02-21 11:27:26 -08:00
} ;
if ( flags & CMD_ASYNC )
2011-11-15 14:45:59 +01:00
return il_send_cmd_pdu_async ( il , C_STATS , sizeof ( struct il_stats_cmd ) ,
& stats_cmd , NULL ) ;
2011-02-21 11:27:26 -08:00
else
2011-11-15 14:45:59 +01:00
return il_send_cmd_pdu ( il , C_STATS , sizeof ( struct il_stats_cmd ) ,
& stats_cmd ) ;
2011-02-21 11:27:26 -08:00
}
2011-08-26 15:43:47 +02:00
EXPORT_SYMBOL ( il_send_stats_request ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
void
il_hdl_pm_sleep ( struct il_priv * il , struct il_rx_buf * rxb )
2011-02-21 11:27:26 -08:00
{
2011-11-15 11:25:42 +01:00
# ifdef CONFIG_IWLEGACY_DEBUG
2011-08-26 14:36:21 +02:00
struct il_rx_pkt * pkt = rxb_addr ( rxb ) ;
2011-10-24 15:41:30 +02:00
struct il_sleep_notification * sleep = & ( pkt - > u . sleep_notif ) ;
2011-11-15 11:21:01 +01:00
D_RX ( " sleep mode: %d, src: %d \n " ,
2011-11-15 14:51:01 +01:00
sleep - > pm_sleep_mode , sleep - > pm_wakeup_src ) ;
2011-02-21 11:27:26 -08:00
# endif
}
2011-11-15 13:16:38 +01:00
EXPORT_SYMBOL ( il_hdl_pm_sleep ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
void
il_hdl_pm_debug_stats ( struct il_priv * il , struct il_rx_buf * rxb )
2011-02-21 11:27:26 -08:00
{
2011-08-26 14:36:21 +02:00
struct il_rx_pkt * pkt = rxb_addr ( rxb ) ;
2011-08-31 13:23:20 +02:00
u32 len = le32_to_cpu ( pkt - > len_n_flags ) & IL_RX_FRAME_SIZE_MSK ;
2011-11-15 14:45:59 +01:00
D_RADIO ( " Dumping %d bytes of unhandled notification for %s: \n " , len ,
il_get_cmd_string ( pkt - > hdr . cmd ) ) ;
2011-10-24 16:49:25 +02:00
il_print_hex_dump ( il , IL_DL_RADIO , pkt - > u . raw , len ) ;
2011-02-21 11:27:26 -08:00
}
2011-11-15 13:16:38 +01:00
EXPORT_SYMBOL ( il_hdl_pm_debug_stats ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
void
il_hdl_error ( struct il_priv * il , struct il_rx_buf * rxb )
2011-02-21 11:27:26 -08:00
{
2011-08-26 14:36:21 +02:00
struct il_rx_pkt * pkt = rxb_addr ( rxb ) ;
2011-02-21 11:27:26 -08:00
2011-08-18 22:07:57 +02:00
IL_ERR ( " Error Reply type 0x%08X cmd %s (0x%02X) "
2011-11-15 14:45:59 +01:00
" seq 0x%04X ser 0x%08X \n " ,
le32_to_cpu ( pkt - > u . err_resp . error_type ) ,
il_get_cmd_string ( pkt - > u . err_resp . cmd_id ) ,
pkt - > u . err_resp . cmd_id ,
le16_to_cpu ( pkt - > u . err_resp . bad_cmd_seq_num ) ,
le32_to_cpu ( pkt - > u . err_resp . error_info ) ) ;
2011-02-21 11:27:26 -08:00
}
2011-08-30 15:45:31 +02:00
EXPORT_SYMBOL ( il_hdl_error ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
void
il_clear_isr_stats ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
memset ( & il - > isr_stats , 0 , sizeof ( il - > isr_stats ) ) ;
2011-02-21 11:27:26 -08:00
}
2011-11-15 14:45:59 +01:00
int
il_mac_conf_tx ( struct ieee80211_hw * hw , struct ieee80211_vif * vif , u16 queue ,
const struct ieee80211_tx_queue_params * params )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
struct il_priv * il = hw - > priv ;
2011-02-21 11:27:26 -08:00
unsigned long flags ;
int q ;
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " enter \n " ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
if ( ! il_is_ready_rf ( il ) ) {
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " leave - RF not ready \n " ) ;
2011-02-21 11:27:26 -08:00
return - EIO ;
}
if ( queue > = AC_NUM ) {
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " leave - queue >= AC_NUM %d \n " , queue ) ;
2011-02-21 11:27:26 -08:00
return 0 ;
}
q = AC_NUM - 1 - queue ;
2011-10-24 16:49:25 +02:00
spin_lock_irqsave ( & il - > lock , flags ) ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:51 +01:00
il - > qos_data . def_qos_parm . ac [ q ] . cw_min =
2011-11-15 14:45:59 +01:00
cpu_to_le16 ( params - > cw_min ) ;
2012-02-03 17:31:51 +01:00
il - > qos_data . def_qos_parm . ac [ q ] . cw_max =
2011-11-15 14:45:59 +01:00
cpu_to_le16 ( params - > cw_max ) ;
2012-02-03 17:31:51 +01:00
il - > qos_data . def_qos_parm . ac [ q ] . aifsn = params - > aifs ;
il - > qos_data . def_qos_parm . ac [ q ] . edca_txop =
2011-11-15 14:45:59 +01:00
cpu_to_le16 ( ( params - > txop * 32 ) ) ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:51 +01:00
il - > qos_data . def_qos_parm . ac [ q ] . reserved1 = 0 ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
spin_unlock_irqrestore ( & il - > lock , flags ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " leave \n " ) ;
2011-02-21 11:27:26 -08:00
return 0 ;
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_mac_conf_tx ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
int
il_mac_tx_last_beacon ( struct ieee80211_hw * hw )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
struct il_priv * il = hw - > priv ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
return il - > ibss_manager = = IL_IBSS_MANAGER ;
2011-02-21 11:27:26 -08:00
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL_GPL ( il_mac_tx_last_beacon ) ;
2011-02-21 11:27:26 -08:00
static int
2012-02-03 17:31:57 +01:00
il_set_mode ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
2012-02-03 17:31:57 +01:00
il_connection_init_rx_config ( il ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
if ( il - > cfg - > ops - > hcmd - > set_rxon_chain )
2012-02-03 17:31:57 +01:00
il - > cfg - > ops - > hcmd - > set_rxon_chain ( il ) ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:57 +01:00
return il_commit_rxon ( il ) ;
2011-02-21 11:27:26 -08:00
}
int
2011-10-24 15:41:30 +02:00
il_mac_add_interface ( struct ieee80211_hw * hw , struct ieee80211_vif * vif )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
struct il_priv * il = hw - > priv ;
2011-02-21 11:27:26 -08:00
int err ;
2011-11-15 14:45:59 +01:00
D_MAC80211 ( " enter: type %d, addr %pM \n " , vif - > type , vif - > addr ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
mutex_lock ( & il - > mutex ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
if ( ! il_is_ready_rf ( il ) ) {
2011-08-18 22:07:57 +02:00
IL_WARN ( " Try to add interface when device not ready \n " ) ;
2011-02-21 11:27:26 -08:00
err = - EINVAL ;
goto out ;
}
2012-02-03 17:31:57 +01:00
if ( il - > vif ) {
2011-02-21 11:27:26 -08:00
err = - EOPNOTSUPP ;
goto out ;
}
2012-02-03 17:31:57 +01:00
il - > vif = vif ;
2012-02-03 17:31:56 +01:00
il - > iw_mode = vif - > type ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:57 +01:00
err = il_set_mode ( il ) ;
2011-08-29 12:52:20 +02:00
if ( err ) {
2012-02-03 17:31:57 +01:00
il - > vif = NULL ;
2011-08-29 12:52:20 +02:00
il - > iw_mode = NL80211_IFTYPE_STATION ;
}
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
out :
2011-10-24 16:49:25 +02:00
mutex_unlock ( & il - > mutex ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " leave \n " ) ;
2011-02-21 11:27:26 -08:00
return err ;
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_mac_add_interface ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
static void
il_teardown_interface ( struct il_priv * il , struct ieee80211_vif * vif ,
bool mode_change )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
lockdep_assert_held ( & il - > mutex ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
if ( il - > scan_vif = = vif ) {
il_scan_cancel_timeout ( il , 200 ) ;
il_force_scan_end ( il ) ;
2011-02-21 11:27:26 -08:00
}
2012-02-03 17:31:55 +01:00
if ( ! mode_change )
2012-02-03 17:31:57 +01:00
il_set_mode ( il ) ;
2012-02-03 17:31:55 +01:00
2011-02-21 11:27:26 -08:00
}
2011-11-15 14:45:59 +01:00
void
il_mac_remove_interface ( struct ieee80211_hw * hw , struct ieee80211_vif * vif )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
struct il_priv * il = hw - > priv ;
2011-02-21 11:27:26 -08:00
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " enter \n " ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
mutex_lock ( & il - > mutex ) ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:57 +01:00
WARN_ON ( il - > vif ! = vif ) ;
il - > vif = NULL ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
il_teardown_interface ( il , vif , false ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
memset ( il - > bssid , 0 , ETH_ALEN ) ;
mutex_unlock ( & il - > mutex ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " leave \n " ) ;
2011-02-21 11:27:26 -08:00
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_mac_remove_interface ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
int
il_alloc_txq_mem ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
if ( ! il - > txq )
2011-11-15 14:45:59 +01:00
il - > txq =
kzalloc ( sizeof ( struct il_tx_queue ) *
il - > cfg - > base_params - > num_of_queues , GFP_KERNEL ) ;
2011-10-24 16:49:25 +02:00
if ( ! il - > txq ) {
2011-08-18 22:07:57 +02:00
IL_ERR ( " Not enough memory for txq \n " ) ;
2011-02-21 11:27:26 -08:00
return - ENOMEM ;
}
return 0 ;
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_alloc_txq_mem ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
void
il_txq_mem ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
kfree ( il - > txq ) ;
il - > txq = NULL ;
2011-02-21 11:27:26 -08:00
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_txq_mem ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 11:25:42 +01:00
# ifdef CONFIG_IWLEGACY_DEBUGFS
2011-02-21 11:27:26 -08:00
2011-10-24 15:41:30 +02:00
# define IL_TRAFFIC_DUMP_SIZE (IL_TRAFFIC_ENTRY_SIZE * IL_TRAFFIC_ENTRIES)
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
void
il_reset_traffic_log ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
il - > tx_traffic_idx = 0 ;
il - > rx_traffic_idx = 0 ;
if ( il - > tx_traffic )
memset ( il - > tx_traffic , 0 , IL_TRAFFIC_DUMP_SIZE ) ;
if ( il - > rx_traffic )
memset ( il - > rx_traffic , 0 , IL_TRAFFIC_DUMP_SIZE ) ;
2011-02-21 11:27:26 -08:00
}
2011-11-15 14:45:59 +01:00
int
il_alloc_traffic_mem ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
2011-10-24 15:41:30 +02:00
u32 traffic_size = IL_TRAFFIC_DUMP_SIZE ;
2011-02-21 11:27:26 -08:00
2011-08-16 14:17:04 +02:00
if ( il_debug_level & IL_DL_TX ) {
2011-10-24 16:49:25 +02:00
if ( ! il - > tx_traffic ) {
2011-11-15 14:45:59 +01:00
il - > tx_traffic = kzalloc ( traffic_size , GFP_KERNEL ) ;
2011-10-24 16:49:25 +02:00
if ( ! il - > tx_traffic )
2011-02-21 11:27:26 -08:00
return - ENOMEM ;
}
}
2011-08-16 14:17:04 +02:00
if ( il_debug_level & IL_DL_RX ) {
2011-10-24 16:49:25 +02:00
if ( ! il - > rx_traffic ) {
2011-11-15 14:45:59 +01:00
il - > rx_traffic = kzalloc ( traffic_size , GFP_KERNEL ) ;
2011-10-24 16:49:25 +02:00
if ( ! il - > rx_traffic )
2011-02-21 11:27:26 -08:00
return - ENOMEM ;
}
}
2011-10-24 16:49:25 +02:00
il_reset_traffic_log ( il ) ;
2011-02-21 11:27:26 -08:00
return 0 ;
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_alloc_traffic_mem ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
void
il_free_traffic_mem ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
kfree ( il - > tx_traffic ) ;
il - > tx_traffic = NULL ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
kfree ( il - > rx_traffic ) ;
il - > rx_traffic = NULL ;
2011-02-21 11:27:26 -08:00
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_free_traffic_mem ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
void
il_dbg_log_tx_data_frame ( struct il_priv * il , u16 length ,
struct ieee80211_hdr * header )
2011-02-21 11:27:26 -08:00
{
__le16 fc ;
u16 len ;
2011-08-16 14:17:04 +02:00
if ( likely ( ! ( il_debug_level & IL_DL_TX ) ) )
2011-02-21 11:27:26 -08:00
return ;
2011-10-24 16:49:25 +02:00
if ( ! il - > tx_traffic )
2011-02-21 11:27:26 -08:00
return ;
fc = header - > frame_control ;
if ( ieee80211_is_data ( fc ) ) {
2011-11-15 14:45:59 +01:00
len =
( length >
IL_TRAFFIC_ENTRY_SIZE ) ? IL_TRAFFIC_ENTRY_SIZE : length ;
2011-10-24 16:49:25 +02:00
memcpy ( ( il - > tx_traffic +
2011-11-15 14:45:59 +01:00
( il - > tx_traffic_idx * IL_TRAFFIC_ENTRY_SIZE ) ) , header ,
len ) ;
2011-10-24 16:49:25 +02:00
il - > tx_traffic_idx =
2011-11-15 14:45:59 +01:00
( il - > tx_traffic_idx + 1 ) % IL_TRAFFIC_ENTRIES ;
2011-02-21 11:27:26 -08:00
}
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_dbg_log_tx_data_frame ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
void
il_dbg_log_rx_data_frame ( struct il_priv * il , u16 length ,
struct ieee80211_hdr * header )
2011-02-21 11:27:26 -08:00
{
__le16 fc ;
u16 len ;
2011-08-16 14:17:04 +02:00
if ( likely ( ! ( il_debug_level & IL_DL_RX ) ) )
2011-02-21 11:27:26 -08:00
return ;
2011-10-24 16:49:25 +02:00
if ( ! il - > rx_traffic )
2011-02-21 11:27:26 -08:00
return ;
fc = header - > frame_control ;
if ( ieee80211_is_data ( fc ) ) {
2011-11-15 14:45:59 +01:00
len =
( length >
IL_TRAFFIC_ENTRY_SIZE ) ? IL_TRAFFIC_ENTRY_SIZE : length ;
2011-10-24 16:49:25 +02:00
memcpy ( ( il - > rx_traffic +
2011-11-15 14:45:59 +01:00
( il - > rx_traffic_idx * IL_TRAFFIC_ENTRY_SIZE ) ) , header ,
len ) ;
2011-10-24 16:49:25 +02:00
il - > rx_traffic_idx =
2011-11-15 14:45:59 +01:00
( il - > rx_traffic_idx + 1 ) % IL_TRAFFIC_ENTRIES ;
2011-02-21 11:27:26 -08:00
}
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_dbg_log_rx_data_frame ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
const char *
il_get_mgmt_string ( int cmd )
2011-02-21 11:27:26 -08:00
{
switch ( cmd ) {
2011-10-24 15:41:30 +02:00
IL_CMD ( MANAGEMENT_ASSOC_REQ ) ;
IL_CMD ( MANAGEMENT_ASSOC_RESP ) ;
IL_CMD ( MANAGEMENT_REASSOC_REQ ) ;
IL_CMD ( MANAGEMENT_REASSOC_RESP ) ;
IL_CMD ( MANAGEMENT_PROBE_REQ ) ;
IL_CMD ( MANAGEMENT_PROBE_RESP ) ;
IL_CMD ( MANAGEMENT_BEACON ) ;
IL_CMD ( MANAGEMENT_ATIM ) ;
IL_CMD ( MANAGEMENT_DISASSOC ) ;
IL_CMD ( MANAGEMENT_AUTH ) ;
IL_CMD ( MANAGEMENT_DEAUTH ) ;
IL_CMD ( MANAGEMENT_ACTION ) ;
2011-02-21 11:27:26 -08:00
default :
return " UNKNOWN " ;
}
}
2011-11-15 14:45:59 +01:00
const char *
il_get_ctrl_string ( int cmd )
2011-02-21 11:27:26 -08:00
{
switch ( cmd ) {
2011-10-24 15:41:30 +02:00
IL_CMD ( CONTROL_BACK_REQ ) ;
IL_CMD ( CONTROL_BACK ) ;
IL_CMD ( CONTROL_PSPOLL ) ;
IL_CMD ( CONTROL_RTS ) ;
IL_CMD ( CONTROL_CTS ) ;
IL_CMD ( CONTROL_ACK ) ;
IL_CMD ( CONTROL_CFEND ) ;
IL_CMD ( CONTROL_CFENDACK ) ;
2011-02-21 11:27:26 -08:00
default :
return " UNKNOWN " ;
}
}
2011-11-15 14:45:59 +01:00
void
il_clear_traffic_stats ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
memset ( & il - > tx_stats , 0 , sizeof ( struct traffic_stats ) ) ;
memset ( & il - > rx_stats , 0 , sizeof ( struct traffic_stats ) ) ;
2011-02-21 11:27:26 -08:00
}
/*
2011-11-15 11:25:42 +01:00
* if CONFIG_IWLEGACY_DEBUGFS defined ,
2011-10-24 15:41:30 +02:00
* il_update_stats function will
2011-02-21 11:27:26 -08:00
* record all the MGMT , CTRL and DATA pkt for both TX and Rx pass
2011-08-26 15:43:47 +02:00
* Use debugFs to display the rx / rx_stats
2011-11-15 11:25:42 +01:00
* if CONFIG_IWLEGACY_DEBUGFS not being defined , then no MGMT and CTRL
2011-02-21 11:27:26 -08:00
* information will be recorded , but DATA pkt still will be recorded
2011-10-24 15:41:30 +02:00
* for the reason of il_led . c need to control the led blinking based on
2011-02-21 11:27:26 -08:00
* number of tx and rx data .
*
*/
void
2011-10-24 16:49:25 +02:00
il_update_stats ( struct il_priv * il , bool is_tx , __le16 fc , u16 len )
2011-02-21 11:27:26 -08:00
{
2011-11-15 14:45:59 +01:00
struct traffic_stats * stats ;
2011-02-21 11:27:26 -08:00
if ( is_tx )
2011-10-24 16:49:25 +02:00
stats = & il - > tx_stats ;
2011-02-21 11:27:26 -08:00
else
2011-10-24 16:49:25 +02:00
stats = & il - > rx_stats ;
2011-02-21 11:27:26 -08:00
if ( ieee80211_is_mgmt ( fc ) ) {
switch ( fc & cpu_to_le16 ( IEEE80211_FCTL_STYPE ) ) {
case cpu_to_le16 ( IEEE80211_STYPE_ASSOC_REQ ) :
stats - > mgmt [ MANAGEMENT_ASSOC_REQ ] + + ;
break ;
case cpu_to_le16 ( IEEE80211_STYPE_ASSOC_RESP ) :
stats - > mgmt [ MANAGEMENT_ASSOC_RESP ] + + ;
break ;
case cpu_to_le16 ( IEEE80211_STYPE_REASSOC_REQ ) :
stats - > mgmt [ MANAGEMENT_REASSOC_REQ ] + + ;
break ;
case cpu_to_le16 ( IEEE80211_STYPE_REASSOC_RESP ) :
stats - > mgmt [ MANAGEMENT_REASSOC_RESP ] + + ;
break ;
case cpu_to_le16 ( IEEE80211_STYPE_PROBE_REQ ) :
stats - > mgmt [ MANAGEMENT_PROBE_REQ ] + + ;
break ;
case cpu_to_le16 ( IEEE80211_STYPE_PROBE_RESP ) :
stats - > mgmt [ MANAGEMENT_PROBE_RESP ] + + ;
break ;
case cpu_to_le16 ( IEEE80211_STYPE_BEACON ) :
stats - > mgmt [ MANAGEMENT_BEACON ] + + ;
break ;
case cpu_to_le16 ( IEEE80211_STYPE_ATIM ) :
stats - > mgmt [ MANAGEMENT_ATIM ] + + ;
break ;
case cpu_to_le16 ( IEEE80211_STYPE_DISASSOC ) :
stats - > mgmt [ MANAGEMENT_DISASSOC ] + + ;
break ;
case cpu_to_le16 ( IEEE80211_STYPE_AUTH ) :
stats - > mgmt [ MANAGEMENT_AUTH ] + + ;
break ;
case cpu_to_le16 ( IEEE80211_STYPE_DEAUTH ) :
stats - > mgmt [ MANAGEMENT_DEAUTH ] + + ;
break ;
case cpu_to_le16 ( IEEE80211_STYPE_ACTION ) :
stats - > mgmt [ MANAGEMENT_ACTION ] + + ;
break ;
}
} else if ( ieee80211_is_ctl ( fc ) ) {
switch ( fc & cpu_to_le16 ( IEEE80211_FCTL_STYPE ) ) {
case cpu_to_le16 ( IEEE80211_STYPE_BACK_REQ ) :
stats - > ctrl [ CONTROL_BACK_REQ ] + + ;
break ;
case cpu_to_le16 ( IEEE80211_STYPE_BACK ) :
stats - > ctrl [ CONTROL_BACK ] + + ;
break ;
case cpu_to_le16 ( IEEE80211_STYPE_PSPOLL ) :
stats - > ctrl [ CONTROL_PSPOLL ] + + ;
break ;
case cpu_to_le16 ( IEEE80211_STYPE_RTS ) :
stats - > ctrl [ CONTROL_RTS ] + + ;
break ;
case cpu_to_le16 ( IEEE80211_STYPE_CTS ) :
stats - > ctrl [ CONTROL_CTS ] + + ;
break ;
case cpu_to_le16 ( IEEE80211_STYPE_ACK ) :
stats - > ctrl [ CONTROL_ACK ] + + ;
break ;
case cpu_to_le16 ( IEEE80211_STYPE_CFEND ) :
stats - > ctrl [ CONTROL_CFEND ] + + ;
break ;
case cpu_to_le16 ( IEEE80211_STYPE_CFENDACK ) :
stats - > ctrl [ CONTROL_CFENDACK ] + + ;
break ;
}
} else {
/* data */
stats - > data_cnt + + ;
stats - > data_bytes + = len ;
}
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_update_stats ) ;
2011-02-21 11:27:26 -08:00
# endif
2011-11-15 14:45:59 +01:00
int
il_force_reset ( struct il_priv * il , bool external )
2011-02-21 11:27:26 -08:00
{
2011-10-24 15:41:30 +02:00
struct il_force_reset * force_reset ;
2011-02-21 11:27:26 -08:00
2011-11-15 13:09:01 +01:00
if ( test_bit ( S_EXIT_PENDING , & il - > status ) )
2011-02-21 11:27:26 -08:00
return - EINVAL ;
2011-10-24 16:49:25 +02:00
force_reset = & il - > force_reset ;
2011-02-21 11:27:26 -08:00
force_reset - > reset_request_count + + ;
if ( ! external ) {
if ( force_reset - > last_force_reset_jiffies & &
time_after ( force_reset - > last_force_reset_jiffies +
2011-11-15 14:45:59 +01:00
force_reset - > reset_duration , jiffies ) ) {
2011-11-15 11:21:01 +01:00
D_INFO ( " force reset rejected \n " ) ;
2011-02-21 11:27:26 -08:00
force_reset - > reset_reject_count + + ;
return - EAGAIN ;
}
}
force_reset - > reset_success_count + + ;
force_reset - > last_force_reset_jiffies = jiffies ;
2011-06-08 15:28:26 +02:00
/*
* if the request is from external ( ex : debugfs ) ,
* then always perform the request in regardless the module
* parameter setting
* if the request is from internal ( uCode error or driver
* detect failure ) , then fw_restart module parameter
* need to be check before performing firmware reload
*/
2011-10-24 16:49:25 +02:00
if ( ! external & & ! il - > cfg - > mod_params - > restart_fw ) {
2011-11-15 11:21:01 +01:00
D_INFO ( " Cancel firmware reload based on "
2011-11-15 14:45:59 +01:00
" module parameter setting \n " ) ;
2011-06-08 15:28:26 +02:00
return 0 ;
2011-02-21 11:27:26 -08:00
}
2011-06-08 15:28:26 +02:00
2011-08-18 22:07:57 +02:00
IL_ERR ( " On demand firmware reload \n " ) ;
2011-06-08 15:28:26 +02:00
2011-10-24 15:41:30 +02:00
/* Set the FW error flag -- cleared on il_down */
2011-11-15 13:09:01 +01:00
set_bit ( S_FW_ERROR , & il - > status ) ;
2011-10-24 16:49:25 +02:00
wake_up ( & il - > wait_command_queue ) ;
2011-06-08 15:28:26 +02:00
/*
* Keep the restart process from trying to send host
* commands by clearing the INIT status bit
*/
2011-11-15 13:09:01 +01:00
clear_bit ( S_READY , & il - > status ) ;
2011-10-24 16:49:25 +02:00
queue_work ( il - > workqueue , & il - > restart ) ;
2011-06-08 15:28:26 +02:00
2011-02-21 11:27:26 -08:00
return 0 ;
}
int
2011-11-15 14:45:59 +01:00
il_mac_change_interface ( struct ieee80211_hw * hw , struct ieee80211_vif * vif ,
2011-02-21 11:27:26 -08:00
enum nl80211_iftype newtype , bool newp2p )
{
2011-10-24 16:49:25 +02:00
struct il_priv * il = hw - > priv ;
2011-02-21 11:27:26 -08:00
int err ;
2012-02-03 17:31:50 +01:00
if ( newp2p )
return - EOPNOTSUPP ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
mutex_lock ( & il - > mutex ) ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:57 +01:00
if ( ! il - > vif | | ! il_is_ready_rf ( il ) ) {
2011-03-29 15:28:11 +02:00
/*
* Huh ? But wait . . . this can maybe happen when
* we ' re in the middle of a firmware restart !
*/
err = - EBUSY ;
goto out ;
}
2011-02-21 11:27:26 -08:00
/* success */
2011-10-24 16:49:25 +02:00
il_teardown_interface ( il , vif , true ) ;
2011-02-21 11:27:26 -08:00
vif - > type = newtype ;
2012-02-03 17:31:50 +01:00
vif - > p2p = false ;
2012-02-03 17:31:57 +01:00
err = il_set_mode ( il ) ;
2011-02-21 11:27:26 -08:00
WARN_ON ( err ) ;
/*
* We ' ve switched internally , but submitting to the
* device may have failed for some reason . Mask this
* error , because otherwise mac80211 will not switch
* ( and set the interface type back ) and we ' ll be
* out of sync with it .
*/
err = 0 ;
2011-11-15 14:45:59 +01:00
out :
2011-10-24 16:49:25 +02:00
mutex_unlock ( & il - > mutex ) ;
2011-02-21 11:27:26 -08:00
return err ;
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_mac_change_interface ) ;
2011-02-21 11:27:26 -08:00
/*
* On every watchdog tick we check ( latest ) time stamp . If it does not
* change during timeout period and queue is not empty we reset firmware .
*/
2011-11-15 14:45:59 +01:00
static int
il_check_stuck_queue ( struct il_priv * il , int cnt )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
struct il_tx_queue * txq = & il - > txq [ cnt ] ;
2011-10-24 15:41:30 +02:00
struct il_queue * q = & txq - > q ;
2011-02-21 11:27:26 -08:00
unsigned long timeout ;
int ret ;
if ( q - > read_ptr = = q - > write_ptr ) {
txq - > time_stamp = jiffies ;
return 0 ;
}
2011-11-15 14:45:59 +01:00
timeout =
txq - > time_stamp +
msecs_to_jiffies ( il - > cfg - > base_params - > wd_timeout ) ;
2011-02-21 11:27:26 -08:00
if ( time_after ( jiffies , timeout ) ) {
2011-11-15 14:45:59 +01:00
IL_ERR ( " Queue %d stuck for %u ms. \n " , q - > id ,
il - > cfg - > base_params - > wd_timeout ) ;
2011-10-24 16:49:25 +02:00
ret = il_force_reset ( il , false ) ;
2011-02-21 11:27:26 -08:00
return ( ret = = - EAGAIN ) ? 0 : 1 ;
}
return 0 ;
}
/*
* Making watchdog tick be a quarter of timeout assure we will
* discover the queue hung between timeout and 1.25 * timeout
*/
2011-10-24 15:41:30 +02:00
# define IL_WD_TICK(timeout) ((timeout) / 4)
2011-02-21 11:27:26 -08:00
/*
* Watchdog timer callback , we check each tx queue for stuck , if if hung
* we reset the firmware . If everything is fine just rearm the timer .
*/
2011-11-15 14:45:59 +01:00
void
il_bg_watchdog ( unsigned long data )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
struct il_priv * il = ( struct il_priv * ) data ;
2011-02-21 11:27:26 -08:00
int cnt ;
unsigned long timeout ;
2011-11-15 13:09:01 +01:00
if ( test_bit ( S_EXIT_PENDING , & il - > status ) )
2011-02-21 11:27:26 -08:00
return ;
2011-10-24 16:49:25 +02:00
timeout = il - > cfg - > base_params - > wd_timeout ;
2011-02-21 11:27:26 -08:00
if ( timeout = = 0 )
return ;
/* monitor and check for stuck cmd queue */
2011-10-24 16:49:25 +02:00
if ( il_check_stuck_queue ( il , il - > cmd_queue ) )
2011-02-21 11:27:26 -08:00
return ;
/* monitor and check for other stuck queues */
2011-10-24 16:49:25 +02:00
if ( il_is_any_associated ( il ) ) {
for ( cnt = 0 ; cnt < il - > hw_params . max_txq_num ; cnt + + ) {
2011-02-21 11:27:26 -08:00
/* skip as we already checked the command queue */
2011-10-24 16:49:25 +02:00
if ( cnt = = il - > cmd_queue )
2011-02-21 11:27:26 -08:00
continue ;
2011-10-24 16:49:25 +02:00
if ( il_check_stuck_queue ( il , cnt ) )
2011-02-21 11:27:26 -08:00
return ;
}
}
2011-11-15 14:45:59 +01:00
mod_timer ( & il - > watchdog ,
jiffies + msecs_to_jiffies ( IL_WD_TICK ( timeout ) ) ) ;
2011-02-21 11:27:26 -08:00
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_bg_watchdog ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
void
il_setup_watchdog ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
unsigned int timeout = il - > cfg - > base_params - > wd_timeout ;
2011-02-21 11:27:26 -08:00
if ( timeout )
2011-10-24 16:49:25 +02:00
mod_timer ( & il - > watchdog ,
2011-10-24 15:41:30 +02:00
jiffies + msecs_to_jiffies ( IL_WD_TICK ( timeout ) ) ) ;
2011-02-21 11:27:26 -08:00
else
2011-10-24 16:49:25 +02:00
del_timer ( & il - > watchdog ) ;
2011-02-21 11:27:26 -08:00
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_setup_watchdog ) ;
2011-02-21 11:27:26 -08:00
/*
* extended beacon time format
* time in usec will be changed into a 32 - bit value in extended : internal format
* the extended part is the beacon counts
* the internal part is the time in usec within one beacon interval
*/
u32
2011-11-15 14:45:59 +01:00
il_usecs_to_beacons ( struct il_priv * il , u32 usec , u32 beacon_interval )
2011-02-21 11:27:26 -08:00
{
u32 quot ;
u32 rem ;
u32 interval = beacon_interval * TIME_UNIT ;
if ( ! interval | | ! usec )
return 0 ;
2011-11-15 14:45:59 +01:00
quot =
( usec /
interval ) & ( il_beacon_time_mask_high ( il ,
il - > hw_params .
beacon_time_tsf_bits ) > > il - >
hw_params . beacon_time_tsf_bits ) ;
rem =
( usec % interval ) & il_beacon_time_mask_low ( il ,
il - > hw_params .
beacon_time_tsf_bits ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
return ( quot < < il - > hw_params . beacon_time_tsf_bits ) + rem ;
2011-02-21 11:27:26 -08:00
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_usecs_to_beacons ) ;
2011-02-21 11:27:26 -08:00
/* base is usually what we get from ucode with each received frame,
* the same as HW timer counter counting down
*/
2011-11-15 14:45:59 +01:00
__le32
2011-11-15 14:51:01 +01:00
il_add_beacon_time ( struct il_priv * il , u32 base , u32 addon ,
2011-11-15 14:45:59 +01:00
u32 beacon_interval )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
u32 base_low = base & il_beacon_time_mask_low ( il ,
2011-11-15 14:45:59 +01:00
il - > hw_params .
beacon_time_tsf_bits ) ;
2011-10-24 16:49:25 +02:00
u32 addon_low = addon & il_beacon_time_mask_low ( il ,
2011-11-15 14:45:59 +01:00
il - > hw_params .
beacon_time_tsf_bits ) ;
2011-02-21 11:27:26 -08:00
u32 interval = beacon_interval * TIME_UNIT ;
2011-10-24 16:49:25 +02:00
u32 res = ( base & il_beacon_time_mask_high ( il ,
2011-11-15 14:45:59 +01:00
il - > hw_params .
beacon_time_tsf_bits ) ) +
( addon & il_beacon_time_mask_high ( il ,
il - > hw_params .
beacon_time_tsf_bits ) ) ;
2011-02-21 11:27:26 -08:00
if ( base_low > addon_low )
res + = base_low - addon_low ;
else if ( base_low < addon_low ) {
res + = interval + base_low - addon_low ;
2011-10-24 16:49:25 +02:00
res + = ( 1 < < il - > hw_params . beacon_time_tsf_bits ) ;
2011-02-21 11:27:26 -08:00
} else
2011-10-24 16:49:25 +02:00
res + = ( 1 < < il - > hw_params . beacon_time_tsf_bits ) ;
2011-02-21 11:27:26 -08:00
return cpu_to_le32 ( res ) ;
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_add_beacon_time ) ;
2011-02-21 11:27:26 -08:00
# ifdef CONFIG_PM
2011-11-15 14:45:59 +01:00
int
il_pci_suspend ( struct device * device )
2011-02-21 11:27:26 -08:00
{
struct pci_dev * pdev = to_pci_dev ( device ) ;
2011-10-24 16:49:25 +02:00
struct il_priv * il = pci_get_drvdata ( pdev ) ;
2011-02-21 11:27:26 -08:00
/*
* This function is called when system goes into suspend state
2011-10-24 15:41:30 +02:00
* mac80211 will call il_mac_stop ( ) from the mac80211 suspend function
* first but since il_mac_stop ( ) has no knowledge of who the caller is ,
2011-02-21 11:27:26 -08:00
* it will not call apm_ops . stop ( ) to stop the DMA operation .
* Calling apm_ops . stop here to make sure we stop the DMA .
*/
2011-10-24 16:49:25 +02:00
il_apm_stop ( il ) ;
2011-02-21 11:27:26 -08:00
return 0 ;
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_pci_suspend ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
int
il_pci_resume ( struct device * device )
2011-02-21 11:27:26 -08:00
{
struct pci_dev * pdev = to_pci_dev ( device ) ;
2011-10-24 16:49:25 +02:00
struct il_priv * il = pci_get_drvdata ( pdev ) ;
2011-02-21 11:27:26 -08:00
bool hw_rfkill = false ;
/*
* We disable the RETRY_TIMEOUT register ( 0x41 ) to keep
* PCI Tx retries from interfering with C3 CPU state .
*/
pci_write_config_byte ( pdev , PCI_CFG_RETRY_TIMEOUT , 0x00 ) ;
2011-10-24 16:49:25 +02:00
il_enable_interrupts ( il ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
if ( ! ( _il_rd ( il , CSR_GP_CNTRL ) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW ) )
2011-02-21 11:27:26 -08:00
hw_rfkill = true ;
if ( hw_rfkill )
2011-11-15 13:09:01 +01:00
set_bit ( S_RF_KILL_HW , & il - > status ) ;
2011-02-21 11:27:26 -08:00
else
2011-11-15 13:09:01 +01:00
clear_bit ( S_RF_KILL_HW , & il - > status ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
wiphy_rfkill_set_hw_state ( il - > hw - > wiphy , hw_rfkill ) ;
2011-02-21 11:27:26 -08:00
return 0 ;
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_pci_resume ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 15:41:30 +02:00
const struct dev_pm_ops il_pm_ops = {
. suspend = il_pci_suspend ,
. resume = il_pci_resume ,
. freeze = il_pci_suspend ,
. thaw = il_pci_resume ,
. poweroff = il_pci_suspend ,
. restore = il_pci_resume ,
2011-02-21 11:27:26 -08:00
} ;
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_pm_ops ) ;
2011-02-21 11:27:26 -08:00
# endif /* CONFIG_PM */
static void
2012-02-03 17:31:57 +01:00
il_update_qos ( struct il_priv * il )
2011-02-21 11:27:26 -08:00
{
2011-11-15 13:09:01 +01:00
if ( test_bit ( S_EXIT_PENDING , & il - > status ) )
2011-02-21 11:27:26 -08:00
return ;
2012-02-03 17:31:51 +01:00
il - > qos_data . def_qos_parm . qos_flags = 0 ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:51 +01:00
if ( il - > qos_data . qos_active )
il - > qos_data . def_qos_parm . qos_flags | =
2011-11-15 14:45:59 +01:00
QOS_PARAM_FLG_UPDATE_EDCA_MSK ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:52 +01:00
if ( il - > ht . enabled )
2012-02-03 17:31:51 +01:00
il - > qos_data . def_qos_parm . qos_flags | = QOS_PARAM_FLG_TGN_MSK ;
2011-02-21 11:27:26 -08:00
2011-11-15 11:21:01 +01:00
D_QOS ( " send QoS cmd with Qos active=%d FLAGS=0x%X \n " ,
2012-02-03 17:31:51 +01:00
il - > qos_data . qos_active , il - > qos_data . def_qos_parm . qos_flags ) ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:41 +01:00
il_send_cmd_pdu_async ( il , C_QOS_PARAM , sizeof ( struct il_qosparam_cmd ) ,
2012-02-03 17:31:51 +01:00
& il - > qos_data . def_qos_parm , NULL ) ;
2011-02-21 11:27:26 -08:00
}
/**
2011-10-24 15:41:30 +02:00
* il_mac_config - mac80211 config callback
2011-02-21 11:27:26 -08:00
*/
2011-11-15 14:45:59 +01:00
int
il_mac_config ( struct ieee80211_hw * hw , u32 changed )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
struct il_priv * il = hw - > priv ;
2011-10-24 15:41:30 +02:00
const struct il_channel_info * ch_info ;
2011-02-21 11:27:26 -08:00
struct ieee80211_conf * conf = & hw - > conf ;
struct ieee80211_channel * channel = conf - > channel ;
2011-10-24 16:49:25 +02:00
struct il_ht_config * ht_conf = & il - > current_ht_config ;
2011-02-21 11:27:26 -08:00
unsigned long flags = 0 ;
int ret = 0 ;
u16 ch ;
int scan_active = 0 ;
2011-11-15 11:29:04 +01:00
bool ht_changed = false ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
if ( WARN_ON ( ! il - > cfg - > ops - > legacy ) )
2011-02-21 11:27:26 -08:00
return - EOPNOTSUPP ;
2011-10-24 16:49:25 +02:00
mutex_lock ( & il - > mutex ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
D_MAC80211 ( " enter to channel %d changed 0x%X \n " , channel - > hw_value ,
changed ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 13:09:01 +01:00
if ( unlikely ( test_bit ( S_SCANNING , & il - > status ) ) ) {
2011-02-21 11:27:26 -08:00
scan_active = 1 ;
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " scan active \n " ) ;
2011-02-21 11:27:26 -08:00
}
2011-11-15 14:45:59 +01:00
if ( changed &
( IEEE80211_CONF_CHANGE_SMPS | IEEE80211_CONF_CHANGE_CHANNEL ) ) {
2011-02-21 11:27:26 -08:00
/* mac80211 uses static for non-HT which is what we want */
2011-10-24 16:49:25 +02:00
il - > current_ht_config . smps = conf - > smps_mode ;
2011-02-21 11:27:26 -08:00
/*
* Recalculate chain counts .
*
* If monitor mode is enabled then mac80211 will
* set up the SM PS mode to OFF if an HT channel is
* configured .
*/
2011-10-24 16:49:25 +02:00
if ( il - > cfg - > ops - > hcmd - > set_rxon_chain )
2012-02-03 17:31:57 +01:00
il - > cfg - > ops - > hcmd - > set_rxon_chain ( il ) ;
2011-02-21 11:27:26 -08:00
}
/* during scanning mac80211 will delay channel setting until
* scan finish with changed = 0
*/
if ( ! changed | | ( changed & IEEE80211_CONF_CHANGE_CHANNEL ) ) {
2011-08-29 12:52:20 +02:00
2011-02-21 11:27:26 -08:00
if ( scan_active )
goto set_ch_out ;
ch = channel - > hw_value ;
2011-10-24 16:49:25 +02:00
ch_info = il_get_channel_info ( il , channel - > band , ch ) ;
2011-10-24 15:41:30 +02:00
if ( ! il_is_channel_valid ( ch_info ) ) {
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " leave - invalid channel \n " ) ;
2011-02-21 11:27:26 -08:00
ret = - EINVAL ;
goto set_ch_out ;
}
2011-10-24 16:49:25 +02:00
if ( il - > iw_mode = = NL80211_IFTYPE_ADHOC & &
2011-10-24 15:41:30 +02:00
! il_is_channel_ibss ( ch_info ) ) {
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " leave - not IBSS channel \n " ) ;
2011-05-07 17:46:21 +02:00
ret = - EINVAL ;
goto set_ch_out ;
}
2011-10-24 16:49:25 +02:00
spin_lock_irqsave ( & il - > lock , flags ) ;
2011-02-21 11:27:26 -08:00
2011-08-29 12:52:20 +02:00
/* Configure HT40 channels */
2012-02-03 17:31:52 +01:00
if ( il - > ht . enabled ! = conf_is_ht ( conf ) ) {
il - > ht . enabled = conf_is_ht ( conf ) ;
2011-08-29 12:52:20 +02:00
ht_changed = true ;
}
2012-02-03 17:31:52 +01:00
if ( il - > ht . enabled ) {
2011-08-29 12:52:20 +02:00
if ( conf_is_ht40_minus ( conf ) ) {
2012-02-03 17:31:52 +01:00
il - > ht . extension_chan_offset =
2011-11-15 14:45:59 +01:00
IEEE80211_HT_PARAM_CHA_SEC_BELOW ;
2012-02-03 17:31:52 +01:00
il - > ht . is_40mhz = true ;
2011-08-29 12:52:20 +02:00
} else if ( conf_is_ht40_plus ( conf ) ) {
2012-02-03 17:31:52 +01:00
il - > ht . extension_chan_offset =
2011-11-15 14:45:59 +01:00
IEEE80211_HT_PARAM_CHA_SEC_ABOVE ;
2012-02-03 17:31:52 +01:00
il - > ht . is_40mhz = true ;
2011-08-29 12:52:20 +02:00
} else {
2012-02-03 17:31:52 +01:00
il - > ht . extension_chan_offset =
2011-11-15 14:45:59 +01:00
IEEE80211_HT_PARAM_CHA_SEC_NONE ;
2012-02-03 17:31:52 +01:00
il - > ht . is_40mhz = false ;
2011-08-29 12:52:20 +02:00
}
} else
2012-02-03 17:31:52 +01:00
il - > ht . is_40mhz = false ;
2011-02-21 11:27:26 -08:00
2011-08-29 12:52:20 +02:00
/*
* Default to no protection . Protection mode will
* later be set from BSS config in il_ht_conf
*/
2012-02-03 17:31:52 +01:00
il - > ht . protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE ;
2011-02-21 11:27:26 -08:00
2011-08-29 12:52:20 +02:00
/* if we are switching from ht to 2.4 clear flags
* from any ht related info since 2.4 does not
* support ht */
2012-02-03 17:31:37 +01:00
if ( ( le16_to_cpu ( il - > staging . channel ) ! = ch ) )
il - > staging . flags = 0 ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:57 +01:00
il_set_rxon_channel ( il , channel ) ;
2011-08-29 12:52:20 +02:00
il_set_rxon_ht ( il , ht_conf ) ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:57 +01:00
il_set_flags_for_band ( il , channel - > band , il - > vif ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
spin_unlock_irqrestore ( & il - > lock , flags ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
if ( il - > cfg - > ops - > legacy - > update_bcast_stations )
2011-11-15 14:45:59 +01:00
ret = il - > cfg - > ops - > legacy - > update_bcast_stations ( il ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
set_ch_out :
2011-02-21 11:27:26 -08:00
/* The list of supported rates and rate mask can be different
* for each band ; since the band may have changed , reset
* the rate mask to what mac80211 lists */
2011-10-24 16:49:25 +02:00
il_set_rate ( il ) ;
2011-02-21 11:27:26 -08:00
}
2011-11-15 14:45:59 +01:00
if ( changed & ( IEEE80211_CONF_CHANGE_PS | IEEE80211_CONF_CHANGE_IDLE ) ) {
2011-10-24 16:49:25 +02:00
ret = il_power_update_mode ( il , false ) ;
2011-02-21 11:27:26 -08:00
if ( ret )
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " Error setting sleep level \n " ) ;
2011-02-21 11:27:26 -08:00
}
if ( changed & IEEE80211_CONF_CHANGE_POWER ) {
2011-11-15 14:45:59 +01:00
D_MAC80211 ( " TX Power old=%d new=%d \n " , il - > tx_power_user_lmt ,
conf - > power_level ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
il_set_tx_power ( il , conf - > power_level , false ) ;
2011-02-21 11:27:26 -08:00
}
2011-10-24 16:49:25 +02:00
if ( ! il_is_ready ( il ) ) {
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " leave - not ready \n " ) ;
2011-02-21 11:27:26 -08:00
goto out ;
}
if ( scan_active )
goto out ;
2012-02-03 17:31:37 +01:00
if ( memcmp ( & il - > active , & il - > staging , sizeof ( il - > staging ) ) )
2012-02-03 17:31:57 +01:00
il_commit_rxon ( il ) ;
2011-08-29 12:52:20 +02:00
else
D_INFO ( " Not re-sending same RXON configuration. \n " ) ;
if ( ht_changed )
2012-02-03 17:31:57 +01:00
il_update_qos ( il ) ;
2011-02-21 11:27:26 -08:00
out :
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " leave \n " ) ;
2011-10-24 16:49:25 +02:00
mutex_unlock ( & il - > mutex ) ;
2011-02-21 11:27:26 -08:00
return ret ;
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_mac_config ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
void
il_mac_reset_tsf ( struct ieee80211_hw * hw , struct ieee80211_vif * vif )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
struct il_priv * il = hw - > priv ;
2011-02-21 11:27:26 -08:00
unsigned long flags ;
2011-10-24 16:49:25 +02:00
if ( WARN_ON ( ! il - > cfg - > ops - > legacy ) )
2011-02-21 11:27:26 -08:00
return ;
2011-10-24 16:49:25 +02:00
mutex_lock ( & il - > mutex ) ;
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " enter \n " ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
spin_lock_irqsave ( & il - > lock , flags ) ;
memset ( & il - > current_ht_config , 0 , sizeof ( struct il_ht_config ) ) ;
spin_unlock_irqrestore ( & il - > lock , flags ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
spin_lock_irqsave ( & il - > lock , flags ) ;
2011-02-21 11:27:26 -08:00
/* new association get rid of ibss beacon skb */
2011-10-24 16:49:25 +02:00
if ( il - > beacon_skb )
dev_kfree_skb ( il - > beacon_skb ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
il - > beacon_skb = NULL ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
il - > timestamp = 0 ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
spin_unlock_irqrestore ( & il - > lock , flags ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
il_scan_cancel_timeout ( il , 100 ) ;
if ( ! il_is_ready_rf ( il ) ) {
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " leave - not ready \n " ) ;
2011-10-24 16:49:25 +02:00
mutex_unlock ( & il - > mutex ) ;
2011-02-21 11:27:26 -08:00
return ;
}
/* we are restarting association process
* clear RXON_FILTER_ASSOC_MSK bit
*/
2012-02-03 17:31:37 +01:00
il - > staging . filter_flags & = ~ RXON_FILTER_ASSOC_MSK ;
2012-02-03 17:31:57 +01:00
il_commit_rxon ( il ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
il_set_rate ( il ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
mutex_unlock ( & il - > mutex ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " leave \n " ) ;
2011-02-21 11:27:26 -08:00
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_mac_reset_tsf ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
static void
il_ht_conf ( struct il_priv * il , struct ieee80211_vif * vif )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
struct il_ht_config * ht_conf = & il - > current_ht_config ;
2011-02-21 11:27:26 -08:00
struct ieee80211_sta * sta ;
struct ieee80211_bss_conf * bss_conf = & vif - > bss_conf ;
2011-11-15 11:21:01 +01:00
D_ASSOC ( " enter: \n " ) ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:52 +01:00
if ( ! il - > ht . enabled )
2011-02-21 11:27:26 -08:00
return ;
2012-02-03 17:31:52 +01:00
il - > ht . protection =
2011-11-15 14:45:59 +01:00
bss_conf - > ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION ;
2012-02-03 17:31:52 +01:00
il - > ht . non_gf_sta_present =
2011-11-15 14:45:59 +01:00
! ! ( bss_conf - >
ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT ) ;
2011-02-21 11:27:26 -08:00
ht_conf - > single_chain_sufficient = false ;
switch ( vif - > type ) {
case NL80211_IFTYPE_STATION :
rcu_read_lock ( ) ;
sta = ieee80211_find_sta ( vif , bss_conf - > bssid ) ;
if ( sta ) {
struct ieee80211_sta_ht_cap * ht_cap = & sta - > ht_cap ;
int maxstreams ;
2011-11-15 14:45:59 +01:00
maxstreams =
( ht_cap - > mcs .
tx_params & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK )
> > IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT ;
2011-02-21 11:27:26 -08:00
maxstreams + = 1 ;
2011-08-26 10:45:16 +02:00
if ( ht_cap - > mcs . rx_mask [ 1 ] = = 0 & &
ht_cap - > mcs . rx_mask [ 2 ] = = 0 )
2011-02-21 11:27:26 -08:00
ht_conf - > single_chain_sufficient = true ;
if ( maxstreams < = 1 )
ht_conf - > single_chain_sufficient = true ;
} else {
/*
* If at all , this can only happen through a race
* when the AP disconnects us while we ' re still
* setting up the connection , in that case mac80211
* will soon tell us about that .
*/
ht_conf - > single_chain_sufficient = true ;
}
rcu_read_unlock ( ) ;
break ;
case NL80211_IFTYPE_ADHOC :
ht_conf - > single_chain_sufficient = true ;
break ;
default :
break ;
}
2011-11-15 11:21:01 +01:00
D_ASSOC ( " leave \n " ) ;
2011-02-21 11:27:26 -08:00
}
2011-11-15 14:45:59 +01:00
static inline void
il_set_no_assoc ( struct il_priv * il , struct ieee80211_vif * vif )
2011-02-21 11:27:26 -08:00
{
/*
* inform the ucode that there is no longer an
* association and that no more packets should be
* sent
*/
2012-02-03 17:31:37 +01:00
il - > staging . filter_flags & = ~ RXON_FILTER_ASSOC_MSK ;
il - > staging . assoc_id = 0 ;
2012-02-03 17:31:57 +01:00
il_commit_rxon ( il ) ;
2011-02-21 11:27:26 -08:00
}
2011-11-15 14:45:59 +01:00
static void
il_beacon_update ( struct ieee80211_hw * hw , struct ieee80211_vif * vif )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
struct il_priv * il = hw - > priv ;
2011-02-21 11:27:26 -08:00
unsigned long flags ;
__le64 timestamp ;
struct sk_buff * skb = ieee80211_beacon_get ( hw , vif ) ;
if ( ! skb )
return ;
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " enter \n " ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
lockdep_assert_held ( & il - > mutex ) ;
2011-02-21 11:27:26 -08:00
2012-02-03 17:31:57 +01:00
if ( ! il - > beacon_enabled ) {
IL_ERR ( " update beacon with no beaconing enabled \n " ) ;
2011-02-21 11:27:26 -08:00
dev_kfree_skb ( skb ) ;
return ;
}
2011-10-24 16:49:25 +02:00
spin_lock_irqsave ( & il - > lock , flags ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
if ( il - > beacon_skb )
dev_kfree_skb ( il - > beacon_skb ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
il - > beacon_skb = skb ;
2011-02-21 11:27:26 -08:00
timestamp = ( ( struct ieee80211_mgmt * ) skb - > data ) - > u . beacon . timestamp ;
2011-10-24 16:49:25 +02:00
il - > timestamp = le64_to_cpu ( timestamp ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " leave \n " ) ;
2011-10-24 16:49:25 +02:00
spin_unlock_irqrestore ( & il - > lock , flags ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
if ( ! il_is_ready_rf ( il ) ) {
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " leave - RF not ready \n " ) ;
2011-02-21 11:27:26 -08:00
return ;
}
2011-10-24 16:49:25 +02:00
il - > cfg - > ops - > legacy - > post_associate ( il ) ;
2011-02-21 11:27:26 -08:00
}
2011-11-15 14:45:59 +01:00
void
il_mac_bss_info_changed ( struct ieee80211_hw * hw , struct ieee80211_vif * vif ,
struct ieee80211_bss_conf * bss_conf , u32 changes )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
struct il_priv * il = hw - > priv ;
2011-02-21 11:27:26 -08:00
int ret ;
2011-10-24 16:49:25 +02:00
if ( WARN_ON ( ! il - > cfg - > ops - > legacy ) )
2011-02-21 11:27:26 -08:00
return ;
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " changes = 0x%X \n " , changes ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
mutex_lock ( & il - > mutex ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
if ( ! il_is_alive ( il ) ) {
mutex_unlock ( & il - > mutex ) ;
2011-04-28 11:51:32 +02:00
return ;
}
2011-02-21 11:27:26 -08:00
if ( changes & BSS_CHANGED_QOS ) {
unsigned long flags ;
2011-10-24 16:49:25 +02:00
spin_lock_irqsave ( & il - > lock , flags ) ;
2012-02-03 17:31:51 +01:00
il - > qos_data . qos_active = bss_conf - > qos ;
2012-02-03 17:31:57 +01:00
il_update_qos ( il ) ;
2011-10-24 16:49:25 +02:00
spin_unlock_irqrestore ( & il - > lock , flags ) ;
2011-02-21 11:27:26 -08:00
}
if ( changes & BSS_CHANGED_BEACON_ENABLED ) {
2012-02-03 17:31:57 +01:00
/* FIXME: can we remove beacon_enabled ? */
2011-02-21 11:27:26 -08:00
if ( vif - > bss_conf . enable_beacon )
2012-02-03 17:31:57 +01:00
il - > beacon_enabled = true ;
2011-02-21 11:27:26 -08:00
else
2012-02-03 17:31:57 +01:00
il - > beacon_enabled = false ;
2011-02-21 11:27:26 -08:00
}
if ( changes & BSS_CHANGED_BSSID ) {
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " BSSID %pM \n " , bss_conf - > bssid ) ;
2011-02-21 11:27:26 -08:00
/*
* If there is currently a HW scan going on in the
* background then we need to cancel it else the RXON
* below / in post_associate will fail .
*/
2011-10-24 16:49:25 +02:00
if ( il_scan_cancel_timeout ( il , 100 ) ) {
2011-11-15 14:45:59 +01:00
IL_WARN ( " Aborted scan still in progress after 100ms \n " ) ;
D_MAC80211 ( " leaving - scan abort failed. \n " ) ;
2011-10-24 16:49:25 +02:00
mutex_unlock ( & il - > mutex ) ;
2011-02-21 11:27:26 -08:00
return ;
}
/* mac80211 only sets assoc when in STATION mode */
if ( vif - > type = = NL80211_IFTYPE_ADHOC | | bss_conf - > assoc ) {
2012-02-03 17:31:37 +01:00
memcpy ( il - > staging . bssid_addr , bss_conf - > bssid ,
2011-11-15 14:45:59 +01:00
ETH_ALEN ) ;
2011-02-21 11:27:26 -08:00
/* currently needed in a few places */
2011-10-24 16:49:25 +02:00
memcpy ( il - > bssid , bss_conf - > bssid , ETH_ALEN ) ;
2011-02-21 11:27:26 -08:00
} else {
2012-02-03 17:31:37 +01:00
il - > staging . filter_flags & = ~ RXON_FILTER_ASSOC_MSK ;
2011-02-21 11:27:26 -08:00
}
}
/*
* This needs to be after setting the BSSID in case
* mac80211 decides to do both changes at once because
* it will invoke post_associate .
*/
2011-08-26 10:45:16 +02:00
if ( vif - > type = = NL80211_IFTYPE_ADHOC & & ( changes & BSS_CHANGED_BEACON ) )
2011-10-24 15:41:30 +02:00
il_beacon_update ( hw , vif ) ;
2011-02-21 11:27:26 -08:00
if ( changes & BSS_CHANGED_ERP_PREAMBLE ) {
2011-11-15 14:45:59 +01:00
D_MAC80211 ( " ERP_PREAMBLE %d \n " , bss_conf - > use_short_preamble ) ;
2011-02-21 11:27:26 -08:00
if ( bss_conf - > use_short_preamble )
2012-02-03 17:31:37 +01:00
il - > staging . flags | = RXON_FLG_SHORT_PREAMBLE_MSK ;
2011-02-21 11:27:26 -08:00
else
2012-02-03 17:31:37 +01:00
il - > staging . flags & = ~ RXON_FLG_SHORT_PREAMBLE_MSK ;
2011-02-21 11:27:26 -08:00
}
if ( changes & BSS_CHANGED_ERP_CTS_PROT ) {
2011-11-15 14:45:59 +01:00
D_MAC80211 ( " ERP_CTS %d \n " , bss_conf - > use_cts_prot ) ;
2011-08-26 10:45:16 +02:00
if ( bss_conf - > use_cts_prot & & il - > band ! = IEEE80211_BAND_5GHZ )
2012-02-03 17:31:37 +01:00
il - > staging . flags | = RXON_FLG_TGG_PROTECT_MSK ;
2011-02-21 11:27:26 -08:00
else
2012-02-03 17:31:37 +01:00
il - > staging . flags & = ~ RXON_FLG_TGG_PROTECT_MSK ;
2011-02-21 11:27:26 -08:00
if ( bss_conf - > use_cts_prot )
2012-02-03 17:31:37 +01:00
il - > staging . flags | = RXON_FLG_SELF_CTS_EN ;
2011-02-21 11:27:26 -08:00
else
2012-02-03 17:31:37 +01:00
il - > staging . flags & = ~ RXON_FLG_SELF_CTS_EN ;
2011-02-21 11:27:26 -08:00
}
if ( changes & BSS_CHANGED_BASIC_RATES ) {
/* XXX use this information
*
2011-10-24 15:41:30 +02:00
* To do that , remove code from il_set_rate ( ) and put something
2011-02-21 11:27:26 -08:00
* like this here :
*
2011-11-15 14:45:59 +01:00
if ( A - band )
2012-02-03 17:31:37 +01:00
il - > staging . ofdm_basic_rates =
2011-11-15 14:45:59 +01:00
bss_conf - > basic_rates ;
else
2012-02-03 17:31:37 +01:00
il - > staging . ofdm_basic_rates =
2011-11-15 14:45:59 +01:00
bss_conf - > basic_rates > > 4 ;
2012-02-03 17:31:37 +01:00
il - > staging . cck_basic_rates =
2011-11-15 14:45:59 +01:00
bss_conf - > basic_rates & 0xF ;
2011-02-21 11:27:26 -08:00
*/
}
if ( changes & BSS_CHANGED_HT ) {
2011-10-24 16:49:25 +02:00
il_ht_conf ( il , vif ) ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
if ( il - > cfg - > ops - > hcmd - > set_rxon_chain )
2012-02-03 17:31:57 +01:00
il - > cfg - > ops - > hcmd - > set_rxon_chain ( il ) ;
2011-02-21 11:27:26 -08:00
}
if ( changes & BSS_CHANGED_ASSOC ) {
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " ASSOC %d \n " , bss_conf - > assoc ) ;
2011-02-21 11:27:26 -08:00
if ( bss_conf - > assoc ) {
2011-10-24 16:49:25 +02:00
il - > timestamp = bss_conf - > timestamp ;
2011-02-21 11:27:26 -08:00
2011-10-24 16:49:25 +02:00
if ( ! il_is_rfkill ( il ) )
il - > cfg - > ops - > legacy - > post_associate ( il ) ;
2011-02-21 11:27:26 -08:00
} else
2011-10-24 16:49:25 +02:00
il_set_no_assoc ( il , vif ) ;
2011-02-21 11:27:26 -08:00
}
2012-02-03 17:31:37 +01:00
if ( changes & & il_is_associated ( il ) & & bss_conf - > aid ) {
2011-11-15 14:45:59 +01:00
D_MAC80211 ( " Changes (%#x) while associated \n " , changes ) ;
2012-02-03 17:31:57 +01:00
ret = il_send_rxon_assoc ( il ) ;
2011-02-21 11:27:26 -08:00
if ( ! ret ) {
/* Sync active_rxon with latest change. */
2012-02-03 17:31:37 +01:00
memcpy ( ( void * ) & il - > active , & il - > staging ,
2011-11-15 14:45:59 +01:00
sizeof ( struct il_rxon_cmd ) ) ;
2011-02-21 11:27:26 -08:00
}
}
if ( changes & BSS_CHANGED_BEACON_ENABLED ) {
if ( vif - > bss_conf . enable_beacon ) {
2012-02-03 17:31:37 +01:00
memcpy ( il - > staging . bssid_addr , bss_conf - > bssid ,
2011-11-15 14:45:59 +01:00
ETH_ALEN ) ;
2011-10-24 16:49:25 +02:00
memcpy ( il - > bssid , bss_conf - > bssid , ETH_ALEN ) ;
il - > cfg - > ops - > legacy - > config_ap ( il ) ;
2011-02-21 11:27:26 -08:00
} else
2011-10-24 16:49:25 +02:00
il_set_no_assoc ( il , vif ) ;
2011-02-21 11:27:26 -08:00
}
if ( changes & BSS_CHANGED_IBSS ) {
2011-11-15 14:45:59 +01:00
ret =
il - > cfg - > ops - > legacy - > manage_ibss_station ( il , vif ,
bss_conf - >
ibss_joined ) ;
2011-02-21 11:27:26 -08:00
if ( ret )
2011-08-18 22:07:57 +02:00
IL_ERR ( " failed to %s IBSS station %pM \n " ,
2011-11-15 14:45:59 +01:00
bss_conf - > ibss_joined ? " add " : " remove " ,
bss_conf - > bssid ) ;
2011-02-21 11:27:26 -08:00
}
2011-10-24 16:49:25 +02:00
mutex_unlock ( & il - > mutex ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 11:21:01 +01:00
D_MAC80211 ( " leave \n " ) ;
2011-02-21 11:27:26 -08:00
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_mac_bss_info_changed ) ;
2011-02-21 11:27:26 -08:00
2011-11-15 14:45:59 +01:00
irqreturn_t
il_isr ( int irq , void * data )
2011-02-21 11:27:26 -08:00
{
2011-10-24 16:49:25 +02:00
struct il_priv * il = data ;
2011-02-21 11:27:26 -08:00
u32 inta , inta_mask ;
u32 inta_fh ;
unsigned long flags ;
2011-10-24 16:49:25 +02:00
if ( ! il )
2011-02-21 11:27:26 -08:00
return IRQ_NONE ;
2011-10-24 16:49:25 +02:00
spin_lock_irqsave ( & il - > lock , flags ) ;
2011-02-21 11:27:26 -08:00
/* Disable (but don't clear!) interrupts here to avoid
* back - to - back ISRs and sporadic interrupts from our NIC .
* If we have something to service , the tasklet will re - enable ints .
* If we * don ' t * have something , we ' ll re - enable before leaving here . */
2011-11-15 14:45:59 +01:00
inta_mask = _il_rd ( il , CSR_INT_MASK ) ; /* just for debug */
2011-08-24 15:14:03 +02:00
_il_wr ( il , CSR_INT_MASK , 0x00000000 ) ;
2011-02-21 11:27:26 -08:00
/* Discover which interrupts are active/pending */
2011-08-24 15:14:03 +02:00
inta = _il_rd ( il , CSR_INT ) ;
inta_fh = _il_rd ( il , CSR_FH_INT_STATUS ) ;
2011-02-21 11:27:26 -08:00
/* Ignore interrupt if there's nothing in NIC to service.
* This may be due to IRQ shared with another device ,
* or due to sporadic interrupts thrown from our NIC . */
if ( ! inta & & ! inta_fh ) {
2011-11-15 14:45:59 +01:00
D_ISR ( " Ignore interrupt, inta == 0, inta_fh == 0 \n " ) ;
2011-02-21 11:27:26 -08:00
goto none ;
}
2011-08-26 10:45:16 +02:00
if ( inta = = 0xFFFFFFFF | | ( inta & 0xFFFFFFF0 ) = = 0xa5a5a5a0 ) {
2011-02-21 11:27:26 -08:00
/* Hardware disappeared. It might have already raised
* an interrupt */
2011-08-18 22:07:57 +02:00
IL_WARN ( " HARDWARE GONE?? INTA == 0x%08x \n " , inta ) ;
2011-02-21 11:27:26 -08:00
goto unplugged ;
}
2011-11-15 14:45:59 +01:00
D_ISR ( " ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x \n " , inta , inta_mask ,
inta_fh ) ;
2011-02-21 11:27:26 -08:00
inta & = ~ CSR_INT_BIT_SCD ;
2011-10-24 15:41:30 +02:00
/* il_irq_tasklet() will service interrupts and re-enable them */
2011-02-21 11:27:26 -08:00
if ( likely ( inta | | inta_fh ) )
2011-10-24 16:49:25 +02:00
tasklet_schedule ( & il - > irq_tasklet ) ;
2011-02-21 11:27:26 -08:00
unplugged :
2011-10-24 16:49:25 +02:00
spin_unlock_irqrestore ( & il - > lock , flags ) ;
2011-02-21 11:27:26 -08:00
return IRQ_HANDLED ;
none :
/* re-enable interrupts here since we don't have anything to service. */
2011-04-28 11:51:30 +02:00
/* only Re-enable if disabled by irq */
2011-11-15 13:09:01 +01:00
if ( test_bit ( S_INT_ENABLED , & il - > status ) )
2011-10-24 16:49:25 +02:00
il_enable_interrupts ( il ) ;
spin_unlock_irqrestore ( & il - > lock , flags ) ;
2011-02-21 11:27:26 -08:00
return IRQ_NONE ;
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_isr ) ;
2011-02-21 11:27:26 -08:00
/*
2011-10-24 15:41:30 +02:00
* il_tx_cmd_protection : Set rts / cts . 3945 and 4965 only share this
2011-02-21 11:27:26 -08:00
* function .
*/
2011-11-15 14:45:59 +01:00
void
il_tx_cmd_protection ( struct il_priv * il , struct ieee80211_tx_info * info ,
2011-11-15 14:51:01 +01:00
__le16 fc , __le32 * tx_flags )
2011-02-21 11:27:26 -08:00
{
if ( info - > control . rates [ 0 ] . flags & IEEE80211_TX_RC_USE_RTS_CTS ) {
* tx_flags | = TX_CMD_FLG_RTS_MSK ;
* tx_flags & = ~ TX_CMD_FLG_CTS_MSK ;
* tx_flags | = TX_CMD_FLG_FULL_TXOP_PROT_MSK ;
if ( ! ieee80211_is_mgmt ( fc ) )
return ;
switch ( fc & cpu_to_le16 ( IEEE80211_FCTL_STYPE ) ) {
case cpu_to_le16 ( IEEE80211_STYPE_AUTH ) :
case cpu_to_le16 ( IEEE80211_STYPE_DEAUTH ) :
case cpu_to_le16 ( IEEE80211_STYPE_ASSOC_REQ ) :
case cpu_to_le16 ( IEEE80211_STYPE_REASSOC_REQ ) :
* tx_flags & = ~ TX_CMD_FLG_RTS_MSK ;
* tx_flags | = TX_CMD_FLG_CTS_MSK ;
break ;
}
2011-11-15 14:45:59 +01:00
} else if ( info - > control . rates [ 0 ] .
flags & IEEE80211_TX_RC_USE_CTS_PROTECT ) {
2011-02-21 11:27:26 -08:00
* tx_flags & = ~ TX_CMD_FLG_RTS_MSK ;
* tx_flags | = TX_CMD_FLG_CTS_MSK ;
* tx_flags | = TX_CMD_FLG_FULL_TXOP_PROT_MSK ;
}
}
2011-10-24 15:41:30 +02:00
EXPORT_SYMBOL ( il_tx_cmd_protection ) ;