2011-02-21 11:11:05 -08:00
/******************************************************************************
*
2011-02-21 11:27:26 -08:00
* Copyright ( c ) 2003 - 2011 Intel Corporation . All rights reserved .
2011-02-21 11:11:05 -08:00
*
* 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 .
*
* 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/init.h>
# include <linux/pci.h>
# include <linux/dma-mapping.h>
# include <linux/delay.h>
# include <linux/sched.h>
# include <linux/skbuff.h>
# include <linux/netdevice.h>
# include <net/mac80211.h>
# include <linux/etherdevice.h>
# include <asm/unaligned.h>
2011-11-15 14:19:34 +01:00
# include "common.h"
2011-08-30 13:58:27 +02:00
# include "4965.h"
2011-02-21 11:11:05 -08:00
2011-08-30 12:50:25 +02:00
/**
* il_verify_inst_sparse - verify runtime uCode image in card vs . host ,
* using sample data 100 bytes apart . If these sample points are good ,
* it ' s a pretty good bet that everything between them is good , too .
*/
static int
2011-11-15 14:45:59 +01:00
il4965_verify_inst_sparse ( struct il_priv * il , __le32 * image , u32 len )
2011-08-30 12:50:25 +02:00
{
u32 val ;
int ret = 0 ;
u32 errcnt = 0 ;
u32 i ;
D_INFO ( " ucode inst image size is %u \n " , len ) ;
2011-11-15 14:45:59 +01:00
for ( i = 0 ; i < len ; i + = 100 , image + = 100 / sizeof ( u32 ) ) {
2011-08-30 12:50:25 +02:00
/* read data comes through single port, auto-incr addr */
/* NOTE: Use the debugless read so we don't flood kernel log
* if IL_DL_IO is set */
2011-11-15 14:45:59 +01:00
il_wr ( il , HBUS_TARG_MEM_RADDR , i + IL4965_RTC_INST_LOWER_BOUND ) ;
2011-08-30 12:50:25 +02:00
val = _il_rd ( il , HBUS_TARG_MEM_RDAT ) ;
if ( val ! = le32_to_cpu ( * image ) ) {
ret = - EIO ;
errcnt + + ;
if ( errcnt > = 3 )
break ;
}
}
return ret ;
}
/**
* il4965_verify_inst_full - verify runtime uCode image in card vs . host ,
* looking at all data .
*/
2011-11-15 14:45:59 +01:00
static int
il4965_verify_inst_full ( struct il_priv * il , __le32 * image , u32 len )
2011-08-30 12:50:25 +02:00
{
u32 val ;
u32 save_len = len ;
int ret = 0 ;
u32 errcnt ;
D_INFO ( " ucode inst image size is %u \n " , len ) ;
2011-11-15 14:45:59 +01:00
il_wr ( il , HBUS_TARG_MEM_RADDR , IL4965_RTC_INST_LOWER_BOUND ) ;
2011-08-30 12:50:25 +02:00
errcnt = 0 ;
for ( ; len > 0 ; len - = sizeof ( u32 ) , image + + ) {
/* read data comes through single port, auto-incr addr */
/* NOTE: Use the debugless read so we don't flood kernel log
* if IL_DL_IO is set */
val = _il_rd ( il , HBUS_TARG_MEM_RDAT ) ;
if ( val ! = le32_to_cpu ( * image ) ) {
IL_ERR ( " uCode INST section is invalid at "
2011-11-15 14:45:59 +01:00
" offset 0x%x, is 0x%x, s/b 0x%x \n " ,
save_len - len , val , le32_to_cpu ( * image ) ) ;
2011-08-30 12:50:25 +02:00
ret = - EIO ;
errcnt + + ;
if ( errcnt > = 20 )
break ;
}
}
if ( ! errcnt )
2011-11-15 14:45:59 +01:00
D_INFO ( " ucode image in INSTRUCTION memory is good \n " ) ;
2011-08-30 12:50:25 +02:00
return ret ;
}
/**
* il4965_verify_ucode - determine which instruction image is in SRAM ,
* and verify its contents
*/
2011-11-15 14:45:59 +01:00
int
il4965_verify_ucode ( struct il_priv * il )
2011-08-30 12:50:25 +02:00
{
__le32 * image ;
u32 len ;
int ret ;
/* Try bootstrap */
2011-11-15 14:45:59 +01:00
image = ( __le32 * ) il - > ucode_boot . v_addr ;
2011-08-30 12:50:25 +02:00
len = il - > ucode_boot . len ;
ret = il4965_verify_inst_sparse ( il , image , len ) ;
if ( ! ret ) {
D_INFO ( " Bootstrap uCode is good in inst SRAM \n " ) ;
return 0 ;
}
/* Try initialize */
2011-11-15 14:45:59 +01:00
image = ( __le32 * ) il - > ucode_init . v_addr ;
2011-08-30 12:50:25 +02:00
len = il - > ucode_init . len ;
ret = il4965_verify_inst_sparse ( il , image , len ) ;
if ( ! ret ) {
D_INFO ( " Initialize uCode is good in inst SRAM \n " ) ;
return 0 ;
}
/* Try runtime/protocol */
2011-11-15 14:45:59 +01:00
image = ( __le32 * ) il - > ucode_code . v_addr ;
2011-08-30 12:50:25 +02:00
len = il - > ucode_code . len ;
ret = il4965_verify_inst_sparse ( il , image , len ) ;
if ( ! ret ) {
D_INFO ( " Runtime uCode is good in inst SRAM \n " ) ;
return 0 ;
}
IL_ERR ( " NO VALID UCODE IMAGE IN INSTRUCTION SRAM!! \n " ) ;
/* Since nothing seems to match, show first several data entries in
* instruction SRAM , so maybe visual inspection will give a clue .
* Selection of bootstrap image ( vs . other images ) is arbitrary . */
2011-11-15 14:45:59 +01:00
image = ( __le32 * ) il - > ucode_boot . v_addr ;
2011-08-30 12:50:25 +02:00
len = il - > ucode_boot . len ;
ret = il4965_verify_inst_full ( il , image , len ) ;
return ret ;
}
2011-08-30 12:45:25 +02:00
/******************************************************************************
*
* EEPROM related functions
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* The device ' s EEPROM semaphore prevents conflicts between driver and uCode
* when accessing the EEPROM ; each access is a series of pulses to / from the
* EEPROM chip , not a single event , so even reads could conflict if they
* weren ' t arbitrated by the semaphore .
*/
2011-11-15 14:45:59 +01:00
int
il4965_eeprom_acquire_semaphore ( struct il_priv * il )
2011-08-30 12:45:25 +02:00
{
u16 count ;
int ret ;
for ( count = 0 ; count < EEPROM_SEM_RETRY_LIMIT ; count + + ) {
/* Request semaphore */
il_set_bit ( il , CSR_HW_IF_CONFIG_REG ,
2011-11-15 14:45:59 +01:00
CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM ) ;
2011-08-30 12:45:25 +02:00
/* See if we got it */
2011-11-15 14:45:59 +01:00
ret =
_il_poll_bit ( il , CSR_HW_IF_CONFIG_REG ,
CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM ,
CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM ,
EEPROM_SEM_TIMEOUT ) ;
2011-08-30 12:45:25 +02:00
if ( ret > = 0 )
return ret ;
}
return ret ;
}
2011-11-15 14:45:59 +01:00
void
il4965_eeprom_release_semaphore ( struct il_priv * il )
2011-08-30 12:45:25 +02:00
{
il_clear_bit ( il , CSR_HW_IF_CONFIG_REG ,
2011-11-15 14:45:59 +01:00
CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM ) ;
2011-08-30 12:45:25 +02:00
}
2011-11-15 14:45:59 +01:00
int
il4965_eeprom_check_version ( struct il_priv * il )
2011-08-30 12:45:25 +02:00
{
u16 eeprom_ver ;
u16 calib_ver ;
eeprom_ver = il_eeprom_query16 ( il , EEPROM_VERSION ) ;
2011-11-15 14:45:59 +01:00
calib_ver = il_eeprom_query16 ( il , EEPROM_4965_CALIB_VERSION_OFFSET ) ;
2011-08-30 12:45:25 +02:00
if ( eeprom_ver < il - > cfg - > eeprom_ver | |
calib_ver < il - > cfg - > eeprom_calib_ver )
goto err ;
2011-11-15 14:45:59 +01:00
IL_INFO ( " device EEPROM VER=0x%x, CALIB=0x%x \n " , eeprom_ver , calib_ver ) ;
2011-08-30 12:45:25 +02:00
return 0 ;
err :
IL_ERR ( " Unsupported (too old) EEPROM VER=0x%x < 0x%x "
2011-11-15 14:45:59 +01:00
" CALIB=0x%x < 0x%x \n " , eeprom_ver , il - > cfg - > eeprom_ver ,
calib_ver , il - > cfg - > eeprom_calib_ver ) ;
2011-08-30 12:45:25 +02:00
return - EINVAL ;
}
2011-11-15 14:45:59 +01:00
void
il4965_eeprom_get_mac ( const struct il_priv * il , u8 * mac )
2011-08-30 12:45:25 +02:00
{
const u8 * addr = il_eeprom_query_addr ( il ,
2011-11-15 14:45:59 +01:00
EEPROM_MAC_ADDRESS ) ;
2011-08-30 12:45:25 +02:00
memcpy ( mac , addr , ETH_ALEN ) ;
}
2011-08-29 16:59:15 +02:00
/* Send led command */
static int
il4965_send_led_cmd ( struct il_priv * il , struct il_led_cmd * led_cmd )
{
struct il_host_cmd cmd = {
2011-08-30 15:26:35 +02:00
. id = C_LEDS ,
2011-08-29 16:59:15 +02:00
. len = sizeof ( struct il_led_cmd ) ,
. data = led_cmd ,
. flags = CMD_ASYNC ,
. callback = NULL ,
} ;
u32 reg ;
reg = _il_rd ( il , CSR_LED_REG ) ;
if ( reg ! = ( reg & CSR_LED_BSM_CTRL_MSK ) )
_il_wr ( il , CSR_LED_REG , reg & CSR_LED_BSM_CTRL_MSK ) ;
return il_send_cmd ( il , & cmd ) ;
}
/* Set led register off */
2011-11-15 14:45:59 +01:00
void
il4965_led_enable ( struct il_priv * il )
2011-08-29 16:59:15 +02:00
{
_il_wr ( il , CSR_LED_REG , CSR_LED_REG_TRUN_ON ) ;
}
const struct il_led_ops il4965_led_ops = {
. cmd = il4965_send_led_cmd ,
} ;
2011-10-24 16:49:25 +02:00
static int il4965_send_tx_power ( struct il_priv * il ) ;
static int il4965_hw_get_temperature ( struct il_priv * il ) ;
2011-02-21 11:11:05 -08:00
/* Highest firmware API version supported */
2011-11-15 11:25:42 +01:00
# define IL4965_UCODE_API_MAX 2
2011-02-21 11:11:05 -08:00
/* Lowest firmware API version supported */
2011-11-15 11:25:42 +01:00
# define IL4965_UCODE_API_MIN 2
2011-02-21 11:11:05 -08:00
2011-11-15 11:25:42 +01:00
# define IL4965_FW_PRE "iwlwifi-4965-"
# define _IL4965_MODULE_FIRMWARE(api) IL4965_FW_PRE #api ".ucode"
# define IL4965_MODULE_FIRMWARE(api) _IL4965_MODULE_FIRMWARE(api)
2011-02-21 11:11:05 -08:00
/* check contents of special bootstrap uCode SRAM */
2011-11-15 14:45:59 +01:00
static int
il4965_verify_bsm ( struct il_priv * il )
2011-02-21 11:11:05 -08:00
{
2011-10-24 16:49:25 +02:00
__le32 * image = il - > ucode_boot . v_addr ;
u32 len = il - > ucode_boot . len ;
2011-02-21 11:11:05 -08:00
u32 reg ;
u32 val ;
2011-11-15 11:21:01 +01:00
D_INFO ( " Begin verify bsm \n " ) ;
2011-02-21 11:11:05 -08:00
/* verify BSM SRAM contents */
2011-08-24 21:06:33 +02:00
val = il_rd_prph ( il , BSM_WR_DWCOUNT_REG ) ;
2011-11-15 14:45:59 +01:00
for ( reg = BSM_SRAM_LOWER_BOUND ; reg < BSM_SRAM_LOWER_BOUND + len ;
2011-02-21 11:11:05 -08:00
reg + = sizeof ( u32 ) , image + + ) {
2011-08-24 21:06:33 +02:00
val = il_rd_prph ( il , reg ) ;
2011-02-21 11:11:05 -08:00
if ( val ! = le32_to_cpu ( * image ) ) {
2011-08-18 22:07:57 +02:00
IL_ERR ( " BSM uCode verification failed at "
2011-11-15 14:45:59 +01:00
" addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x \n " ,
BSM_SRAM_LOWER_BOUND , reg - BSM_SRAM_LOWER_BOUND ,
len , val , le32_to_cpu ( * image ) ) ;
2011-02-21 11:11:05 -08:00
return - EIO ;
}
}
2011-11-15 11:21:01 +01:00
D_INFO ( " BSM bootstrap uCode image OK \n " ) ;
2011-02-21 11:11:05 -08:00
return 0 ;
}
/**
2011-10-24 15:41:30 +02:00
* il4965_load_bsm - Load bootstrap instructions
2011-02-21 11:11:05 -08:00
*
* BSM operation :
*
* The Bootstrap State Machine ( BSM ) stores a short bootstrap uCode program
* in special SRAM that does not power down during RFKILL . When powering back
* up after power - saving sleeps ( or during initial uCode load ) , the BSM loads
* the bootstrap program into the on - board processor , and starts it .
*
* The bootstrap program loads ( via DMA ) instructions and data for a new
* program from host DRAM locations indicated by the host driver in the
* BSM_DRAM_ * registers . Once the new program is loaded , it starts
* automatically .
*
* When initializing the NIC , the host driver points the BSM to the
* " initialize " uCode image . This uCode sets up some internal data , then
* notifies host via " initialize alive " that it is complete .
*
* The host then replaces the BSM_DRAM_ * pointer values to point to the
* normal runtime uCode instructions and a backup uCode data cache buffer
* ( filled initially with starting data values for the on - board processor ) ,
* then triggers the " initialize " uCode to load and launch the runtime uCode ,
* which begins normal operation .
*
* When doing a power - save shutdown , runtime uCode saves data SRAM into
* the backup data cache in DRAM before SRAM is powered down .
*
* When powering back up , the BSM loads the bootstrap program . This reloads
* the runtime uCode instructions and the backup data cache into SRAM ,
* and re - launches the runtime uCode from where it left off .
*/
2011-11-15 14:45:59 +01:00
static int
il4965_load_bsm ( struct il_priv * il )
2011-02-21 11:11:05 -08:00
{
2011-10-24 16:49:25 +02:00
__le32 * image = il - > ucode_boot . v_addr ;
u32 len = il - > ucode_boot . len ;
2011-02-21 11:11:05 -08:00
dma_addr_t pinst ;
dma_addr_t pdata ;
u32 inst_len ;
u32 data_len ;
int i ;
u32 done ;
u32 reg_offset ;
int ret ;
2011-11-15 11:21:01 +01:00
D_INFO ( " Begin load bsm \n " ) ;
2011-02-21 11:11:05 -08:00
2011-10-24 16:49:25 +02:00
il - > ucode_type = UCODE_RT ;
2011-02-21 11:11:05 -08:00
/* make sure bootstrap program is no larger than BSM's SRAM size */
2011-11-15 11:25:42 +01:00
if ( len > IL49_MAX_BSM_SIZE )
2011-02-21 11:11:05 -08:00
return - EINVAL ;
/* Tell bootstrap uCode where to find the "Initialize" uCode
* in host DRAM . . . host DRAM physical address bits 35 : 4 for 4965.
2011-10-24 15:41:30 +02:00
* NOTE : il_init_alive_start ( ) will replace these values ,
2011-02-21 11:11:05 -08:00
* after the " initialize " uCode has run , to point to
* runtime / protocol instructions and backup data cache .
*/
2011-10-24 16:49:25 +02:00
pinst = il - > ucode_init . p_addr > > 4 ;
pdata = il - > ucode_init_data . p_addr > > 4 ;
inst_len = il - > ucode_init . len ;
data_len = il - > ucode_init_data . len ;
2011-02-21 11:11:05 -08:00
2011-08-24 21:06:33 +02:00
il_wr_prph ( il , BSM_DRAM_INST_PTR_REG , pinst ) ;
il_wr_prph ( il , BSM_DRAM_DATA_PTR_REG , pdata ) ;
il_wr_prph ( il , BSM_DRAM_INST_BYTECOUNT_REG , inst_len ) ;
il_wr_prph ( il , BSM_DRAM_DATA_BYTECOUNT_REG , data_len ) ;
2011-02-21 11:11:05 -08:00
/* Fill BSM memory with bootstrap instructions */
for ( reg_offset = BSM_SRAM_LOWER_BOUND ;
reg_offset < BSM_SRAM_LOWER_BOUND + len ;
reg_offset + = sizeof ( u32 ) , image + + )
2011-08-24 21:06:33 +02:00
_il_wr_prph ( il , reg_offset , le32_to_cpu ( * image ) ) ;
2011-02-21 11:11:05 -08:00
2011-10-24 16:49:25 +02:00
ret = il4965_verify_bsm ( il ) ;
2011-02-21 11:11:05 -08:00
if ( ret )
return ret ;
/* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
2011-08-24 21:06:33 +02:00
il_wr_prph ( il , BSM_WR_MEM_SRC_REG , 0x0 ) ;
2011-11-15 14:45:59 +01:00
il_wr_prph ( il , BSM_WR_MEM_DST_REG , IL49_RTC_INST_LOWER_BOUND ) ;
2011-08-24 21:06:33 +02:00
il_wr_prph ( il , BSM_WR_DWCOUNT_REG , len / sizeof ( u32 ) ) ;
2011-02-21 11:11:05 -08:00
/* Load bootstrap code into instruction SRAM now,
* to prepare to load " initialize " uCode */
2011-08-24 21:06:33 +02:00
il_wr_prph ( il , BSM_WR_CTRL_REG , BSM_WR_CTRL_REG_BIT_START ) ;
2011-02-21 11:11:05 -08:00
/* Wait for load of bootstrap uCode to finish */
for ( i = 0 ; i < 100 ; i + + ) {
2011-08-24 21:06:33 +02:00
done = il_rd_prph ( il , BSM_WR_CTRL_REG ) ;
2011-02-21 11:11:05 -08:00
if ( ! ( done & BSM_WR_CTRL_REG_BIT_START ) )
break ;
udelay ( 10 ) ;
}
if ( i < 100 )
2011-11-15 11:21:01 +01:00
D_INFO ( " BSM write complete, poll %d iterations \n " , i ) ;
2011-02-21 11:11:05 -08:00
else {
2011-08-18 22:07:57 +02:00
IL_ERR ( " BSM write did not complete! \n " ) ;
2011-02-21 11:11:05 -08:00
return - EIO ;
}
/* Enable future boot loads whenever power management unit triggers it
* ( e . g . when powering back up after power - save shutdown ) */
2011-11-15 14:45:59 +01:00
il_wr_prph ( il , BSM_WR_CTRL_REG , BSM_WR_CTRL_REG_BIT_START_EN ) ;
2011-02-21 11:11:05 -08:00
return 0 ;
}
/**
2011-10-24 15:41:30 +02:00
* il4965_set_ucode_ptrs - Set uCode address location
2011-02-21 11:11:05 -08:00
*
* Tell initialization uCode where to find runtime uCode .
*
* BSM registers initially contain pointers to initialization uCode .
* We need to replace them to load runtime uCode inst and data ,
* and to save runtime data when powering down .
*/
2011-11-15 14:45:59 +01:00
static int
il4965_set_ucode_ptrs ( struct il_priv * il )
2011-02-21 11:11:05 -08:00
{
dma_addr_t pinst ;
dma_addr_t pdata ;
int ret = 0 ;
/* bits 35:4 for 4965 */
2011-10-24 16:49:25 +02:00
pinst = il - > ucode_code . p_addr > > 4 ;
pdata = il - > ucode_data_backup . p_addr > > 4 ;
2011-02-21 11:11:05 -08:00
/* Tell bootstrap uCode where to find image to load */
2011-08-24 21:06:33 +02:00
il_wr_prph ( il , BSM_DRAM_INST_PTR_REG , pinst ) ;
il_wr_prph ( il , BSM_DRAM_DATA_PTR_REG , pdata ) ;
2011-11-15 14:45:59 +01:00
il_wr_prph ( il , BSM_DRAM_DATA_BYTECOUNT_REG , il - > ucode_data . len ) ;
2011-02-21 11:11:05 -08:00
/* Inst byte count must be last to set up, bit 31 signals uCode
* that all new ptr / size info is in place */
2011-08-24 21:06:33 +02:00
il_wr_prph ( il , BSM_DRAM_INST_BYTECOUNT_REG ,
2011-11-15 14:45:59 +01:00
il - > ucode_code . len | BSM_DRAM_INST_LOAD ) ;
2011-11-15 11:21:01 +01:00
D_INFO ( " Runtime uCode pointers are set. \n " ) ;
2011-02-21 11:11:05 -08:00
return ret ;
}
/**
2011-08-30 15:26:35 +02:00
* il4965_init_alive_start - Called after N_ALIVE notification received
2011-02-21 11:11:05 -08:00
*
2011-08-30 15:26:35 +02:00
* Called after N_ALIVE notification received from " initialize " uCode .
2011-02-21 11:11:05 -08:00
*
* The 4965 " initialize " ALIVE reply contains calibration data for :
2011-10-24 16:49:25 +02:00
* Voltage , temperature , and MIMO tx gain correction , now stored in il
2011-02-21 11:11:05 -08:00
* ( 3945 does not contain this data ) .
*
* Tell " initialize " uCode to go ahead and load the runtime uCode .
*/
2011-11-15 14:45:59 +01:00
static void
il4965_init_alive_start ( struct il_priv * il )
2011-02-21 11:11:05 -08:00
{
/* Bootstrap uCode has loaded initialize uCode ... verify inst image.
* This is a paranoid check , because we would not have gotten the
* " initialize " alive if code weren ' t properly loaded . */
2011-10-24 16:49:25 +02:00
if ( il4965_verify_ucode ( il ) ) {
2011-02-21 11:11:05 -08:00
/* Runtime instruction load was bad;
* take it all the way back down so we can try again */
2011-11-15 11:21:01 +01:00
D_INFO ( " Bad \" initialize \" uCode load. \n " ) ;
2011-02-21 11:11:05 -08:00
goto restart ;
}
/* Calculate temperature */
2011-10-24 16:49:25 +02:00
il - > temperature = il4965_hw_get_temperature ( il ) ;
2011-02-21 11:11:05 -08:00
/* Send pointers to protocol/runtime uCode image ... init code will
* load and launch runtime uCode , which will send us another " Alive "
* notification . */
2011-11-15 11:21:01 +01:00
D_INFO ( " Initialization Alive received. \n " ) ;
2011-10-24 16:49:25 +02:00
if ( il4965_set_ucode_ptrs ( il ) ) {
2011-02-21 11:11:05 -08:00
/* Runtime instruction load won't happen;
* take it all the way back down so we can try again */
2011-11-15 11:21:01 +01:00
D_INFO ( " Couldn't set up uCode pointers. \n " ) ;
2011-02-21 11:11:05 -08:00
goto restart ;
}
return ;
restart :
2011-10-24 16:49:25 +02:00
queue_work ( il - > workqueue , & il - > restart ) ;
2011-02-21 11:11:05 -08:00
}
2011-11-15 14:45:59 +01:00
static bool
iw4965_is_ht40_channel ( __le32 rxon_flags )
2011-02-21 11:11:05 -08:00
{
2011-11-15 14:45:59 +01:00
int chan_mod =
le32_to_cpu ( rxon_flags & RXON_FLG_CHANNEL_MODE_MSK ) > >
RXON_FLG_CHANNEL_MODE_POS ;
2011-08-26 10:45:16 +02:00
return ( chan_mod = = CHANNEL_MODE_PURE_40 | |
chan_mod = = CHANNEL_MODE_MIXED ) ;
2011-02-21 11:11:05 -08:00
}
2011-11-15 14:45:59 +01:00
static void
il4965_nic_config ( struct il_priv * il )
2011-02-21 11:11:05 -08:00
{
unsigned long flags ;
u16 radio_cfg ;
2011-10-24 16:49:25 +02:00
spin_lock_irqsave ( & il - > lock , flags ) ;
2011-02-21 11:11:05 -08:00
2011-10-24 16:49:25 +02:00
radio_cfg = il_eeprom_query16 ( il , EEPROM_RADIO_CONFIG ) ;
2011-02-21 11:11:05 -08:00
/* write radio config values to register */
if ( EEPROM_RF_CFG_TYPE_MSK ( radio_cfg ) = = EEPROM_4965_RF_CFG_TYPE_MAX )
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
EEPROM_RF_CFG_TYPE_MSK ( radio_cfg ) |
EEPROM_RF_CFG_STEP_MSK ( radio_cfg ) |
EEPROM_RF_CFG_DASH_MSK ( radio_cfg ) ) ;
2011-02-21 11:11:05 -08:00
/* set CSR_HW_CONFIG_REG for uCode use */
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_RADIO_SI |
CSR_HW_IF_CONFIG_REG_BIT_MAC_SI ) ;
2011-02-21 11:11:05 -08:00
2011-11-15 14:45:59 +01:00
il - > calib_info =
2011-11-15 14:51:01 +01:00
( struct il_eeprom_calib_info * )
il_eeprom_query_addr ( il , EEPROM_4965_CALIB_TXPOWER_OFFSET ) ;
2011-02-21 11:11:05 -08:00
2011-10-24 16:49:25 +02:00
spin_unlock_irqrestore ( & il - > lock , flags ) ;
2011-02-21 11:11:05 -08:00
}
/* Reset differential Rx gains in NIC to prepare for chain noise calibration.
* Called after every association , but this runs only once !
* . . . once chain noise is calibrated the first time , it ' s good forever . */
2011-11-15 14:45:59 +01:00
static void
il4965_chain_noise_reset ( struct il_priv * il )
2011-02-21 11:11:05 -08:00
{
2011-10-24 16:49:25 +02:00
struct il_chain_noise_data * data = & ( il - > chain_noise_data ) ;
2011-02-21 11:11:05 -08:00
2011-11-15 14:45:59 +01:00
if ( data - > state = = IL_CHAIN_NOISE_ALIVE & & il_is_any_associated ( il ) ) {
2011-10-24 15:41:30 +02:00
struct il_calib_diff_gain_cmd cmd ;
2011-02-21 11:11:05 -08:00
/* clear data for chain noise calibration algorithm */
data - > chain_noise_a = 0 ;
data - > chain_noise_b = 0 ;
data - > chain_noise_c = 0 ;
data - > chain_signal_a = 0 ;
data - > chain_signal_b = 0 ;
data - > chain_signal_c = 0 ;
data - > beacon_count = 0 ;
memset ( & cmd , 0 , sizeof ( cmd ) ) ;
2011-10-24 15:41:30 +02:00
cmd . hdr . op_code = IL_PHY_CALIBRATE_DIFF_GAIN_CMD ;
2011-02-21 11:11:05 -08:00
cmd . diff_gain_a = 0 ;
cmd . diff_gain_b = 0 ;
cmd . diff_gain_c = 0 ;
2011-11-15 14:45:59 +01:00
if ( il_send_cmd_pdu ( il , C_PHY_CALIBRATION , sizeof ( cmd ) , & cmd ) )
IL_ERR ( " Could not send C_PHY_CALIBRATION \n " ) ;
2011-10-24 15:41:30 +02:00
data - > state = IL_CHAIN_NOISE_ACCUMULATE ;
2011-11-15 11:21:01 +01:00
D_CALIB ( " Run chain_noise_calibrate \n " ) ;
2011-02-21 11:11:05 -08:00
}
}
2011-10-24 15:41:30 +02:00
static struct il_sensitivity_ranges il4965_sensitivity = {
2011-02-21 11:11:05 -08:00
. min_nrg_cck = 97 ,
2011-11-15 14:45:59 +01:00
. max_nrg_cck = 0 , /* not used, set to 0 */
2011-02-21 11:11:05 -08:00
. auto_corr_min_ofdm = 85 ,
. auto_corr_min_ofdm_mrc = 170 ,
. auto_corr_min_ofdm_x1 = 105 ,
. auto_corr_min_ofdm_mrc_x1 = 220 ,
. auto_corr_max_ofdm = 120 ,
. auto_corr_max_ofdm_mrc = 210 ,
. auto_corr_max_ofdm_x1 = 140 ,
. auto_corr_max_ofdm_mrc_x1 = 270 ,
. auto_corr_min_cck = 125 ,
. auto_corr_max_cck = 200 ,
. auto_corr_min_cck_mrc = 200 ,
. auto_corr_max_cck_mrc = 400 ,
. nrg_th_cck = 100 ,
. nrg_th_ofdm = 100 ,
. barker_corr_th_min = 190 ,
. barker_corr_th_min_mrc = 390 ,
. nrg_th_cca = 62 ,
} ;
2011-11-15 14:45:59 +01:00
static void
il4965_set_ct_threshold ( struct il_priv * il )
2011-02-21 11:11:05 -08:00
{
/* want Kelvin */
2011-10-24 16:49:25 +02:00
il - > hw_params . ct_kill_threshold =
2011-11-15 14:45:59 +01:00
CELSIUS_TO_KELVIN ( CT_KILL_THRESHOLD_LEGACY ) ;
2011-02-21 11:11:05 -08:00
}
/**
2011-10-24 15:41:30 +02:00
* il4965_hw_set_hw_params
2011-02-21 11:11:05 -08:00
*
* Called when initializing driver
*/
2011-11-15 14:45:59 +01:00
static int
il4965_hw_set_hw_params ( struct il_priv * il )
2011-02-21 11:11:05 -08:00
{
2011-10-24 16:49:25 +02:00
if ( il - > cfg - > mod_params - > num_of_queues > = IL_MIN_NUM_QUEUES & &
2011-11-15 11:25:42 +01:00
il - > cfg - > mod_params - > num_of_queues < = IL49_NUM_QUEUES )
2012-02-03 17:31:59 +01:00
il - > cfg - > num_of_queues =
2011-11-15 14:45:59 +01:00
il - > cfg - > mod_params - > num_of_queues ;
2011-10-24 16:49:25 +02:00
2012-02-03 17:31:59 +01:00
il - > hw_params . max_txq_num = il - > cfg - > num_of_queues ;
2011-10-24 16:49:25 +02:00
il - > hw_params . dma_chnl_num = FH49_TCSR_CHNL_NUM ;
il - > hw_params . scd_bc_tbls_size =
2012-02-03 17:31:59 +01:00
il - > cfg - > num_of_queues *
2011-11-15 14:45:59 +01:00
sizeof ( struct il4965_scd_bc_tbl ) ;
2011-10-24 16:49:25 +02:00
il - > hw_params . tfd_size = sizeof ( struct il_tfd ) ;
2011-11-15 11:25:42 +01:00
il - > hw_params . max_stations = IL4965_STATION_COUNT ;
il - > hw_params . max_data_size = IL49_RTC_DATA_SIZE ;
il - > hw_params . max_inst_size = IL49_RTC_INST_SIZE ;
2011-10-24 16:49:25 +02:00
il - > hw_params . max_bsm_size = BSM_SRAM_SIZE ;
il - > hw_params . ht40_channel = BIT ( IEEE80211_BAND_5GHZ ) ;
2011-02-21 11:11:05 -08:00
2011-08-31 14:20:23 +02:00
il - > hw_params . rx_wrt_ptr_reg = FH49_RSCSR_CHNL0_WPTR ;
2011-02-21 11:11:05 -08:00
2011-10-24 16:49:25 +02:00
il - > hw_params . tx_chains_num = il4965_num_of_ant ( il - > cfg - > valid_tx_ant ) ;
il - > hw_params . rx_chains_num = il4965_num_of_ant ( il - > cfg - > valid_rx_ant ) ;
il - > hw_params . valid_tx_ant = il - > cfg - > valid_tx_ant ;
il - > hw_params . valid_rx_ant = il - > cfg - > valid_rx_ant ;
2011-02-21 11:11:05 -08:00
2011-10-24 16:49:25 +02:00
il4965_set_ct_threshold ( il ) ;
2011-02-21 11:11:05 -08:00
2011-10-24 16:49:25 +02:00
il - > hw_params . sens = & il4965_sensitivity ;
2011-11-15 11:25:42 +01:00
il - > hw_params . beacon_time_tsf_bits = IL4965_EXT_BEACON_TIME_POS ;
2011-02-21 11:11:05 -08:00
return 0 ;
}
2011-11-15 14:45:59 +01:00
static s32
il4965_math_div_round ( s32 num , s32 denom , s32 * res )
2011-02-21 11:11:05 -08:00
{
s32 sign = 1 ;
if ( num < 0 ) {
sign = - sign ;
num = - num ;
}
if ( denom < 0 ) {
sign = - sign ;
denom = - denom ;
}
* res = 1 ;
* res = ( ( num * 2 + denom ) / ( denom * 2 ) ) * sign ;
return 1 ;
}
/**
2011-10-24 15:41:30 +02:00
* il4965_get_voltage_compensation - Power supply voltage comp for txpower
2011-02-21 11:11:05 -08:00
*
* Determines power supply voltage compensation for txpower calculations .
2011-11-15 12:30:17 +01:00
* Returns number of 1 / 2 - dB steps to subtract from gain table idx ,
2011-02-21 11:11:05 -08:00
* to compensate for difference between power supply voltage during
* factory measurements , vs . current power supply voltage .
*
* Voltage indication is higher for lower voltage .
2011-11-15 12:30:17 +01:00
* Lower voltage requires more gain ( lower gain table idx ) .
2011-02-21 11:11:05 -08:00
*/
2011-11-15 14:45:59 +01:00
static s32
il4965_get_voltage_compensation ( s32 eeprom_voltage , s32 current_voltage )
2011-02-21 11:11:05 -08:00
{
s32 comp = 0 ;
2011-08-26 10:45:16 +02:00
if ( TX_POWER_IL_ILLEGAL_VOLTAGE = = eeprom_voltage | |
TX_POWER_IL_ILLEGAL_VOLTAGE = = current_voltage )
2011-02-21 11:11:05 -08:00
return 0 ;
2011-10-24 15:41:30 +02:00
il4965_math_div_round ( current_voltage - eeprom_voltage ,
2011-11-15 14:45:59 +01:00
TX_POWER_IL_VOLTAGE_CODES_PER_03V , & comp ) ;
2011-02-21 11:11:05 -08:00
if ( current_voltage > eeprom_voltage )
comp * = 2 ;
if ( ( comp < - 2 ) | | ( comp > 2 ) )
comp = 0 ;
return comp ;
}
2011-11-15 14:45:59 +01:00
static s32
il4965_get_tx_atten_grp ( u16 channel )
2011-02-21 11:11:05 -08:00
{
2011-10-24 15:41:30 +02:00
if ( channel > = CALIB_IL_TX_ATTEN_GR5_FCH & &
channel < = CALIB_IL_TX_ATTEN_GR5_LCH )
2011-02-21 11:11:05 -08:00
return CALIB_CH_GROUP_5 ;
2011-10-24 15:41:30 +02:00
if ( channel > = CALIB_IL_TX_ATTEN_GR1_FCH & &
channel < = CALIB_IL_TX_ATTEN_GR1_LCH )
2011-02-21 11:11:05 -08:00
return CALIB_CH_GROUP_1 ;
2011-10-24 15:41:30 +02:00
if ( channel > = CALIB_IL_TX_ATTEN_GR2_FCH & &
channel < = CALIB_IL_TX_ATTEN_GR2_LCH )
2011-02-21 11:11:05 -08:00
return CALIB_CH_GROUP_2 ;
2011-10-24 15:41:30 +02:00
if ( channel > = CALIB_IL_TX_ATTEN_GR3_FCH & &
channel < = CALIB_IL_TX_ATTEN_GR3_LCH )
2011-02-21 11:11:05 -08:00
return CALIB_CH_GROUP_3 ;
2011-10-24 15:41:30 +02:00
if ( channel > = CALIB_IL_TX_ATTEN_GR4_FCH & &
channel < = CALIB_IL_TX_ATTEN_GR4_LCH )
2011-02-21 11:11:05 -08:00
return CALIB_CH_GROUP_4 ;
2011-06-02 21:06:08 -05:00
return - EINVAL ;
2011-02-21 11:11:05 -08:00
}
2011-11-15 14:45:59 +01:00
static u32
il4965_get_sub_band ( const struct il_priv * il , u32 channel )
2011-02-21 11:11:05 -08:00
{
s32 b = - 1 ;
for ( b = 0 ; b < EEPROM_TX_POWER_BANDS ; b + + ) {
2011-10-24 16:49:25 +02:00
if ( il - > calib_info - > band_info [ b ] . ch_from = = 0 )
2011-02-21 11:11:05 -08:00
continue ;
2011-08-26 10:45:16 +02:00
if ( channel > = il - > calib_info - > band_info [ b ] . ch_from & &
channel < = il - > calib_info - > band_info [ b ] . ch_to )
2011-02-21 11:11:05 -08:00
break ;
}
return b ;
}
2011-11-15 14:45:59 +01:00
static s32
il4965_interpolate_value ( s32 x , s32 x1 , s32 y1 , s32 x2 , s32 y2 )
2011-02-21 11:11:05 -08:00
{
s32 val ;
if ( x2 = = x1 )
return y1 ;
else {
2011-10-24 15:41:30 +02:00
il4965_math_div_round ( ( x2 - x ) * ( y1 - y2 ) , ( x2 - x1 ) , & val ) ;
2011-02-21 11:11:05 -08:00
return val + y2 ;
}
}
/**
2011-10-24 15:41:30 +02:00
* il4965_interpolate_chan - Interpolate factory measurements for one channel
2011-02-21 11:11:05 -08:00
*
* Interpolates factory measurements from the two sample channels within a
* sub - band , to apply to channel of interest . Interpolation is proportional to
* differences in channel frequencies , which is proportional to differences
* in channel number .
*/
2011-11-15 14:45:59 +01:00
static int
il4965_interpolate_chan ( struct il_priv * il , u32 channel ,
struct il_eeprom_calib_ch_info * chan_info )
2011-02-21 11:11:05 -08:00
{
s32 s = - 1 ;
u32 c ;
u32 m ;
2011-10-24 15:41:30 +02:00
const struct il_eeprom_calib_measure * m1 ;
const struct il_eeprom_calib_measure * m2 ;
struct il_eeprom_calib_measure * omeas ;
2011-02-21 11:11:05 -08:00
u32 ch_i1 ;
u32 ch_i2 ;
2011-10-24 16:49:25 +02:00
s = il4965_get_sub_band ( il , channel ) ;
2011-02-21 11:11:05 -08:00
if ( s > = EEPROM_TX_POWER_BANDS ) {
2011-08-18 22:07:57 +02:00
IL_ERR ( " Tx Power can not find channel %d \n " , channel ) ;
2011-02-21 11:11:05 -08:00
return - 1 ;
}
2011-10-24 16:49:25 +02:00
ch_i1 = il - > calib_info - > band_info [ s ] . ch1 . ch_num ;
ch_i2 = il - > calib_info - > band_info [ s ] . ch2 . ch_num ;
2011-02-21 11:11:05 -08:00
chan_info - > ch_num = ( u8 ) channel ;
2011-11-15 14:45:59 +01:00
D_TXPOWER ( " channel %d subband %d factory cal ch %d & %d \n " , channel , s ,
ch_i1 , ch_i2 ) ;
2011-02-21 11:11:05 -08:00
for ( c = 0 ; c < EEPROM_TX_POWER_TX_CHAINS ; c + + ) {
for ( m = 0 ; m < EEPROM_TX_POWER_MEASUREMENTS ; m + + ) {
2011-10-24 16:49:25 +02:00
m1 = & ( il - > calib_info - > band_info [ s ] . ch1 .
2011-02-21 11:11:05 -08:00
measurements [ c ] [ m ] ) ;
2011-10-24 16:49:25 +02:00
m2 = & ( il - > calib_info - > band_info [ s ] . ch2 .
2011-02-21 11:11:05 -08:00
measurements [ c ] [ m ] ) ;
omeas = & ( chan_info - > measurements [ c ] [ m ] ) ;
omeas - > actual_pow =
2011-10-24 15:41:30 +02:00
( u8 ) il4965_interpolate_value ( channel , ch_i1 ,
2011-11-15 14:45:59 +01:00
m1 - > actual_pow , ch_i2 ,
m2 - > actual_pow ) ;
2011-02-21 11:11:05 -08:00
omeas - > gain_idx =
2011-10-24 15:41:30 +02:00
( u8 ) il4965_interpolate_value ( channel , ch_i1 ,
2011-11-15 14:45:59 +01:00
m1 - > gain_idx , ch_i2 ,
m2 - > gain_idx ) ;
2011-02-21 11:11:05 -08:00
omeas - > temperature =
2011-10-24 15:41:30 +02:00
( u8 ) il4965_interpolate_value ( channel , ch_i1 ,
2011-11-15 14:45:59 +01:00
m1 - > temperature ,
ch_i2 ,
m2 - > temperature ) ;
2011-02-21 11:11:05 -08:00
omeas - > pa_det =
2011-10-24 15:41:30 +02:00
( s8 ) il4965_interpolate_value ( channel , ch_i1 ,
2011-11-15 14:45:59 +01:00
m1 - > pa_det , ch_i2 ,
m2 - > pa_det ) ;
D_TXPOWER ( " chain %d meas %d AP1=%d AP2=%d AP=%d \n " , c ,
m , m1 - > actual_pow , m2 - > actual_pow ,
omeas - > actual_pow ) ;
D_TXPOWER ( " chain %d meas %d NI1=%d NI2=%d NI=%d \n " , c ,
m , m1 - > gain_idx , m2 - > gain_idx ,
omeas - > gain_idx ) ;
D_TXPOWER ( " chain %d meas %d PA1=%d PA2=%d PA=%d \n " , c ,
m , m1 - > pa_det , m2 - > pa_det , omeas - > pa_det ) ;
D_TXPOWER ( " chain %d meas %d T1=%d T2=%d T=%d \n " , c ,
m , m1 - > temperature , m2 - > temperature ,
omeas - > temperature ) ;
2011-02-21 11:11:05 -08:00
}
}
return 0 ;
}
/* bit-rate-dependent table to prevent Tx distortion, in half-dB units,
* for OFDM 6 , 12 , 18 , 24 , 36 , 48 , 54 , 60 MBit , and CCK all rates . */
static s32 back_off_table [ ] = {
10 , 10 , 10 , 10 , 10 , 15 , 17 , 20 , /* OFDM SISO 20 MHz */
10 , 10 , 10 , 10 , 10 , 15 , 17 , 20 , /* OFDM MIMO 20 MHz */
10 , 10 , 10 , 10 , 10 , 15 , 17 , 20 , /* OFDM SISO 40 MHz */
10 , 10 , 10 , 10 , 10 , 15 , 17 , 20 , /* OFDM MIMO 40 MHz */
10 /* CCK */
} ;
/* Thermal compensation values for txpower for various frequency ranges ...
* ratios from 3 : 1 to 4.5 : 1 of degrees ( Celsius ) per half - dB gain adjust */
2011-10-24 15:41:30 +02:00
static struct il4965_txpower_comp_entry {
2011-02-21 11:11:05 -08:00
s32 degrees_per_05db_a ;
s32 degrees_per_05db_a_denom ;
} tx_power_cmp_tble [ CALIB_CH_GROUP_MAX ] = {
2011-11-15 14:45:59 +01:00
{
9 , 2 } , /* group 0 5.2, ch 34-43 */
{
4 , 1 } , /* group 1 5.2, ch 44-70 */
{
4 , 1 } , /* group 2 5.2, ch 71-124 */
{
4 , 1 } , /* group 3 5.2, ch 125-200 */
{
3 , 1 } /* group 4 2.4, ch all */
2011-02-21 11:11:05 -08:00
} ;
2011-11-15 14:45:59 +01:00
static s32
get_min_power_idx ( s32 rate_power_idx , u32 band )
2011-02-21 11:11:05 -08:00
{
if ( ! band ) {
2011-11-15 12:30:17 +01:00
if ( ( rate_power_idx & 7 ) < = 4 )
2011-08-26 16:10:40 +02:00
return MIN_TX_GAIN_IDX_52GHZ_EXT ;
2011-02-21 11:11:05 -08:00
}
2011-08-26 16:10:40 +02:00
return MIN_TX_GAIN_IDX ;
2011-02-21 11:11:05 -08:00
}
struct gain_entry {
u8 dsp ;
u8 radio ;
} ;
static const struct gain_entry gain_table [ 2 ] [ 108 ] = {
2011-11-15 12:30:17 +01:00
/* 5.2GHz power gain idx table */
2011-02-21 11:11:05 -08:00
{
{ 123 , 0x3F } , /* highest txpower */
{ 117 , 0x3F } ,
{ 110 , 0x3F } ,
{ 104 , 0x3F } ,
{ 98 , 0x3F } ,
{ 110 , 0x3E } ,
{ 104 , 0x3E } ,
{ 98 , 0x3E } ,
{ 110 , 0x3D } ,
{ 104 , 0x3D } ,
{ 98 , 0x3D } ,
{ 110 , 0x3C } ,
{ 104 , 0x3C } ,
{ 98 , 0x3C } ,
{ 110 , 0x3B } ,
{ 104 , 0x3B } ,
{ 98 , 0x3B } ,
{ 110 , 0x3A } ,
{ 104 , 0x3A } ,
{ 98 , 0x3A } ,
{ 110 , 0x39 } ,
{ 104 , 0x39 } ,
{ 98 , 0x39 } ,
{ 110 , 0x38 } ,
{ 104 , 0x38 } ,
{ 98 , 0x38 } ,
{ 110 , 0x37 } ,
{ 104 , 0x37 } ,
{ 98 , 0x37 } ,
{ 110 , 0x36 } ,
{ 104 , 0x36 } ,
{ 98 , 0x36 } ,
{ 110 , 0x35 } ,
{ 104 , 0x35 } ,
{ 98 , 0x35 } ,
{ 110 , 0x34 } ,
{ 104 , 0x34 } ,
{ 98 , 0x34 } ,
{ 110 , 0x33 } ,
{ 104 , 0x33 } ,
{ 98 , 0x33 } ,
{ 110 , 0x32 } ,
{ 104 , 0x32 } ,
{ 98 , 0x32 } ,
{ 110 , 0x31 } ,
{ 104 , 0x31 } ,
{ 98 , 0x31 } ,
{ 110 , 0x30 } ,
{ 104 , 0x30 } ,
{ 98 , 0x30 } ,
{ 110 , 0x25 } ,
{ 104 , 0x25 } ,
{ 98 , 0x25 } ,
{ 110 , 0x24 } ,
{ 104 , 0x24 } ,
{ 98 , 0x24 } ,
{ 110 , 0x23 } ,
{ 104 , 0x23 } ,
{ 98 , 0x23 } ,
{ 110 , 0x22 } ,
{ 104 , 0x18 } ,
{ 98 , 0x18 } ,
{ 110 , 0x17 } ,
{ 104 , 0x17 } ,
{ 98 , 0x17 } ,
{ 110 , 0x16 } ,
{ 104 , 0x16 } ,
{ 98 , 0x16 } ,
{ 110 , 0x15 } ,
{ 104 , 0x15 } ,
{ 98 , 0x15 } ,
{ 110 , 0x14 } ,
{ 104 , 0x14 } ,
{ 98 , 0x14 } ,
{ 110 , 0x13 } ,
{ 104 , 0x13 } ,
{ 98 , 0x13 } ,
{ 110 , 0x12 } ,
{ 104 , 0x08 } ,
{ 98 , 0x08 } ,
{ 110 , 0x07 } ,
{ 104 , 0x07 } ,
{ 98 , 0x07 } ,
{ 110 , 0x06 } ,
{ 104 , 0x06 } ,
{ 98 , 0x06 } ,
{ 110 , 0x05 } ,
{ 104 , 0x05 } ,
{ 98 , 0x05 } ,
{ 110 , 0x04 } ,
{ 104 , 0x04 } ,
{ 98 , 0x04 } ,
{ 110 , 0x03 } ,
{ 104 , 0x03 } ,
{ 98 , 0x03 } ,
{ 110 , 0x02 } ,
{ 104 , 0x02 } ,
{ 98 , 0x02 } ,
{ 110 , 0x01 } ,
{ 104 , 0x01 } ,
{ 98 , 0x01 } ,
{ 110 , 0x00 } ,
{ 104 , 0x00 } ,
{ 98 , 0x00 } ,
{ 93 , 0x00 } ,
{ 88 , 0x00 } ,
{ 83 , 0x00 } ,
{ 78 , 0x00 } ,
} ,
2011-11-15 12:30:17 +01:00
/* 2.4GHz power gain idx table */
2011-02-21 11:11:05 -08:00
{
{ 110 , 0x3f } , /* highest txpower */
{ 104 , 0x3f } ,
{ 98 , 0x3f } ,
{ 110 , 0x3e } ,
{ 104 , 0x3e } ,
{ 98 , 0x3e } ,
{ 110 , 0x3d } ,
{ 104 , 0x3d } ,
{ 98 , 0x3d } ,
{ 110 , 0x3c } ,
{ 104 , 0x3c } ,
{ 98 , 0x3c } ,
{ 110 , 0x3b } ,
{ 104 , 0x3b } ,
{ 98 , 0x3b } ,
{ 110 , 0x3a } ,
{ 104 , 0x3a } ,
{ 98 , 0x3a } ,
{ 110 , 0x39 } ,
{ 104 , 0x39 } ,
{ 98 , 0x39 } ,
{ 110 , 0x38 } ,
{ 104 , 0x38 } ,
{ 98 , 0x38 } ,
{ 110 , 0x37 } ,
{ 104 , 0x37 } ,
{ 98 , 0x37 } ,
{ 110 , 0x36 } ,
{ 104 , 0x36 } ,
{ 98 , 0x36 } ,
{ 110 , 0x35 } ,
{ 104 , 0x35 } ,
{ 98 , 0x35 } ,
{ 110 , 0x34 } ,
{ 104 , 0x34 } ,
{ 98 , 0x34 } ,
{ 110 , 0x33 } ,
{ 104 , 0x33 } ,
{ 98 , 0x33 } ,
{ 110 , 0x32 } ,
{ 104 , 0x32 } ,
{ 98 , 0x32 } ,
{ 110 , 0x31 } ,
{ 104 , 0x31 } ,
{ 98 , 0x31 } ,
{ 110 , 0x30 } ,
{ 104 , 0x30 } ,
{ 98 , 0x30 } ,
{ 110 , 0x6 } ,
{ 104 , 0x6 } ,
{ 98 , 0x6 } ,
{ 110 , 0x5 } ,
{ 104 , 0x5 } ,
{ 98 , 0x5 } ,
{ 110 , 0x4 } ,
{ 104 , 0x4 } ,
{ 98 , 0x4 } ,
{ 110 , 0x3 } ,
{ 104 , 0x3 } ,
{ 98 , 0x3 } ,
{ 110 , 0x2 } ,
{ 104 , 0x2 } ,
{ 98 , 0x2 } ,
{ 110 , 0x1 } ,
{ 104 , 0x1 } ,
{ 98 , 0x1 } ,
{ 110 , 0x0 } ,
{ 104 , 0x0 } ,
{ 98 , 0x0 } ,
{ 97 , 0 } ,
{ 96 , 0 } ,
{ 95 , 0 } ,
{ 94 , 0 } ,
{ 93 , 0 } ,
{ 92 , 0 } ,
{ 91 , 0 } ,
{ 90 , 0 } ,
{ 89 , 0 } ,
{ 88 , 0 } ,
{ 87 , 0 } ,
{ 86 , 0 } ,
{ 85 , 0 } ,
{ 84 , 0 } ,
{ 83 , 0 } ,
{ 82 , 0 } ,
{ 81 , 0 } ,
{ 80 , 0 } ,
{ 79 , 0 } ,
{ 78 , 0 } ,
{ 77 , 0 } ,
{ 76 , 0 } ,
{ 75 , 0 } ,
{ 74 , 0 } ,
{ 73 , 0 } ,
{ 72 , 0 } ,
{ 71 , 0 } ,
{ 70 , 0 } ,
{ 69 , 0 } ,
{ 68 , 0 } ,
{ 67 , 0 } ,
{ 66 , 0 } ,
{ 65 , 0 } ,
{ 64 , 0 } ,
{ 63 , 0 } ,
{ 62 , 0 } ,
{ 61 , 0 } ,
{ 60 , 0 } ,
{ 59 , 0 } ,
}
} ;
2011-11-15 14:45:59 +01:00
static int
il4965_fill_txpower_tbl ( struct il_priv * il , u8 band , u16 channel , u8 is_ht40 ,
u8 ctrl_chan_high ,
struct il4965_tx_power_db * tx_power_tbl )
2011-02-21 11:11:05 -08:00
{
u8 saturation_power ;
s32 target_power ;
s32 user_target_power ;
s32 power_limit ;
s32 current_temp ;
s32 reg_limit ;
s32 current_regulatory ;
s32 txatten_grp = CALIB_CH_GROUP_MAX ;
int i ;
int c ;
2011-10-24 15:41:30 +02:00
const struct il_channel_info * ch_info = NULL ;
struct il_eeprom_calib_ch_info ch_eeprom_info ;
const struct il_eeprom_calib_measure * measurement ;
2011-02-21 11:11:05 -08:00
s16 voltage ;
s32 init_voltage ;
s32 voltage_compensation ;
s32 degrees_per_05db_num ;
s32 degrees_per_05db_denom ;
s32 factory_temp ;
s32 temperature_comp [ 2 ] ;
2011-11-15 12:30:17 +01:00
s32 factory_gain_idx [ 2 ] ;
2011-02-21 11:11:05 -08:00
s32 factory_actual_pwr [ 2 ] ;
2011-11-15 12:30:17 +01:00
s32 power_idx ;
2011-02-21 11:11:05 -08:00
/* tx_power_user_lmt is in dBm, convert to half-dBm (half-dB units
2011-11-15 12:30:17 +01:00
* are used for idxing into txpower table ) */
2011-10-24 16:49:25 +02:00
user_target_power = 2 * il - > tx_power_user_lmt ;
2011-02-21 11:11:05 -08:00
/* Get current (RXON) channel, band, width */
2011-11-15 14:45:59 +01:00
D_TXPOWER ( " chan %d band %d is_ht40 %d \n " , channel , band , is_ht40 ) ;
2011-02-21 11:11:05 -08:00
2011-10-24 16:49:25 +02:00
ch_info = il_get_channel_info ( il , il - > band , channel ) ;
2011-02-21 11:11:05 -08:00
2011-10-24 15:41:30 +02:00
if ( ! il_is_channel_valid ( ch_info ) )
2011-02-21 11:11:05 -08:00
return - EINVAL ;
/* get txatten group, used to select 1) thermal txpower adjustment
* and 2 ) mimo txpower balance between Tx chains . */
2011-10-24 15:41:30 +02:00
txatten_grp = il4965_get_tx_atten_grp ( channel ) ;
2011-02-21 11:11:05 -08:00
if ( txatten_grp < 0 ) {
2011-11-15 14:45:59 +01:00
IL_ERR ( " Can't find txatten group for channel %d. \n " , channel ) ;
2011-06-02 21:06:09 -05:00
return txatten_grp ;
2011-02-21 11:11:05 -08:00
}
2011-11-15 14:45:59 +01:00
D_TXPOWER ( " channel %d belongs to txatten group %d \n " , channel ,
txatten_grp ) ;
2011-02-21 11:11:05 -08:00
if ( is_ht40 ) {
if ( ctrl_chan_high )
channel - = 2 ;
else
channel + = 2 ;
}
/* hardware txpower limits ...
* saturation ( clipping distortion ) txpowers are in half - dBm */
if ( band )
2011-10-24 16:49:25 +02:00
saturation_power = il - > calib_info - > saturation_power24 ;
2011-02-21 11:11:05 -08:00
else
2011-10-24 16:49:25 +02:00
saturation_power = il - > calib_info - > saturation_power52 ;
2011-02-21 11:11:05 -08:00
2011-10-24 15:41:30 +02:00
if ( saturation_power < IL_TX_POWER_SATURATION_MIN | |
saturation_power > IL_TX_POWER_SATURATION_MAX ) {
2011-02-21 11:11:05 -08:00
if ( band )
2011-10-24 15:41:30 +02:00
saturation_power = IL_TX_POWER_DEFAULT_SATURATION_24 ;
2011-02-21 11:11:05 -08:00
else
2011-10-24 15:41:30 +02:00
saturation_power = IL_TX_POWER_DEFAULT_SATURATION_52 ;
2011-02-21 11:11:05 -08:00
}
/* regulatory txpower limits ... reg_limit values are in half-dBm,
* max_power_avg values are in dBm , convert * 2 */
if ( is_ht40 )
reg_limit = ch_info - > ht40_max_power_avg * 2 ;
else
reg_limit = ch_info - > max_power_avg * 2 ;
2011-10-24 15:41:30 +02:00
if ( ( reg_limit < IL_TX_POWER_REGULATORY_MIN ) | |
( reg_limit > IL_TX_POWER_REGULATORY_MAX ) ) {
2011-02-21 11:11:05 -08:00
if ( band )
2011-10-24 15:41:30 +02:00
reg_limit = IL_TX_POWER_DEFAULT_REGULATORY_24 ;
2011-02-21 11:11:05 -08:00
else
2011-10-24 15:41:30 +02:00
reg_limit = IL_TX_POWER_DEFAULT_REGULATORY_52 ;
2011-02-21 11:11:05 -08:00
}
/* Interpolate txpower calibration values for this channel,
* based on factory calibration tests on spaced channels . */
2011-10-24 16:49:25 +02:00
il4965_interpolate_chan ( il , channel , & ch_eeprom_info ) ;
2011-02-21 11:11:05 -08:00
/* calculate tx gain adjustment based on power supply voltage */
2011-10-24 16:49:25 +02:00
voltage = le16_to_cpu ( il - > calib_info - > voltage ) ;
2011-11-15 14:45:59 +01:00
init_voltage = ( s32 ) le32_to_cpu ( il - > card_alive_init . voltage ) ;
2011-02-21 11:11:05 -08:00
voltage_compensation =
2011-10-24 15:41:30 +02:00
il4965_get_voltage_compensation ( voltage , init_voltage ) ;
2011-02-21 11:11:05 -08:00
2011-11-15 14:45:59 +01:00
D_TXPOWER ( " curr volt %d eeprom volt %d volt comp %d \n " , init_voltage ,
voltage , voltage_compensation ) ;
2011-02-21 11:11:05 -08:00
/* get current temperature (Celsius) */
2011-10-24 16:49:25 +02:00
current_temp = max ( il - > temperature , IL_TX_POWER_TEMPERATURE_MIN ) ;
current_temp = min ( il - > temperature , IL_TX_POWER_TEMPERATURE_MAX ) ;
2011-02-21 11:11:05 -08:00
current_temp = KELVIN_TO_CELSIUS ( current_temp ) ;
/* select thermal txpower adjustment params, based on channel group
* ( same frequency group used for mimo txatten adjustment ) */
degrees_per_05db_num =
tx_power_cmp_tble [ txatten_grp ] . degrees_per_05db_a ;
degrees_per_05db_denom =
tx_power_cmp_tble [ txatten_grp ] . degrees_per_05db_a_denom ;
/* get per-chain txpower values from factory measurements */
for ( c = 0 ; c < 2 ; c + + ) {
measurement = & ch_eeprom_info . measurements [ c ] [ 1 ] ;
/* txgain adjustment (in half-dB steps) based on difference
* between factory and current temperature */
factory_temp = measurement - > temperature ;
2011-11-15 14:45:59 +01:00
il4965_math_div_round ( ( current_temp -
factory_temp ) * degrees_per_05db_denom ,
degrees_per_05db_num ,
& temperature_comp [ c ] ) ;
2011-02-21 11:11:05 -08:00
2011-11-15 12:30:17 +01:00
factory_gain_idx [ c ] = measurement - > gain_idx ;
2011-02-21 11:11:05 -08:00
factory_actual_pwr [ c ] = measurement - > actual_pow ;
2011-11-15 11:21:01 +01:00
D_TXPOWER ( " chain = %d \n " , c ) ;
2011-11-15 14:45:59 +01:00
D_TXPOWER ( " fctry tmp %d, " " curr tmp %d, comp %d steps \n " ,
factory_temp , current_temp , temperature_comp [ c ] ) ;
D_TXPOWER ( " fctry idx %d, fctry pwr %d \n " , factory_gain_idx [ c ] ,
factory_actual_pwr [ c ] ) ;
2011-02-21 11:11:05 -08:00
}
/* for each of 33 bit-rates (including 1 for CCK) */
2011-08-26 16:29:35 +02:00
for ( i = 0 ; i < POWER_TBL_NUM_ENTRIES ; i + + ) {
2011-02-21 11:11:05 -08:00
u8 is_mimo_rate ;
2011-10-24 15:41:30 +02:00
union il4965_tx_power_dual_stream tx_power ;
2011-02-21 11:11:05 -08:00
/* for mimo, reduce each chain's txpower by half
* ( 3 dB , 6 steps ) , so total output power is regulatory
* compliant . */
if ( i & 0x8 ) {
2011-11-15 14:45:59 +01:00
current_regulatory =
reg_limit -
2011-10-24 15:41:30 +02:00
IL_TX_POWER_MIMO_REGULATORY_COMPENSATION ;
2011-02-21 11:11:05 -08:00
is_mimo_rate = 1 ;
} else {
current_regulatory = reg_limit ;
is_mimo_rate = 0 ;
}
/* find txpower limit, either hardware or regulatory */
power_limit = saturation_power - back_off_table [ i ] ;
if ( power_limit > current_regulatory )
power_limit = current_regulatory ;
/* reduce user's txpower request if necessary
* for this rate on this channel */
target_power = user_target_power ;
if ( target_power > power_limit )
target_power = power_limit ;
2011-11-15 14:45:59 +01:00
D_TXPOWER ( " rate %d sat %d reg %d usr %d tgt %d \n " , i ,
saturation_power - back_off_table [ i ] ,
current_regulatory , user_target_power , target_power ) ;
2011-02-21 11:11:05 -08:00
/* for each of 2 Tx chains (radio transmitters) */
for ( c = 0 ; c < 2 ; c + + ) {
s32 atten_value ;
if ( is_mimo_rate )
atten_value =
2011-11-15 14:45:59 +01:00
( s32 ) le32_to_cpu ( il - > card_alive_init .
tx_atten [ txatten_grp ] [ c ] ) ;
2011-02-21 11:11:05 -08:00
else
atten_value = 0 ;
2011-11-15 12:30:17 +01:00
/* calculate idx; higher idx means lower txpower */
2011-11-15 14:45:59 +01:00
power_idx =
( u8 ) ( factory_gain_idx [ c ] -
( target_power - factory_actual_pwr [ c ] ) -
temperature_comp [ c ] - voltage_compensation +
atten_value ) ;
2011-02-21 11:11:05 -08:00
2011-11-15 12:30:17 +01:00
/* D_TXPOWER("calculated txpower idx %d\n",
power_idx ) ; */
2011-02-21 11:11:05 -08:00
2011-11-15 12:30:17 +01:00
if ( power_idx < get_min_power_idx ( i , band ) )
power_idx = get_min_power_idx ( i , band ) ;
2011-02-21 11:11:05 -08:00
2011-11-15 12:30:17 +01:00
/* adjust 5 GHz idx to support negative idxes */
2011-02-21 11:11:05 -08:00
if ( ! band )
2011-11-15 12:30:17 +01:00
power_idx + = 9 ;
2011-02-21 11:11:05 -08:00
/* CCK, rate 32, reduce txpower for CCK */
2011-08-26 16:29:35 +02:00
if ( i = = POWER_TBL_CCK_ENTRY )
2011-11-15 12:30:17 +01:00
power_idx + =
2011-10-24 15:41:30 +02:00
IL_TX_POWER_CCK_COMPENSATION_C_STEP ;
2011-02-21 11:11:05 -08:00
/* stay within the table! */
2011-11-15 12:30:17 +01:00
if ( power_idx > 107 ) {
2011-11-15 14:45:59 +01:00
IL_WARN ( " txpower idx %d > 107 \n " , power_idx ) ;
2011-11-15 12:30:17 +01:00
power_idx = 107 ;
2011-02-21 11:11:05 -08:00
}
2011-11-15 12:30:17 +01:00
if ( power_idx < 0 ) {
2011-11-15 14:45:59 +01:00
IL_WARN ( " txpower idx %d < 0 \n " , power_idx ) ;
2011-11-15 12:30:17 +01:00
power_idx = 0 ;
2011-02-21 11:11:05 -08:00
}
/* fill txpower command for this rate/chain */
tx_power . s . radio_tx_gain [ c ] =
2011-11-15 14:45:59 +01:00
gain_table [ band ] [ power_idx ] . radio ;
2011-02-21 11:11:05 -08:00
tx_power . s . dsp_predis_atten [ c ] =
2011-11-15 14:45:59 +01:00
gain_table [ band ] [ power_idx ] . dsp ;
2011-02-21 11:11:05 -08:00
2011-11-15 12:30:17 +01:00
D_TXPOWER ( " chain %d mimo %d idx %d "
2011-11-15 14:45:59 +01:00
" gain 0x%02x dsp %d \n " , c , atten_value ,
power_idx , tx_power . s . radio_tx_gain [ c ] ,
tx_power . s . dsp_predis_atten [ c ] ) ;
} /* for each chain */
2011-02-21 11:11:05 -08:00
tx_power_tbl - > power_tbl [ i ] . dw = cpu_to_le32 ( tx_power . dw ) ;
2011-11-15 14:45:59 +01:00
} /* for each rate */
2011-02-21 11:11:05 -08:00
return 0 ;
}
/**
2011-10-24 15:41:30 +02:00
* il4965_send_tx_power - Configure the TXPOWER level user limit
2011-02-21 11:11:05 -08:00
*
* Uses the active RXON for channel , band , and characteristics ( ht40 , high )
2011-10-24 16:49:25 +02:00
* The power limit is taken from il - > tx_power_user_lmt .
2011-02-21 11:11:05 -08:00
*/
2011-11-15 14:45:59 +01:00
static int
il4965_send_tx_power ( struct il_priv * il )
2011-02-21 11:11:05 -08:00
{
2011-10-24 15:41:30 +02:00
struct il4965_txpowertable_cmd cmd = { 0 } ;
2011-02-21 11:11:05 -08:00
int ret ;
u8 band = 0 ;
bool is_ht40 = false ;
u8 ctrl_chan_high = 0 ;
2011-11-15 14:45:59 +01:00
if ( WARN_ONCE
( test_bit ( S_SCAN_HW , & il - > status ) ,
" TX Power requested while scanning! \n " ) )
2011-02-21 11:11:05 -08:00
return - EAGAIN ;
2011-10-24 16:49:25 +02:00
band = il - > band = = IEEE80211_BAND_2GHZ ;
2011-02-21 11:11:05 -08:00
2012-02-03 17:31:37 +01:00
is_ht40 = iw4965_is_ht40_channel ( il - > active . flags ) ;
2011-02-21 11:11:05 -08:00
2012-02-03 17:31:37 +01:00
if ( is_ht40 & & ( il - > active . flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK ) )
2011-02-21 11:11:05 -08:00
ctrl_chan_high = 1 ;
cmd . band = band ;
2012-02-03 17:31:37 +01:00
cmd . channel = il - > active . channel ;
2011-02-21 11:11:05 -08:00
2011-11-15 14:45:59 +01:00
ret =
2012-02-03 17:31:37 +01:00
il4965_fill_txpower_tbl ( il , band , le16_to_cpu ( il - > active . channel ) ,
2011-11-15 14:45:59 +01:00
is_ht40 , ctrl_chan_high , & cmd . tx_power ) ;
2011-02-21 11:11:05 -08:00
if ( ret )
goto out ;
2011-11-15 14:45:59 +01:00
ret = il_send_cmd_pdu ( il , C_TX_PWR_TBL , sizeof ( cmd ) , & cmd ) ;
2011-02-21 11:11:05 -08:00
out :
return ret ;
}
2011-11-15 14:45:59 +01:00
static int
2012-02-03 17:31:57 +01:00
il4965_send_rxon_assoc ( struct il_priv * il )
2011-02-21 11:11:05 -08:00
{
int ret = 0 ;
2011-10-24 15:41:30 +02:00
struct il4965_rxon_assoc_cmd rxon_assoc ;
2012-02-03 17:31:37 +01:00
const struct il_rxon_cmd * rxon1 = & il - > staging ;
const struct il_rxon_cmd * rxon2 = & il - > active ;
2011-02-21 11:11:05 -08:00
2011-08-26 10:45:16 +02:00
if ( rxon1 - > flags = = rxon2 - > flags & &
rxon1 - > filter_flags = = rxon2 - > filter_flags & &
rxon1 - > cck_basic_rates = = rxon2 - > cck_basic_rates & &
rxon1 - > ofdm_ht_single_stream_basic_rates = =
2011-11-15 14:45:59 +01:00
rxon2 - > ofdm_ht_single_stream_basic_rates & &
2011-08-26 10:45:16 +02:00
rxon1 - > ofdm_ht_dual_stream_basic_rates = =
2011-11-15 14:45:59 +01:00
rxon2 - > ofdm_ht_dual_stream_basic_rates & &
2011-08-26 10:45:16 +02:00
rxon1 - > rx_chain = = rxon2 - > rx_chain & &
rxon1 - > ofdm_basic_rates = = rxon2 - > ofdm_basic_rates ) {
2011-11-15 11:21:01 +01:00
D_INFO ( " Using current RXON_ASSOC. Not resending. \n " ) ;
2011-02-21 11:11:05 -08:00
return 0 ;
}
2012-02-03 17:31:37 +01:00
rxon_assoc . flags = il - > staging . flags ;
rxon_assoc . filter_flags = il - > staging . filter_flags ;
rxon_assoc . ofdm_basic_rates = il - > staging . ofdm_basic_rates ;
rxon_assoc . cck_basic_rates = il - > staging . cck_basic_rates ;
2011-02-21 11:11:05 -08:00
rxon_assoc . reserved = 0 ;
rxon_assoc . ofdm_ht_single_stream_basic_rates =
2012-02-03 17:31:37 +01:00
il - > staging . ofdm_ht_single_stream_basic_rates ;
2011-02-21 11:11:05 -08:00
rxon_assoc . ofdm_ht_dual_stream_basic_rates =
2012-02-03 17:31:37 +01:00
il - > staging . ofdm_ht_dual_stream_basic_rates ;
rxon_assoc . rx_chain_select_flags = il - > staging . rx_chain ;
2011-02-21 11:11:05 -08:00
2011-11-15 14:45:59 +01:00
ret =
il_send_cmd_pdu_async ( il , C_RXON_ASSOC , sizeof ( rxon_assoc ) ,
& rxon_assoc , NULL ) ;
2011-02-21 11:11:05 -08:00
return ret ;
}
2011-11-15 14:45:59 +01:00
static int
2012-02-03 17:31:57 +01:00
il4965_commit_rxon ( struct il_priv * il )
2011-02-21 11:11:05 -08:00
{
/* cast away the const for active_rxon in this function */
2012-02-03 17:31:37 +01:00
struct il_rxon_cmd * active_rxon = ( void * ) & il - > active ;
2011-02-21 11:11:05 -08:00
int ret ;
2012-02-03 17:31:37 +01:00
bool new_assoc = ! ! ( il - > staging . filter_flags & RXON_FILTER_ASSOC_MSK ) ;
2011-02-21 11:11:05 -08:00
2011-10-24 16:49:25 +02:00
if ( ! il_is_alive ( il ) )
2011-02-21 11:11:05 -08:00
return - EBUSY ;
/* always get timestamp with Rx frame */
2012-02-03 17:31:37 +01:00
il - > staging . flags | = RXON_FLG_TSF2HOST_MSK ;
2011-02-21 11:11:05 -08:00
2012-02-03 17:31:57 +01:00
ret = il_check_rxon_cmd ( il ) ;
2011-02-21 11:11:05 -08:00
if ( ret ) {
2011-08-18 22:07:57 +02:00
IL_ERR ( " Invalid RXON configuration. Not committing. \n " ) ;
2011-02-21 11:11:05 -08:00
return - EINVAL ;
}
/*
* receive commit_rxon request
* abort any previous channel switch if still in process
*/
2011-11-15 13:09:01 +01:00
if ( test_bit ( S_CHANNEL_SWITCH_PENDING , & il - > status ) & &
2012-02-03 17:31:37 +01:00
il - > switch_channel ! = il - > staging . channel ) {
2011-11-15 11:21:01 +01:00
D_11H ( " abort channel switch on %d \n " ,
2011-10-24 16:49:25 +02:00
le16_to_cpu ( il - > switch_channel ) ) ;
il_chswitch_done ( il , false ) ;
2011-02-21 11:11:05 -08:00
}
/* If we don't need to send a full RXON, we can use
2011-10-24 15:41:30 +02:00
* il_rxon_assoc_cmd which is used to reconfigure filter
2011-02-21 11:11:05 -08:00
* and other flags for the current radio configuration . */
2012-02-03 17:31:57 +01:00
if ( ! il_full_rxon_required ( il ) ) {
ret = il_send_rxon_assoc ( il ) ;
2011-02-21 11:11:05 -08:00
if ( ret ) {
2011-08-18 22:07:57 +02:00
IL_ERR ( " Error setting RXON_ASSOC (%d) \n " , ret ) ;
2011-02-21 11:11:05 -08:00
return ret ;
}
2012-02-03 17:31:37 +01:00
memcpy ( active_rxon , & il - > staging , sizeof ( * active_rxon ) ) ;
2012-02-03 17:31:57 +01:00
il_print_rx_config_cmd ( il ) ;
2011-07-27 15:37:43 +02:00
/*
* We do not commit tx power settings while channel changing ,
* do it now if tx power changed .
*/
2011-10-24 16:49:25 +02:00
il_set_tx_power ( il , il - > tx_power_next , false ) ;
2011-07-27 15:37:43 +02:00
return 0 ;
2011-02-21 11:11:05 -08:00
}
/* If we are currently associated and the new config requires
* an RXON_ASSOC and the new config wants the associated mask enabled ,
* we must clear the associated from the active configuration
* before we apply the new config */
2012-02-03 17:31:37 +01:00
if ( il_is_associated ( il ) & & new_assoc ) {
2011-11-15 11:21:01 +01:00
D_INFO ( " Toggling associated bit on current RXON \n " ) ;
2011-02-21 11:11:05 -08:00
active_rxon - > filter_flags & = ~ RXON_FILTER_ASSOC_MSK ;
2011-11-15 14:45:59 +01:00
ret =
2012-02-03 17:31:38 +01:00
il_send_cmd_pdu ( il , C_RXON ,
2011-11-15 14:45:59 +01:00
sizeof ( struct il_rxon_cmd ) , active_rxon ) ;
2011-02-21 11:11:05 -08:00
/* If the mask clearing failed then we set
* active_rxon back to what it was previously */
if ( ret ) {
active_rxon - > filter_flags | = RXON_FILTER_ASSOC_MSK ;
2011-08-18 22:07:57 +02:00
IL_ERR ( " Error clearing ASSOC_MSK (%d) \n " , ret ) ;
2011-02-21 11:11:05 -08:00
return ret ;
}
2012-02-03 17:31:57 +01:00
il_clear_ucode_stations ( il ) ;
il_restore_stations ( il ) ;
ret = il4965_restore_default_wep_keys ( il ) ;
2011-02-21 11:11:05 -08:00
if ( ret ) {
2011-08-18 22:07:57 +02:00
IL_ERR ( " Failed to restore WEP keys (%d) \n " , ret ) ;
2011-02-21 11:11:05 -08:00
return ret ;
}
}
2011-11-15 14:45:59 +01:00
D_INFO ( " Sending RXON \n " " * with%s RXON_FILTER_ASSOC_MSK \n "
" * channel = %d \n " " * bssid = %pM \n " , ( new_assoc ? " " : " out " ) ,
2012-02-03 17:31:37 +01:00
le16_to_cpu ( il - > staging . channel ) , il - > staging . bssid_addr ) ;
2011-02-21 11:11:05 -08:00
2012-02-03 17:31:57 +01:00
il_set_rxon_hwcrypto ( il , ! il - > cfg - > mod_params - > sw_crypto ) ;
2011-02-21 11:11:05 -08:00
/* Apply the new configuration
* RXON unassoc clears the station table in uCode so restoration of
* stations is needed after it ( the RXON command ) completes
*/
if ( ! new_assoc ) {
2011-11-15 14:45:59 +01:00
ret =
2012-02-03 17:31:38 +01:00
il_send_cmd_pdu ( il , C_RXON ,
2012-02-03 17:31:37 +01:00
sizeof ( struct il_rxon_cmd ) , & il - > staging ) ;
2011-02-21 11:11:05 -08:00
if ( ret ) {
2011-08-18 22:07:57 +02:00
IL_ERR ( " Error setting new RXON (%d) \n " , ret ) ;
2011-02-21 11:11:05 -08:00
return ret ;
}
2011-11-15 11:21:01 +01:00
D_INFO ( " Return from !new_assoc RXON. \n " ) ;
2012-02-03 17:31:37 +01:00
memcpy ( active_rxon , & il - > staging , sizeof ( * active_rxon ) ) ;
2012-02-03 17:31:57 +01:00
il_clear_ucode_stations ( il ) ;
il_restore_stations ( il ) ;
ret = il4965_restore_default_wep_keys ( il ) ;
2011-02-21 11:11:05 -08:00
if ( ret ) {
2011-08-18 22:07:57 +02:00
IL_ERR ( " Failed to restore WEP keys (%d) \n " , ret ) ;
2011-02-21 11:11:05 -08:00
return ret ;
}
}
if ( new_assoc ) {
2011-10-24 16:49:25 +02:00
il - > start_calib = 0 ;
2011-02-21 11:11:05 -08:00
/* Apply the new configuration
* RXON assoc doesn ' t clear the station table in uCode ,
*/
2011-11-15 14:45:59 +01:00
ret =
2012-02-03 17:31:38 +01:00
il_send_cmd_pdu ( il , C_RXON ,
2012-02-03 17:31:37 +01:00
sizeof ( struct il_rxon_cmd ) , & il - > staging ) ;
2011-02-21 11:11:05 -08:00
if ( ret ) {
2011-08-18 22:07:57 +02:00
IL_ERR ( " Error setting new RXON (%d) \n " , ret ) ;
2011-02-21 11:11:05 -08:00
return ret ;
}
2012-02-03 17:31:37 +01:00
memcpy ( active_rxon , & il - > staging , sizeof ( * active_rxon ) ) ;
2011-02-21 11:11:05 -08:00
}
2012-02-03 17:31:57 +01:00
il_print_rx_config_cmd ( il ) ;
2011-02-21 11:11:05 -08:00
2011-10-24 16:49:25 +02:00
il4965_init_sensitivity ( il ) ;
2011-02-21 11:11:05 -08:00
/* If we issue a new RXON command which required a tune then we must
* send a new TXPOWER command or we won ' t be able to Tx any frames */
2011-10-24 16:49:25 +02:00
ret = il_set_tx_power ( il , il - > tx_power_next , true ) ;
2011-02-21 11:11:05 -08:00
if ( ret ) {
2011-08-18 22:07:57 +02:00
IL_ERR ( " Error sending TX power (%d) \n " , ret ) ;
2011-02-21 11:11:05 -08:00
return ret ;
}
return 0 ;
}
2011-11-15 14:45:59 +01:00
static int
il4965_hw_channel_switch ( struct il_priv * il ,
struct ieee80211_channel_switch * ch_switch )
2011-02-21 11:11:05 -08:00
{
int rc ;
u8 band = 0 ;
bool is_ht40 = false ;
u8 ctrl_chan_high = 0 ;
2011-10-24 15:41:30 +02:00
struct il4965_channel_switch_cmd cmd ;
const struct il_channel_info * ch_info ;
2011-02-21 11:11:05 -08:00
u32 switch_time_in_usec , ucode_switch_time ;
u16 ch ;
u32 tsf_low ;
u8 switch_count ;
2012-02-03 17:31:37 +01:00
u16 beacon_interval = le16_to_cpu ( il - > timing . beacon_interval ) ;
2012-02-03 17:31:57 +01:00
struct ieee80211_vif * vif = il - > vif ;
band = ( il - > band = = IEEE80211_BAND_2GHZ ) ;
if ( WARN_ON_ONCE ( vif = = NULL ) )
return - EIO ;
2011-02-21 11:11:05 -08:00
2012-02-03 17:31:37 +01:00
is_ht40 = iw4965_is_ht40_channel ( il - > staging . flags ) ;
2011-02-21 11:11:05 -08:00
2012-02-03 17:31:37 +01:00
if ( is_ht40 & & ( il - > staging . flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK ) )
2011-02-21 11:11:05 -08:00
ctrl_chan_high = 1 ;
cmd . band = band ;
cmd . expect_beacon = 0 ;
ch = ch_switch - > channel - > hw_value ;
cmd . channel = cpu_to_le16 ( ch ) ;
2012-02-03 17:31:37 +01:00
cmd . rxon_flags = il - > staging . flags ;
cmd . rxon_filter_flags = il - > staging . filter_flags ;
2011-02-21 11:11:05 -08:00
switch_count = ch_switch - > count ;
tsf_low = ch_switch - > timestamp & 0x0ffffffff ;
/*
* calculate the ucode channel switch time
* adding TSF as one of the factor for when to switch
*/
2011-08-26 10:45:16 +02:00
if ( il - > ucode_beacon_time > tsf_low & & beacon_interval ) {
2011-11-15 14:45:59 +01:00
if ( switch_count >
( ( il - > ucode_beacon_time - tsf_low ) / beacon_interval ) ) {
switch_count - =
( il - > ucode_beacon_time - tsf_low ) / beacon_interval ;
2011-02-21 11:11:05 -08:00
} else
switch_count = 0 ;
}
if ( switch_count < = 1 )
2011-10-24 16:49:25 +02:00
cmd . switch_time = cpu_to_le32 ( il - > ucode_beacon_time ) ;
2011-02-21 11:11:05 -08:00
else {
switch_time_in_usec =
2011-11-15 14:45:59 +01:00
vif - > bss_conf . beacon_int * switch_count * TIME_UNIT ;
ucode_switch_time =
il_usecs_to_beacons ( il , switch_time_in_usec ,
beacon_interval ) ;
cmd . switch_time =
il_add_beacon_time ( il , il - > ucode_beacon_time ,
ucode_switch_time , beacon_interval ) ;
2011-02-21 11:11:05 -08:00
}
2011-11-15 14:45:59 +01:00
D_11H ( " uCode time for the switch is 0x%x \n " , cmd . switch_time ) ;
2011-10-24 16:49:25 +02:00
ch_info = il_get_channel_info ( il , il - > band , ch ) ;
2011-02-21 11:11:05 -08:00
if ( ch_info )
2011-10-24 15:41:30 +02:00
cmd . expect_beacon = il_is_channel_radar ( ch_info ) ;
2011-02-21 11:11:05 -08:00
else {
2011-08-18 22:07:57 +02:00
IL_ERR ( " invalid channel switch from %u to %u \n " ,
2012-02-03 17:31:37 +01:00
il - > active . channel , ch ) ;
2011-02-21 11:11:05 -08:00
return - EFAULT ;
}
2011-11-15 14:45:59 +01:00
rc = il4965_fill_txpower_tbl ( il , band , ch , is_ht40 , ctrl_chan_high ,
& cmd . tx_power ) ;
2011-02-21 11:11:05 -08:00
if ( rc ) {
2011-11-15 11:21:01 +01:00
D_11H ( " error:%d fill txpower_tbl \n " , rc ) ;
2011-02-21 11:11:05 -08:00
return rc ;
}
2011-11-15 14:45:59 +01:00
return il_send_cmd_pdu ( il , C_CHANNEL_SWITCH , sizeof ( cmd ) , & cmd ) ;
2011-02-21 11:11:05 -08:00
}
/**
2011-10-24 15:41:30 +02:00
* il4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte - count array
2011-02-21 11:11:05 -08:00
*/
2011-11-15 14:45:59 +01:00
static void
il4965_txq_update_byte_cnt_tbl ( struct il_priv * il , struct il_tx_queue * txq ,
u16 byte_cnt )
2011-02-21 11:11:05 -08:00
{
2011-10-24 16:49:25 +02:00
struct il4965_scd_bc_tbl * scd_bc_tbl = il - > scd_bc_tbls . addr ;
2011-02-21 11:11:05 -08:00
int txq_id = txq - > q . id ;
int write_ptr = txq - > q . write_ptr ;
2011-10-24 15:41:30 +02:00
int len = byte_cnt + IL_TX_CRC_SIZE + IL_TX_DELIMITER_SIZE ;
2011-02-21 11:11:05 -08:00
__le16 bc_ent ;
WARN_ON ( len > 0xFFF | | write_ptr > = TFD_QUEUE_SIZE_MAX ) ;
bc_ent = cpu_to_le16 ( len & 0xFFF ) ;
/* Set up byte count within first 256 entries */
scd_bc_tbl [ txq_id ] . tfd_offset [ write_ptr ] = bc_ent ;
/* If within first 64 entries, duplicate at end */
if ( write_ptr < TFD_QUEUE_SIZE_BC_DUP )
2011-11-15 14:45:59 +01:00
scd_bc_tbl [ txq_id ] . tfd_offset [ TFD_QUEUE_SIZE_MAX + write_ptr ] =
bc_ent ;
2011-02-21 11:11:05 -08:00
}
/**
2011-10-24 15:41:30 +02:00
* il4965_hw_get_temperature - return the calibrated temperature ( in Kelvin )
2011-08-26 15:43:47 +02:00
* @ stats : Provides the temperature reading from the uCode
2011-02-21 11:11:05 -08:00
*
2011-08-26 15:43:47 +02:00
* A return of < 0 indicates bogus data in the stats
2011-02-21 11:11:05 -08:00
*/
2011-11-15 14:45:59 +01:00
static int
il4965_hw_get_temperature ( struct il_priv * il )
2011-02-21 11:11:05 -08:00
{
s32 temperature ;
s32 vt ;
s32 R1 , R2 , R3 ;
u32 R4 ;
2011-11-15 13:09:01 +01:00
if ( test_bit ( S_TEMPERATURE , & il - > status ) & &
2011-11-15 14:45:59 +01:00
( il - > _4965 . stats . flag & STATS_REPLY_FLG_HT40_MODE_MSK ) ) {
2011-11-15 11:21:01 +01:00
D_TEMP ( " Running HT40 temperature calibration \n " ) ;
2011-11-15 14:45:59 +01:00
R1 = ( s32 ) le32_to_cpu ( il - > card_alive_init . therm_r1 [ 1 ] ) ;
R2 = ( s32 ) le32_to_cpu ( il - > card_alive_init . therm_r2 [ 1 ] ) ;
R3 = ( s32 ) le32_to_cpu ( il - > card_alive_init . therm_r3 [ 1 ] ) ;
2011-10-24 16:49:25 +02:00
R4 = le32_to_cpu ( il - > card_alive_init . therm_r4 [ 1 ] ) ;
2011-02-21 11:11:05 -08:00
} else {
2011-11-15 11:21:01 +01:00
D_TEMP ( " Running temperature calibration \n " ) ;
2011-11-15 14:45:59 +01:00
R1 = ( s32 ) le32_to_cpu ( il - > card_alive_init . therm_r1 [ 0 ] ) ;
R2 = ( s32 ) le32_to_cpu ( il - > card_alive_init . therm_r2 [ 0 ] ) ;
R3 = ( s32 ) le32_to_cpu ( il - > card_alive_init . therm_r3 [ 0 ] ) ;
2011-10-24 16:49:25 +02:00
R4 = le32_to_cpu ( il - > card_alive_init . therm_r4 [ 0 ] ) ;
2011-02-21 11:11:05 -08:00
}
/*
* Temperature is only 23 bits , so sign extend out to 32.
*
2011-08-26 15:43:47 +02:00
* NOTE If we haven ' t received a stats notification yet
2011-02-21 11:11:05 -08:00
* with an updated temperature , use R4 provided to us in the
* " initialize " ALIVE response .
*/
2011-11-15 13:09:01 +01:00
if ( ! test_bit ( S_TEMPERATURE , & il - > status ) )
2011-02-21 11:11:05 -08:00
vt = sign_extend32 ( R4 , 23 ) ;
else
2011-11-15 14:45:59 +01:00
vt = sign_extend32 ( le32_to_cpu
( il - > _4965 . stats . general . common . temperature ) ,
23 ) ;
2011-02-21 11:11:05 -08:00
2011-11-15 11:21:01 +01:00
D_TEMP ( " Calib values R[1-3]: %d %d %d R4: %d \n " , R1 , R2 , R3 , vt ) ;
2011-02-21 11:11:05 -08:00
if ( R3 = = R1 ) {
2011-08-18 22:07:57 +02:00
IL_ERR ( " Calibration conflict R1 == R3 \n " ) ;
2011-02-21 11:11:05 -08:00
return - 1 ;
}
/* Calculate temperature in degrees Kelvin, adjust by 97%.
* Add offset to center the adjustment around 0 degrees Centigrade . */
temperature = TEMPERATURE_CALIB_A_VAL * ( vt - R2 ) ;
temperature / = ( R3 - R1 ) ;
2011-11-15 14:45:59 +01:00
temperature =
( temperature * 97 ) / 100 + TEMPERATURE_CALIB_KELVIN_OFFSET ;
2011-02-21 11:11:05 -08:00
2011-11-15 14:45:59 +01:00
D_TEMP ( " Calibrated temperature: %dK, %dC \n " , temperature ,
KELVIN_TO_CELSIUS ( temperature ) ) ;
2011-02-21 11:11:05 -08:00
return temperature ;
}
/* Adjust Txpower only if temperature variance is greater than threshold. */
2011-10-24 15:41:30 +02:00
# define IL_TEMPERATURE_THRESHOLD 3
2011-02-21 11:11:05 -08:00
/**
2011-10-24 15:41:30 +02:00
* il4965_is_temp_calib_needed - determines if new calibration is needed
2011-02-21 11:11:05 -08:00
*
* If the temperature changed has changed sufficiently , then a recalibration
* is needed .
*
2011-10-24 16:49:25 +02:00
* Assumes caller will replace il - > last_temperature once calibration
2011-02-21 11:11:05 -08:00
* executed .
*/
2011-11-15 14:45:59 +01:00
static int
il4965_is_temp_calib_needed ( struct il_priv * il )
2011-02-21 11:11:05 -08:00
{
int temp_diff ;
2011-11-15 13:11:50 +01:00
if ( ! test_bit ( S_STATS , & il - > status ) ) {
2011-08-26 15:43:47 +02:00
D_TEMP ( " Temperature not updated -- no stats. \n " ) ;
2011-02-21 11:11:05 -08:00
return 0 ;
}
2011-10-24 16:49:25 +02:00
temp_diff = il - > temperature - il - > last_temperature ;
2011-02-21 11:11:05 -08:00
/* get absolute value */
if ( temp_diff < 0 ) {
2011-11-15 11:21:01 +01:00
D_POWER ( " Getting cooler, delta %d \n " , temp_diff ) ;
2011-02-21 11:11:05 -08:00
temp_diff = - temp_diff ;
} else if ( temp_diff = = 0 )
2011-11-15 11:21:01 +01:00
D_POWER ( " Temperature unchanged \n " ) ;
2011-02-21 11:11:05 -08:00
else
2011-11-15 11:21:01 +01:00
D_POWER ( " Getting warmer, delta %d \n " , temp_diff ) ;
2011-02-21 11:11:05 -08:00
2011-10-24 15:41:30 +02:00
if ( temp_diff < IL_TEMPERATURE_THRESHOLD ) {
2011-11-15 11:21:01 +01:00
D_POWER ( " => thermal txpower calib not needed \n " ) ;
2011-02-21 11:11:05 -08:00
return 0 ;
}
2011-11-15 11:21:01 +01:00
D_POWER ( " => thermal txpower calib needed \n " ) ;
2011-02-21 11:11:05 -08:00
return 1 ;
}
2011-11-15 14:45:59 +01:00
static void
il4965_temperature_calib ( struct il_priv * il )
2011-02-21 11:11:05 -08:00
{
s32 temp ;
2011-10-24 16:49:25 +02:00
temp = il4965_hw_get_temperature ( il ) ;
2011-10-24 15:41:30 +02:00
if ( IL_TX_POWER_TEMPERATURE_OUT_OF_RANGE ( temp ) )
2011-02-21 11:11:05 -08:00
return ;
2011-10-24 16:49:25 +02:00
if ( il - > temperature ! = temp ) {
if ( il - > temperature )
2011-11-15 14:45:59 +01:00
D_TEMP ( " Temperature changed " " from %dC to %dC \n " ,
KELVIN_TO_CELSIUS ( il - > temperature ) ,
KELVIN_TO_CELSIUS ( temp ) ) ;
2011-02-21 11:11:05 -08:00
else
2011-11-15 14:45:59 +01:00
D_TEMP ( " Temperature " " initialized to %dC \n " ,
KELVIN_TO_CELSIUS ( temp ) ) ;
2011-02-21 11:11:05 -08:00
}
2011-10-24 16:49:25 +02:00
il - > temperature = temp ;
2011-11-15 13:09:01 +01:00
set_bit ( S_TEMPERATURE , & il - > status ) ;
2011-02-21 11:11:05 -08:00
2011-10-24 16:49:25 +02:00
if ( ! il - > disable_tx_power_cal & &
2011-11-15 14:45:59 +01:00
unlikely ( ! test_bit ( S_SCANNING , & il - > status ) ) & &
il4965_is_temp_calib_needed ( il ) )
2011-10-24 16:49:25 +02:00
queue_work ( il - > workqueue , & il - > txpower_work ) ;
2011-02-21 11:11:05 -08:00
}
2011-11-15 14:45:59 +01:00
static u16
il4965_get_hcmd_size ( u8 cmd_id , u16 len )
2011-02-21 11:11:05 -08:00
{
switch ( cmd_id ) {
2011-08-30 15:26:35 +02:00
case C_RXON :
2011-10-24 15:41:30 +02:00
return ( u16 ) sizeof ( struct il4965_rxon_cmd ) ;
2011-02-21 11:11:05 -08:00
default :
return len ;
}
}
2011-11-15 14:45:59 +01:00
static u16
il4965_build_addsta_hcmd ( const struct il_addsta_cmd * cmd , u8 * data )
2011-02-21 11:11:05 -08:00
{
2011-10-24 15:41:30 +02:00
struct il4965_addsta_cmd * addsta = ( struct il4965_addsta_cmd * ) data ;
2011-02-21 11:11:05 -08:00
addsta - > mode = cmd - > mode ;
memcpy ( & addsta - > sta , & cmd - > sta , sizeof ( struct sta_id_modify ) ) ;
2011-10-24 15:41:30 +02:00
memcpy ( & addsta - > key , & cmd - > key , sizeof ( struct il4965_keyinfo ) ) ;
2011-02-21 11:11:05 -08:00
addsta - > station_flags = cmd - > station_flags ;
addsta - > station_flags_msk = cmd - > station_flags_msk ;
addsta - > tid_disable_tx = cmd - > tid_disable_tx ;
addsta - > add_immediate_ba_tid = cmd - > add_immediate_ba_tid ;
addsta - > remove_immediate_ba_tid = cmd - > remove_immediate_ba_tid ;
addsta - > add_immediate_ba_ssn = cmd - > add_immediate_ba_ssn ;
addsta - > sleep_tx_count = cmd - > sleep_tx_count ;
addsta - > reserved1 = cpu_to_le16 ( 0 ) ;
addsta - > reserved2 = cpu_to_le16 ( 0 ) ;
2011-11-15 14:45:59 +01:00
return ( u16 ) sizeof ( struct il4965_addsta_cmd ) ;
2011-02-21 11:11:05 -08:00
}
2011-11-15 14:45:59 +01:00
static inline u32
il4965_get_scd_ssn ( struct il4965_tx_resp * tx_resp )
2011-02-21 11:11:05 -08:00
{
return le32_to_cpup ( & tx_resp - > u . status + tx_resp - > frame_count ) & MAX_SN ;
}
2011-11-15 14:45:59 +01:00
static inline u32
il4965_tx_status_to_mac80211 ( u32 status )
2011-08-30 13:58:27 +02:00
{
status & = TX_STATUS_MSK ;
switch ( status ) {
case TX_STATUS_SUCCESS :
case TX_STATUS_DIRECT_DONE :
return IEEE80211_TX_STAT_ACK ;
case TX_STATUS_FAIL_DEST_PS :
return IEEE80211_TX_STAT_TX_FILTERED ;
default :
return 0 ;
}
}
2011-11-15 14:45:59 +01:00
static inline bool
il4965_is_tx_success ( u32 status )
2011-08-30 13:58:27 +02:00
{
status & = TX_STATUS_MSK ;
2011-11-15 14:45:59 +01:00
return ( status = = TX_STATUS_SUCCESS | | status = = TX_STATUS_DIRECT_DONE ) ;
2011-08-30 13:58:27 +02:00
}
2011-02-21 11:11:05 -08:00
/**
2011-10-24 15:41:30 +02:00
* il4965_tx_status_reply_tx - Handle Tx response for frames in aggregation queue
2011-02-21 11:11:05 -08:00
*/
2011-11-15 14:45:59 +01:00
static int
il4965_tx_status_reply_tx ( struct il_priv * il , struct il_ht_agg * agg ,
struct il4965_tx_resp * tx_resp , int txq_id ,
u16 start_idx )
2011-02-21 11:11:05 -08:00
{
u16 status ;
struct agg_tx_status * frame_status = tx_resp - > u . agg_status ;
struct ieee80211_tx_info * info = NULL ;
struct ieee80211_hdr * hdr = NULL ;
u32 rate_n_flags = le32_to_cpu ( tx_resp - > rate_n_flags ) ;
int i , sh , idx ;
u16 seq ;
if ( agg - > wait_for_ba )
2011-11-15 11:21:01 +01:00
D_TX_REPLY ( " got tx response w/o block-ack \n " ) ;
2011-02-21 11:11:05 -08:00
agg - > frame_count = tx_resp - > frame_count ;
agg - > start_idx = start_idx ;
agg - > rate_n_flags = rate_n_flags ;
agg - > bitmap = 0 ;
/* num frames attempted by Tx command */
if ( agg - > frame_count = = 1 ) {
/* Only one frame was attempted; no block-ack will arrive */
status = le16_to_cpu ( frame_status [ 0 ] . status ) ;
idx = start_idx ;
2011-11-15 11:21:01 +01:00
D_TX_REPLY ( " FrameCnt = %d, StartIdx=%d idx=%d \n " ,
2011-11-15 14:45:59 +01:00
agg - > frame_count , agg - > start_idx , idx ) ;
2011-02-21 11:11:05 -08:00
2011-10-24 16:49:25 +02:00
info = IEEE80211_SKB_CB ( il - > txq [ txq_id ] . txb [ idx ] . skb ) ;
2011-02-21 11:11:05 -08:00
info - > status . rates [ 0 ] . count = tx_resp - > failure_frame + 1 ;
info - > flags & = ~ IEEE80211_TX_CTL_AMPDU ;
2011-10-24 15:41:30 +02:00
info - > flags | = il4965_tx_status_to_mac80211 ( status ) ;
2011-10-24 16:49:25 +02:00
il4965_hwrate_to_tx_control ( il , rate_n_flags , info ) ;
2011-02-21 11:11:05 -08:00
2011-11-15 14:45:59 +01:00
D_TX_REPLY ( " 1 Frame 0x%x failure :%d \n " , status & 0xff ,
tx_resp - > failure_frame ) ;
2011-11-15 11:21:01 +01:00
D_TX_REPLY ( " Rate Info rate_n_flags=%x \n " , rate_n_flags ) ;
2011-02-21 11:11:05 -08:00
agg - > wait_for_ba = 0 ;
} else {
/* Two or more frames were attempted; expect block-ack */
u64 bitmap = 0 ;
int start = agg - > start_idx ;
2011-08-26 15:49:28 +02:00
/* Construct bit-map of pending frames within Tx win */
2011-02-21 11:11:05 -08:00
for ( i = 0 ; i < agg - > frame_count ; i + + ) {
u16 sc ;
status = le16_to_cpu ( frame_status [ i ] . status ) ;
2011-11-15 14:45:59 +01:00
seq = le16_to_cpu ( frame_status [ i ] . sequence ) ;
2011-08-26 16:10:40 +02:00
idx = SEQ_TO_IDX ( seq ) ;
2011-02-21 11:11:05 -08:00
txq_id = SEQ_TO_QUEUE ( seq ) ;
2011-11-15 14:45:59 +01:00
if ( status &
( AGG_TX_STATE_FEW_BYTES_MSK |
AGG_TX_STATE_ABORT_MSK ) )
2011-02-21 11:11:05 -08:00
continue ;
2011-11-15 11:21:01 +01:00
D_TX_REPLY ( " FrameCnt = %d, txq_id=%d idx=%d \n " ,
2011-11-15 14:45:59 +01:00
agg - > frame_count , txq_id , idx ) ;
2011-02-21 11:11:05 -08:00
2011-10-24 16:49:25 +02:00
hdr = il_tx_queue_get_hdr ( il , txq_id , idx ) ;
2011-02-21 11:11:05 -08:00
if ( ! hdr ) {
2011-11-15 14:45:59 +01:00
IL_ERR ( " BUG_ON idx doesn't point to valid skb "
" idx=%d, txq_id=%d \n " , idx , txq_id ) ;
2011-02-21 11:11:05 -08:00
return - 1 ;
}
sc = le16_to_cpu ( hdr - > seq_ctrl ) ;
if ( idx ! = ( SEQ_TO_SN ( sc ) & 0xff ) ) {
2011-11-15 14:45:59 +01:00
IL_ERR ( " BUG_ON idx doesn't match seq control "
" idx=%d, seq_idx=%d, seq=%d \n " , idx ,
SEQ_TO_SN ( sc ) , hdr - > seq_ctrl ) ;
2011-02-21 11:11:05 -08:00
return - 1 ;
}
2011-11-15 14:45:59 +01:00
D_TX_REPLY ( " AGG Frame i=%d idx %d seq=%d \n " , i , idx ,
SEQ_TO_SN ( sc ) ) ;
2011-02-21 11:11:05 -08:00
sh = idx - start ;
if ( sh > 64 ) {
sh = ( start - idx ) + 0xff ;
bitmap = bitmap < < sh ;
sh = 0 ;
start = idx ;
} else if ( sh < - 64 )
2011-11-15 14:45:59 +01:00
sh = 0xff - ( start - idx ) ;
2011-02-21 11:11:05 -08:00
else if ( sh < 0 ) {
sh = start - idx ;
start = idx ;
bitmap = bitmap < < sh ;
sh = 0 ;
}
bitmap | = 1ULL < < sh ;
2011-11-15 14:45:59 +01:00
D_TX_REPLY ( " start=%d bitmap=0x%llx \n " , start ,
( unsigned long long ) bitmap ) ;
2011-02-21 11:11:05 -08:00
}
agg - > bitmap = bitmap ;
agg - > start_idx = start ;
2011-11-15 11:21:01 +01:00
D_TX_REPLY ( " Frames %d start_idx=%d bitmap=0x%llx \n " ,
2011-11-15 14:45:59 +01:00
agg - > frame_count , agg - > start_idx ,
( unsigned long long ) agg - > bitmap ) ;
2011-02-21 11:11:05 -08:00
if ( bitmap )
agg - > wait_for_ba = 1 ;
}
return 0 ;
}
2011-11-15 14:45:59 +01:00
static u8
il4965_find_station ( struct il_priv * il , const u8 * addr )
2011-02-21 11:11:05 -08:00
{
int i ;
int start = 0 ;
2011-10-24 15:41:30 +02:00
int ret = IL_INVALID_STATION ;
2011-02-21 11:11:05 -08:00
unsigned long flags ;
2011-10-24 16:49:25 +02:00
if ( ( il - > iw_mode = = NL80211_IFTYPE_ADHOC ) )
2011-10-24 15:41:30 +02:00
start = IL_STA_ID ;
2011-02-21 11:11:05 -08:00
if ( is_broadcast_ether_addr ( addr ) )
2012-02-03 17:31:44 +01:00
return il - > hw_params . bcast_id ;
2011-02-21 11:11:05 -08:00
2011-10-24 16:49:25 +02:00
spin_lock_irqsave ( & il - > sta_lock , flags ) ;
for ( i = start ; i < il - > hw_params . max_stations ; i + + )
if ( il - > stations [ i ] . used & &
2011-11-15 14:45:59 +01:00
( ! compare_ether_addr ( il - > stations [ i ] . sta . sta . addr , addr ) ) ) {
2011-02-21 11:11:05 -08:00
ret = i ;
goto out ;
}
2011-11-15 14:45:59 +01:00
D_ASSOC ( " can not find STA %pM total %d \n " , addr , il - > num_stations ) ;
2011-02-21 11:11:05 -08:00
2011-11-15 14:45:59 +01:00
out :
2011-02-21 11:11:05 -08:00
/*
* It may be possible that more commands interacting with stations
* arrive before we completed processing the adding of
* station
*/
2011-10-24 15:41:30 +02:00
if ( ret ! = IL_INVALID_STATION & &
2011-10-24 16:49:25 +02:00
( ! ( il - > stations [ ret ] . used & IL_STA_UCODE_ACTIVE ) | |
( ( il - > stations [ ret ] . used & IL_STA_UCODE_ACTIVE ) & &
( il - > stations [ ret ] . used & IL_STA_UCODE_INPROGRESS ) ) ) ) {
2011-08-18 22:07:57 +02:00
IL_ERR ( " Requested station info for sta %d before ready. \n " ,
2011-11-15 14:45:59 +01:00
ret ) ;
2011-10-24 15:41:30 +02:00
ret = IL_INVALID_STATION ;
2011-02-21 11:11:05 -08:00
}
2011-10-24 16:49:25 +02:00
spin_unlock_irqrestore ( & il - > sta_lock , flags ) ;
2011-02-21 11:11:05 -08:00
return ret ;
}
2011-11-15 14:45:59 +01:00
static int
il4965_get_ra_sta_id ( struct il_priv * il , struct ieee80211_hdr * hdr )
2011-02-21 11:11:05 -08:00
{
2011-10-24 16:49:25 +02:00
if ( il - > iw_mode = = NL80211_IFTYPE_STATION ) {
2011-10-24 15:41:30 +02:00
return IL_AP_ID ;
2011-02-21 11:11:05 -08:00
} else {
u8 * da = ieee80211_get_DA ( hdr ) ;
2011-10-24 16:49:25 +02:00
return il4965_find_station ( il , da ) ;
2011-02-21 11:11:05 -08:00
}
}
/**
2011-08-30 15:45:31 +02:00
* il4965_hdl_tx - Handle standard ( non - aggregation ) Tx response
2011-02-21 11:11:05 -08:00
*/
2011-11-15 14:45:59 +01:00
static void
il4965_hdl_tx ( struct il_priv * il , struct il_rx_buf * rxb )
2011-02-21 11:11:05 -08:00
{
2011-08-26 14:36:21 +02:00
struct il_rx_pkt * pkt = rxb_addr ( rxb ) ;
2011-02-21 11:11:05 -08:00
u16 sequence = le16_to_cpu ( pkt - > hdr . sequence ) ;
int txq_id = SEQ_TO_QUEUE ( sequence ) ;
2011-11-15 12:30:17 +01:00
int idx = SEQ_TO_IDX ( sequence ) ;
2011-10-24 16:49:25 +02:00
struct il_tx_queue * txq = & il - > txq [ txq_id ] ;
2011-02-21 11:11:05 -08:00
struct ieee80211_hdr * hdr ;
struct ieee80211_tx_info * info ;
2011-10-24 15:41:30 +02:00
struct il4965_tx_resp * tx_resp = ( void * ) & pkt - > u . raw [ 0 ] ;
2011-11-15 14:45:59 +01:00
u32 status = le32_to_cpu ( tx_resp - > u . status ) ;
2011-02-21 11:11:05 -08:00
int uninitialized_var ( tid ) ;
int sta_id ;
int freed ;
u8 * qc = NULL ;
unsigned long flags ;
2011-11-15 12:30:17 +01:00
if ( idx > = txq - > q . n_bd | | il_queue_used ( & txq - > 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 ,
txq - > q . n_bd , txq - > q . write_ptr , txq - > q . read_ptr ) ;
2011-02-21 11:11:05 -08:00
return ;
}
txq - > time_stamp = jiffies ;
info = IEEE80211_SKB_CB ( txq - > txb [ txq - > q . read_ptr ] . skb ) ;
memset ( & info - > status , 0 , sizeof ( info - > status ) ) ;
2011-11-15 12:30:17 +01:00
hdr = il_tx_queue_get_hdr ( il , txq_id , idx ) ;
2011-02-21 11:11:05 -08:00
if ( ieee80211_is_data_qos ( hdr - > frame_control ) ) {
qc = ieee80211_get_qos_ctl ( hdr ) ;
tid = qc [ 0 ] & 0xf ;
}
2011-10-24 16:49:25 +02:00
sta_id = il4965_get_ra_sta_id ( il , hdr ) ;
2011-10-24 15:41:30 +02:00
if ( txq - > sched_retry & & unlikely ( sta_id = = IL_INVALID_STATION ) ) {
2011-08-18 22:07:57 +02:00
IL_ERR ( " Station not known \n " ) ;
2011-02-21 11:11:05 -08:00
return ;
}
2011-10-24 16:49:25 +02:00
spin_lock_irqsave ( & il - > sta_lock , flags ) ;
2011-02-21 11:11:05 -08:00
if ( txq - > sched_retry ) {
2011-10-24 15:41:30 +02:00
const u32 scd_ssn = il4965_get_scd_ssn ( tx_resp ) ;
struct il_ht_agg * agg = NULL ;
2011-02-21 11:11:05 -08:00
WARN_ON ( ! qc ) ;
2011-10-24 16:49:25 +02:00
agg = & il - > stations [ sta_id ] . tid [ tid ] . agg ;
2011-02-21 11:11:05 -08:00
2011-11-15 12:30:17 +01:00
il4965_tx_status_reply_tx ( il , agg , tx_resp , txq_id , idx ) ;
2011-02-21 11:11:05 -08:00
/* check if BAR is needed */
2011-11-15 14:45:59 +01:00
if ( ( tx_resp - > frame_count = = 1 ) & &
! il4965_is_tx_success ( status ) )
2011-02-21 11:11:05 -08:00
info - > flags | = IEEE80211_TX_STAT_AMPDU_NO_BACK ;
if ( txq - > q . read_ptr ! = ( scd_ssn & 0xff ) ) {
2011-11-15 14:45:59 +01:00
idx = il_queue_dec_wrap ( scd_ssn & 0xff , txq - > q . n_bd ) ;
2011-11-15 11:21:01 +01:00
D_TX_REPLY ( " Retry scheduler reclaim scd_ssn "
2011-11-15 14:45:59 +01:00
" %d idx %d \n " , scd_ssn , idx ) ;
2011-11-15 12:30:17 +01:00
freed = il4965_tx_queue_reclaim ( il , txq_id , idx ) ;
2011-02-21 11:11:05 -08:00
if ( qc )
2011-11-15 14:45:59 +01:00
il4965_free_tfds_in_queue ( il , sta_id , tid ,
freed ) ;
2011-02-21 11:11:05 -08:00
2011-10-24 16:49:25 +02:00
if ( il - > mac80211_registered & &
2011-08-26 10:45:16 +02:00
il_queue_space ( & txq - > q ) > txq - > q . low_mark & &
agg - > state ! = IL_EMPTYING_HW_QUEUE_DELBA )
2011-10-24 16:49:25 +02:00
il_wake_queue ( il , txq ) ;
2011-02-21 11:11:05 -08:00
}
} else {
info - > status . rates [ 0 ] . count = tx_resp - > failure_frame + 1 ;
2011-10-24 15:41:30 +02:00
info - > flags | = il4965_tx_status_to_mac80211 ( status ) ;
2011-10-24 16:49:25 +02:00
il4965_hwrate_to_tx_control ( il ,
2011-11-15 14:45:59 +01:00
le32_to_cpu ( tx_resp - > rate_n_flags ) ,
info ) ;
2011-02-21 11:11:05 -08:00
2011-11-15 11:21:01 +01:00
D_TX_REPLY ( " TXQ %d status %s (0x%08x) "
2011-11-15 14:45:59 +01:00
" rate_n_flags 0x%x retries %d \n " , txq_id ,
il4965_get_tx_fail_reason ( status ) , status ,
le32_to_cpu ( tx_resp - > rate_n_flags ) ,
tx_resp - > failure_frame ) ;
2011-02-21 11:11:05 -08:00
2011-11-15 12:30:17 +01:00
freed = il4965_tx_queue_reclaim ( il , txq_id , idx ) ;
2011-10-24 15:41:30 +02:00
if ( qc & & likely ( sta_id ! = IL_INVALID_STATION ) )
2011-10-24 16:49:25 +02:00
il4965_free_tfds_in_queue ( il , sta_id , tid , freed ) ;
2011-10-24 15:41:30 +02:00
else if ( sta_id = = IL_INVALID_STATION )
2011-11-15 11:21:01 +01:00
D_TX_REPLY ( " Station not known \n " ) ;
2011-02-21 11:11:05 -08:00
2011-10-24 16:49:25 +02:00
if ( il - > mac80211_registered & &
2011-08-26 10:45:16 +02:00
il_queue_space ( & txq - > q ) > txq - > q . low_mark )
2011-10-24 16:49:25 +02:00
il_wake_queue ( il , txq ) ;
2011-02-21 11:11:05 -08:00
}
2011-10-24 15:41:30 +02:00
if ( qc & & likely ( sta_id ! = IL_INVALID_STATION ) )
2011-10-24 16:49:25 +02:00
il4965_txq_check_empty ( il , sta_id , tid , txq_id ) ;
2011-02-21 11:11:05 -08:00
2011-10-24 16:49:25 +02:00
il4965_check_abort_status ( il , tx_resp - > frame_count , status ) ;
2011-02-21 11:11:05 -08:00
2011-10-24 16:49:25 +02:00
spin_unlock_irqrestore ( & il - > sta_lock , flags ) ;
2011-02-21 11:11:05 -08:00
}
/* Set up 4965-specific Rx frame reply handlers */
2011-11-15 14:45:59 +01:00
static void
il4965_handler_setup ( struct il_priv * il )
2011-02-21 11:11:05 -08:00
{
/* Legacy Rx frames */
2011-08-30 15:45:31 +02:00
il - > handlers [ N_RX ] = il4965_hdl_rx ;
2011-02-21 11:11:05 -08:00
/* Tx response */
2011-08-30 15:45:31 +02:00
il - > handlers [ C_TX ] = il4965_hdl_tx ;
2011-02-21 11:11:05 -08:00
}
2011-10-24 15:41:30 +02:00
static struct il_hcmd_ops il4965_hcmd = {
. rxon_assoc = il4965_send_rxon_assoc ,
. commit_rxon = il4965_commit_rxon ,
. set_rxon_chain = il4965_set_rxon_chain ,
2011-02-21 11:11:05 -08:00
} ;
2011-11-15 14:45:59 +01:00
static void
il4965_post_scan ( struct il_priv * il )
2011-02-21 11:11:05 -08:00
{
/*
* Since setting the RXON may have been deferred while
* performing the scan , fire one off if needed
*/
2012-02-03 17:31:37 +01:00
if ( memcmp ( & il - > staging , & il - > active , sizeof ( il - > staging ) ) )
2012-02-03 17:31:57 +01:00
il_commit_rxon ( il ) ;
2011-02-21 11:11:05 -08:00
}
2011-11-15 14:45:59 +01:00
static void
il4965_post_associate ( struct il_priv * il )
2011-02-21 11:11:05 -08:00
{
2012-02-03 17:31:57 +01:00
struct ieee80211_vif * vif = il - > vif ;
2011-02-21 11:11:05 -08:00
struct ieee80211_conf * conf = NULL ;
int ret = 0 ;
2011-10-24 16:49:25 +02:00
if ( ! vif | | ! il - > is_open )
2011-02-21 11:11:05 -08:00
return ;
2011-11-15 13:09:01 +01:00
if ( test_bit ( S_EXIT_PENDING , & il - > status ) )
2011-02-21 11:11:05 -08:00
return ;
2011-10-24 16:49:25 +02:00
il_scan_cancel_timeout ( il , 200 ) ;
2011-02-21 11:11:05 -08:00
2011-08-31 11:13:05 +02:00
conf = & il - > hw - > conf ;
2011-02-21 11:11:05 -08:00
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:11:05 -08:00
2012-02-03 17:31:57 +01:00
ret = il_send_rxon_timing ( il ) ;
2011-02-21 11:11:05 -08:00
if ( ret )
2011-11-15 14:45:59 +01:00
IL_WARN ( " RXON timing - " " Attempting to continue. \n " ) ;
2011-02-21 11:11:05 -08:00
2012-02-03 17:31:37 +01:00
il - > staging . filter_flags | = RXON_FILTER_ASSOC_MSK ;
2011-02-21 11:11:05 -08:00
2011-10-24 16:49:25 +02:00
il_set_rxon_ht ( il , & il - > current_ht_config ) ;
2011-02-21 11:11:05 -08:00
2012-02-03 17:31:58 +01:00
if ( il - > ops - > hcmd - > set_rxon_chain )
il - > ops - > hcmd - > set_rxon_chain ( il ) ;
2011-02-21 11:11:05 -08:00
2012-02-03 17:31:37 +01:00
il - > staging . assoc_id = cpu_to_le16 ( vif - > bss_conf . aid ) ;
2011-02-21 11:11:05 -08:00
2011-11-15 14:45:59 +01:00
D_ASSOC ( " assoc id %d beacon interval %d \n " , vif - > bss_conf . aid ,
vif - > bss_conf . beacon_int ) ;
2011-02-21 11:11:05 -08:00
if ( vif - > 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:11:05 -08:00
else
2012-02-03 17:31:37 +01:00
il - > staging . flags & = ~ RXON_FLG_SHORT_PREAMBLE_MSK ;
2011-02-21 11:11:05 -08:00
2012-02-03 17:31:37 +01:00
if ( il - > staging . flags & RXON_FLG_BAND_24G_MSK ) {
2011-02-21 11:11:05 -08:00
if ( 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:11:05 -08:00
else
2012-02-03 17:31:37 +01:00
il - > staging . flags & = ~ RXON_FLG_SHORT_SLOT_MSK ;
2011-02-21 11:11:05 -08:00
}
2012-02-03 17:31:57 +01:00
il_commit_rxon ( il ) ;
2011-02-21 11:11:05 -08:00
2011-11-15 14:45:59 +01:00
D_ASSOC ( " Associated as %d to: %pM \n " , vif - > bss_conf . aid ,
2012-02-03 17:31:37 +01:00
il - > active . bssid_addr ) ;
2011-02-21 11:11:05 -08:00
switch ( vif - > type ) {
case NL80211_IFTYPE_STATION :
break ;
case NL80211_IFTYPE_ADHOC :
2011-10-24 16:49:25 +02:00
il4965_send_beacon_cmd ( il ) ;
2011-02-21 11:11:05 -08:00
break ;
default :
2011-11-15 14:45:59 +01:00
IL_ERR ( " %s Should not be called in %d mode \n " , __func__ ,
vif - > type ) ;
2011-02-21 11:11:05 -08:00
break ;
}
/* the chain noise calibration will enabled PM upon completion
* If chain noise has already been run , then we need to enable
* power management here */
2011-10-24 16:49:25 +02:00
if ( il - > chain_noise_data . state = = IL_CHAIN_NOISE_DONE )
il_power_update_mode ( il , false ) ;
2011-02-21 11:11:05 -08:00
/* Enable Rx differential gain and sensitivity calibrations */
2011-10-24 16:49:25 +02:00
il4965_chain_noise_reset ( il ) ;
il - > start_calib = 1 ;
2011-02-21 11:11:05 -08:00
}
2011-11-15 14:45:59 +01:00
static void
il4965_config_ap ( struct il_priv * il )
2011-02-21 11:11:05 -08:00
{
2012-02-03 17:31:57 +01:00
struct ieee80211_vif * vif = il - > vif ;
2011-02-21 11:11:05 -08:00
int ret = 0 ;
2011-10-24 16:49:25 +02:00
lockdep_assert_held ( & il - > mutex ) ;
2011-02-21 11:11:05 -08:00
2011-11-15 13:09:01 +01:00
if ( test_bit ( S_EXIT_PENDING , & il - > status ) )
2011-02-21 11:11:05 -08:00
return ;
/* The following should be done only at AP bring up */
2012-02-03 17:31:37 +01:00
if ( ! il_is_associated ( il ) ) {
2011-02-21 11:11:05 -08:00
/* RXON - unassoc (to set timing command) */
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:11:05 -08:00
/* RXON Timing */
2012-02-03 17:31:57 +01:00
ret = il_send_rxon_timing ( il ) ;
2011-02-21 11:11:05 -08:00
if ( ret )
2011-08-18 22:07:57 +02:00
IL_WARN ( " RXON timing failed - "
2011-11-15 14:45:59 +01:00
" Attempting to continue. \n " ) ;
2011-02-21 11:11:05 -08:00
/* AP has all antennas */
2011-11-15 14:45:59 +01:00
il - > chain_noise_data . active_chains = il - > hw_params . valid_rx_ant ;
2011-10-24 16:49:25 +02:00
il_set_rxon_ht ( il , & il - > current_ht_config ) ;
2012-02-03 17:31:58 +01:00
if ( il - > ops - > hcmd - > set_rxon_chain )
il - > ops - > hcmd - > set_rxon_chain ( il ) ;
2011-02-21 11:11:05 -08:00
2012-02-03 17:31:37 +01:00
il - > staging . assoc_id = 0 ;
2011-02-21 11:11:05 -08:00
if ( vif - > 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:11:05 -08:00
else
2012-02-03 17:31:37 +01:00
il - > staging . flags & = ~ RXON_FLG_SHORT_PREAMBLE_MSK ;
2011-02-21 11:11:05 -08:00
2012-02-03 17:31:37 +01:00
if ( il - > staging . flags & RXON_FLG_BAND_24G_MSK ) {
2011-02-21 11:11:05 -08:00
if ( 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:11:05 -08:00
else
2012-02-03 17:31:37 +01:00
il - > staging . flags & = ~ RXON_FLG_SHORT_SLOT_MSK ;
2011-02-21 11:11:05 -08:00
}
/* need to send beacon cmd before committing assoc RXON! */
2011-10-24 16:49:25 +02:00
il4965_send_beacon_cmd ( il ) ;
2011-02-21 11:11:05 -08:00
/* restore RXON assoc */
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:11:05 -08:00
}
2011-10-24 16:49:25 +02:00
il4965_send_beacon_cmd ( il ) ;
2011-02-21 11:11:05 -08:00
}
2011-10-24 15:41:30 +02:00
static struct il_hcmd_utils_ops il4965_hcmd_utils = {
. get_hcmd_size = il4965_get_hcmd_size ,
. build_addsta_hcmd = il4965_build_addsta_hcmd ,
. request_scan = il4965_request_scan ,
. post_scan = il4965_post_scan ,
2011-02-21 11:11:05 -08:00
} ;
2011-10-24 15:41:30 +02:00
static struct il_lib_ops il4965_lib = {
. set_hw_params = il4965_hw_set_hw_params ,
. txq_update_byte_cnt_tbl = il4965_txq_update_byte_cnt_tbl ,
. txq_attach_buf_to_tfd = il4965_hw_txq_attach_buf_to_tfd ,
. txq_free_tfd = il4965_hw_txq_free_tfd ,
. txq_init = il4965_hw_tx_queue_init ,
2011-08-30 15:39:42 +02:00
. handler_setup = il4965_handler_setup ,
2011-10-24 15:41:30 +02:00
. is_valid_rtc_data_addr = il4965_hw_valid_rtc_data_addr ,
. init_alive_start = il4965_init_alive_start ,
. load_ucode = il4965_load_bsm ,
. dump_nic_error_log = il4965_dump_nic_error_log ,
. dump_fh = il4965_dump_fh ,
. set_channel_switch = il4965_hw_channel_switch ,
2011-02-21 11:11:05 -08:00
. apm_ops = {
2011-11-15 14:45:59 +01:00
. init = il_apm_init ,
. config = il4965_nic_config ,
} ,
2011-02-21 11:11:05 -08:00
. eeprom_ops = {
2011-11-15 14:45:59 +01:00
. regulatory_bands = {
EEPROM_REGULATORY_BAND_1_CHANNELS ,
EEPROM_REGULATORY_BAND_2_CHANNELS ,
EEPROM_REGULATORY_BAND_3_CHANNELS ,
EEPROM_REGULATORY_BAND_4_CHANNELS ,
EEPROM_REGULATORY_BAND_5_CHANNELS ,
EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS ,
EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS } ,
. acquire_semaphore = il4965_eeprom_acquire_semaphore ,
. release_semaphore = il4965_eeprom_release_semaphore ,
} ,
. send_tx_power = il4965_send_tx_power ,
2011-10-24 15:41:30 +02:00
. update_chain_flags = il4965_update_chain_flags ,
2011-02-21 11:11:05 -08:00
. temp_ops = {
2011-11-15 14:45:59 +01:00
. temperature = il4965_temperature_calib ,
} ,
2011-09-06 19:11:35 -05:00
# ifdef CONFIG_IWLEGACY_DEBUGFS
2011-02-21 11:11:05 -08:00
. debugfs_ops = {
2011-11-15 14:45:59 +01:00
. rx_stats_read = il4965_ucode_rx_stats_read ,
. tx_stats_read = il4965_ucode_tx_stats_read ,
. general_stats_read = il4965_ucode_general_stats_read ,
} ,
2011-09-06 19:11:35 -05:00
# endif
2011-02-21 11:11:05 -08:00
} ;
2011-10-24 15:41:30 +02:00
static const struct il_legacy_ops il4965_legacy_ops = {
. post_associate = il4965_post_associate ,
. config_ap = il4965_config_ap ,
. manage_ibss_station = il4965_manage_ibss_station ,
. update_bcast_stations = il4965_update_bcast_stations ,
2011-02-21 11:11:05 -08:00
} ;
2012-02-03 17:31:58 +01:00
const struct il_ops il4965_ops = {
2011-10-24 15:41:30 +02:00
. lib = & il4965_lib ,
. hcmd = & il4965_hcmd ,
. utils = & il4965_hcmd_utils ,
. led = & il4965_led_ops ,
. legacy = & il4965_legacy_ops ,
2011-02-21 11:11:05 -08:00
} ;
2011-10-24 15:41:30 +02:00
struct il_cfg il4965_cfg = {
2011-02-21 11:11:05 -08:00
. name = " Intel(R) Wireless WiFi Link 4965AGN " ,
2011-11-15 11:25:42 +01:00
. fw_name_pre = IL4965_FW_PRE ,
. ucode_api_max = IL4965_UCODE_API_MAX ,
. ucode_api_min = IL4965_UCODE_API_MIN ,
2011-11-15 14:45:59 +01:00
. sku = IL_SKU_A | IL_SKU_G | IL_SKU_N ,
2011-02-21 11:11:05 -08:00
. valid_tx_ant = ANT_AB ,
. valid_rx_ant = ANT_ABC ,
. eeprom_ver = EEPROM_4965_EEPROM_VERSION ,
. eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION ,
2011-10-24 15:41:30 +02:00
. mod_params = & il4965_mod_params ,
. led_mode = IL_LED_BLINK ,
2011-02-21 11:11:05 -08:00
/*
* Force use of chains B and C for scan RX on 5 GHz band
* because the device has off - channel reception on chain A .
*/
. scan_rx_antennas [ IEEE80211_BAND_5GHZ ] = ANT_BC ,
2012-02-03 17:31:59 +01:00
. eeprom_size = IL4965_EEPROM_IMG_SIZE ,
. num_of_queues = IL49_NUM_QUEUES ,
. num_of_ampdu_queues = IL49_NUM_AMPDU_QUEUES ,
. pll_cfg_val = 0 ,
. set_l0s = true ,
. use_bsm = true ,
. led_compensation = 61 ,
. chain_noise_num_beacons = IL4965_CAL_NUM_BEACONS ,
. wd_timeout = IL_DEF_WD_TIMEOUT ,
. temperature_kelvin = true ,
. ucode_tracing = true ,
. sensitivity_calib_by_driver = true ,
. chain_noise_calib_by_driver = true ,
2011-02-21 11:11:05 -08:00
} ;
/* Module firmware */
2011-11-15 11:25:42 +01:00
MODULE_FIRMWARE ( IL4965_MODULE_FIRMWARE ( IL4965_UCODE_API_MAX ) ) ;