2007-09-25 17:54:57 -07:00
/******************************************************************************
*
2009-01-08 10:20:02 -08:00
* Copyright ( c ) 2003 - 2009 Intel Corporation . All rights reserved .
2007-09-25 17:54:57 -07:00
*
* Portions of this file are derived from the ipw3945 project , as well
* as portions of the ieee80211 subsystem header files .
*
* 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 :
2008-12-09 11:28:58 -08:00
* Intel Linux Wireless < ilw @ linux . intel . com >
2007-09-25 17:54:57 -07:00
* 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/skbuff.h>
# include <linux/netdevice.h>
# include <linux/wireless.h>
# include <linux/firmware.h>
# include <linux/etherdevice.h>
# include <linux/if_arp.h>
# include <net/mac80211.h>
# include <asm/div64.h>
2008-12-19 10:37:09 +08:00
# define DRV_NAME "iwlagn"
2008-03-11 16:17:18 -07:00
# include "iwl-eeprom.h"
2008-04-24 11:55:38 -07:00
# include "iwl-dev.h"
2008-04-03 16:05:21 -07:00
# include "iwl-core.h"
2008-03-25 16:33:37 -07:00
# include "iwl-io.h"
2007-09-25 17:54:57 -07:00
# include "iwl-helpers.h"
2008-04-14 21:16:06 -07:00
# include "iwl-sta.h"
2008-04-16 16:34:47 -07:00
# include "iwl-calib.h"
2007-09-25 17:54:57 -07:00
2007-10-25 17:15:49 +08:00
2007-09-25 17:54:57 -07:00
/******************************************************************************
*
* module boiler plate
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* module name , copyright , version , etc .
*/
2008-07-18 13:53:02 +08:00
# define DRV_DESCRIPTION "Intel(R) Wireless WiFi Link AGN driver for Linux"
2007-09-25 17:54:57 -07:00
2008-03-12 16:58:49 -07:00
# ifdef CONFIG_IWLWIFI_DEBUG
2007-09-25 17:54:57 -07:00
# define VD "d"
# else
# define VD
# endif
2009-02-13 11:51:19 -08:00
# ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
2007-09-25 17:54:57 -07:00
# define VS "s"
# else
# define VS
# endif
2008-03-06 10:40:19 -08:00
# define DRV_VERSION IWLWIFI_VERSION VD VS
2007-09-25 17:54:57 -07:00
MODULE_DESCRIPTION ( DRV_DESCRIPTION ) ;
MODULE_VERSION ( DRV_VERSION ) ;
2008-12-11 10:33:41 -08:00
MODULE_AUTHOR ( DRV_COPYRIGHT " " DRV_AUTHOR ) ;
2007-09-25 17:54:57 -07:00
MODULE_LICENSE ( " GPL " ) ;
2008-07-21 18:54:42 +03:00
MODULE_ALIAS ( " iwl4965 " ) ;
2007-09-25 17:54:57 -07:00
/*************** STATION TABLE MANAGEMENT ****
2007-11-29 11:09:47 +08:00
* mac80211 should be examined to determine if sta_info is duplicating
2007-09-25 17:54:57 -07:00
* the functionality provided here
*/
/**************************************************************/
/**
2008-10-29 14:05:46 -07:00
* iwl_commit_rxon - commit staging_rxon to hardware
2007-09-25 17:54:57 -07:00
*
2007-10-25 17:15:22 +08:00
* The RXON command in staging_rxon is committed to the hardware and
2007-09-25 17:54:57 -07:00
* the active_rxon structure is updated with the new data . This
* function correctly transitions out of the RXON_ASSOC_MSK state if
* a HW tune is required based on the RXON structure changes .
*/
2009-04-08 11:26:37 -07:00
int iwl_commit_rxon ( struct iwl_priv * priv )
2007-09-25 17:54:57 -07:00
{
/* cast away the const for active_rxon in this function */
2008-05-15 13:53:59 +08:00
struct iwl_rxon_cmd * active_rxon = ( void * ) & priv - > active_rxon ;
2008-06-30 17:23:06 +08:00
int ret ;
bool new_assoc =
! ! ( priv - > staging_rxon . filter_flags & RXON_FILTER_ASSOC_MSK ) ;
2007-09-25 17:54:57 -07:00
2008-04-03 16:05:21 -07:00
if ( ! iwl_is_alive ( priv ) )
2008-06-30 17:23:06 +08:00
return - EBUSY ;
2007-09-25 17:54:57 -07:00
/* always get timestamp with Rx frame */
priv - > staging_rxon . flags | = RXON_FLG_TSF2HOST_MSK ;
2008-07-11 11:53:31 +08:00
/* allow CTS-to-self if possible. this is relevant only for
* 5000 , but will not damage 4965 */
priv - > staging_rxon . flags | = RXON_FLG_SELF_CTS_EN ;
2007-09-25 17:54:57 -07:00
2009-01-27 14:27:52 -08:00
ret = iwl_check_rxon_cmd ( priv ) ;
2008-06-30 17:23:06 +08:00
if ( ret ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " Invalid RXON configuration. Not committing. \n " ) ;
2007-09-25 17:54:57 -07:00
return - EINVAL ;
}
/* If we don't need to send a full RXON, we can use
2008-10-29 14:05:46 -07:00
* iwl_rxon_assoc_cmd which is used to reconfigure filter
2007-09-25 17:54:57 -07:00
* and other flags for the current radio configuration . */
2008-09-03 11:18:44 +08:00
if ( ! iwl_full_rxon_required ( priv ) ) {
2008-06-30 17:23:06 +08:00
ret = iwl_send_rxon_assoc ( priv ) ;
if ( ret ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " Error setting RXON_ASSOC (%d) \n " , ret ) ;
2008-06-30 17:23:06 +08:00
return ret ;
2007-09-25 17:54:57 -07:00
}
memcpy ( active_rxon , & priv - > staging_rxon , sizeof ( * active_rxon ) ) ;
return 0 ;
}
/* station table will be cleared */
priv - > assoc_station_added = 0 ;
/* 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 */
2008-06-30 17:23:06 +08:00
if ( iwl_is_associated ( priv ) & & new_assoc ) {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " Toggling associated bit on current RXON \n " ) ;
2007-09-25 17:54:57 -07:00
active_rxon - > filter_flags & = ~ RXON_FILTER_ASSOC_MSK ;
2008-06-30 17:23:06 +08:00
ret = iwl_send_cmd_pdu ( priv , REPLY_RXON ,
2008-05-15 13:53:59 +08:00
sizeof ( struct iwl_rxon_cmd ) ,
2007-09-25 17:54:57 -07:00
& priv - > active_rxon ) ;
/* If the mask clearing failed then we set
* active_rxon back to what it was previously */
2008-06-30 17:23:06 +08:00
if ( ret ) {
2007-09-25 17:54:57 -07:00
active_rxon - > filter_flags | = RXON_FILTER_ASSOC_MSK ;
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " Error clearing ASSOC_MSK (%d) \n " , ret ) ;
2008-06-30 17:23:06 +08:00
return ret ;
2007-09-25 17:54:57 -07:00
}
}
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " Sending RXON \n "
2007-09-25 17:54:57 -07:00
" * with%s RXON_FILTER_ASSOC_MSK \n "
" * channel = %d \n "
2008-10-27 15:59:26 -07:00
" * bssid = %pM \n " ,
2008-06-30 17:23:06 +08:00
( new_assoc ? " " : " out " ) ,
2007-09-25 17:54:57 -07:00
le16_to_cpu ( priv - > staging_rxon . channel ) ,
2008-10-27 15:59:26 -07:00
priv - > staging_rxon . bssid_addr ) ;
2007-09-25 17:54:57 -07:00
2008-10-29 14:05:46 -07:00
iwl_set_rxon_hwcrypto ( priv , ! priv - > hw_params . sw_crypto ) ;
2008-06-30 17:23:06 +08:00
/* Apply the new configuration
* RXON unassoc clears the station table in uCode , send it before
* we add the bcast station . If assoc bit is set , we will send RXON
* after having added the bcast and bssid station .
*/
if ( ! new_assoc ) {
ret = iwl_send_cmd_pdu ( priv , REPLY_RXON ,
2008-05-15 13:53:59 +08:00
sizeof ( struct iwl_rxon_cmd ) , & priv - > staging_rxon ) ;
2008-06-30 17:23:06 +08:00
if ( ret ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " Error setting new RXON (%d) \n " , ret ) ;
2008-06-30 17:23:06 +08:00
return ret ;
}
memcpy ( active_rxon , & priv - > staging_rxon , sizeof ( * active_rxon ) ) ;
2007-09-25 17:54:57 -07:00
}
2009-06-03 11:44:07 -07:00
iwl_clear_stations_table ( priv ) ;
2007-09-27 11:27:33 +08:00
2009-05-08 13:44:36 -07:00
priv - > start_calib = 0 ;
2007-09-25 17:54:57 -07:00
/* Add the broadcast address so we can send broadcast frames */
2008-05-15 13:54:04 +08:00
if ( iwl_rxon_add_station ( priv , iwl_bcast_addr , 0 ) = =
2008-06-30 17:23:06 +08:00
IWL_INVALID_STATION ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " Error adding BROADCAST address for transmit. \n " ) ;
2007-09-25 17:54:57 -07:00
return - EIO ;
}
/* If we have set the ASSOC_MSK and we are in BSS mode then
* add the IWL_AP_ID to the station rate table */
2008-06-30 17:23:14 +08:00
if ( new_assoc ) {
2008-09-11 00:01:58 +02:00
if ( priv - > iw_mode = = NL80211_IFTYPE_STATION ) {
2008-06-30 17:23:14 +08:00
ret = iwl_rxon_add_station ( priv ,
priv - > active_rxon . bssid_addr , 1 ) ;
if ( ret = = IWL_INVALID_STATION ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv ,
" Error adding AP address for TX. \n " ) ;
2008-06-30 17:23:14 +08:00
return - EIO ;
}
priv - > assoc_station_added = 1 ;
if ( priv - > default_wep_key & &
iwl_send_static_wepkey_cmd ( priv , 0 ) )
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv ,
" Could not send WEP static key. \n " ) ;
2007-09-25 17:54:57 -07:00
}
2008-06-30 17:23:06 +08:00
/* Apply the new configuration
* RXON assoc doesn ' t clear the station table in uCode ,
*/
ret = iwl_send_cmd_pdu ( priv , REPLY_RXON ,
sizeof ( struct iwl_rxon_cmd ) , & priv - > staging_rxon ) ;
if ( ret ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " Error setting new RXON (%d) \n " , ret ) ;
2008-06-30 17:23:06 +08:00
return ret ;
}
memcpy ( active_rxon , & priv - > staging_rxon , sizeof ( * active_rxon ) ) ;
2007-09-25 17:54:57 -07:00
}
2008-07-11 11:53:40 +08:00
iwl_init_sensitivity ( priv ) ;
/* 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 */
ret = iwl_set_tx_power ( priv , priv - > tx_power_user_lmt , true ) ;
if ( ret ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " Error sending TX power (%d) \n " , ret ) ;
2008-07-11 11:53:40 +08:00
return ret ;
}
2007-09-25 17:54:57 -07:00
return 0 ;
}
2008-10-29 14:05:46 -07:00
void iwl_update_chain_flags ( struct iwl_priv * priv )
2008-04-21 15:41:51 -07:00
{
2009-04-08 11:26:44 -07:00
if ( priv - > cfg - > ops - > hcmd - > set_rxon_chain )
priv - > cfg - > ops - > hcmd - > set_rxon_chain ( priv ) ;
2009-04-08 11:26:37 -07:00
iwlcore_commit_rxon ( priv ) ;
2008-04-21 15:41:51 -07:00
}
2008-05-15 13:54:01 +08:00
static void iwl_clear_free_frames ( struct iwl_priv * priv )
2007-09-25 17:54:57 -07:00
{
struct list_head * element ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " %d frames on pre-allocated heap on clear. \n " ,
2007-09-25 17:54:57 -07:00
priv - > frames_count ) ;
while ( ! list_empty ( & priv - > free_frames ) ) {
element = priv - > free_frames . next ;
list_del ( element ) ;
2008-05-15 13:54:01 +08:00
kfree ( list_entry ( element , struct iwl_frame , list ) ) ;
2007-09-25 17:54:57 -07:00
priv - > frames_count - - ;
}
if ( priv - > frames_count ) {
2008-12-19 10:37:32 +08:00
IWL_WARN ( priv , " %d frames still in use. Did we lose one? \n " ,
2007-09-25 17:54:57 -07:00
priv - > frames_count ) ;
priv - > frames_count = 0 ;
}
}
2008-05-15 13:54:01 +08:00
static struct iwl_frame * iwl_get_free_frame ( struct iwl_priv * priv )
2007-09-25 17:54:57 -07:00
{
2008-05-15 13:54:01 +08:00
struct iwl_frame * frame ;
2007-09-25 17:54:57 -07:00
struct list_head * element ;
if ( list_empty ( & priv - > free_frames ) ) {
frame = kzalloc ( sizeof ( * frame ) , GFP_KERNEL ) ;
if ( ! frame ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " Could not allocate frame! \n " ) ;
2007-09-25 17:54:57 -07:00
return NULL ;
}
priv - > frames_count + + ;
return frame ;
}
element = priv - > free_frames . next ;
list_del ( element ) ;
2008-05-15 13:54:01 +08:00
return list_entry ( element , struct iwl_frame , list ) ;
2007-09-25 17:54:57 -07:00
}
2008-05-15 13:54:01 +08:00
static void iwl_free_frame ( struct iwl_priv * priv , struct iwl_frame * frame )
2007-09-25 17:54:57 -07:00
{
memset ( frame , 0 , sizeof ( * frame ) ) ;
list_add ( & frame - > list , & priv - > free_frames ) ;
}
2008-07-18 13:53:03 +08:00
static unsigned int iwl_fill_beacon_frame ( struct iwl_priv * priv ,
struct ieee80211_hdr * hdr ,
2008-12-16 09:37:07 +02:00
int left )
2007-09-25 17:54:57 -07:00
{
2008-03-28 16:33:35 -07:00
if ( ! iwl_is_associated ( priv ) | | ! priv - > ibss_beacon | |
2008-09-11 00:01:58 +02:00
( ( priv - > iw_mode ! = NL80211_IFTYPE_ADHOC ) & &
( priv - > iw_mode ! = NL80211_IFTYPE_AP ) ) )
2007-09-25 17:54:57 -07:00
return 0 ;
if ( priv - > ibss_beacon - > len > left )
return 0 ;
memcpy ( hdr , priv - > ibss_beacon - > data , priv - > ibss_beacon - > len ) ;
return priv - > ibss_beacon - > len ;
}
2008-10-29 14:05:46 -07:00
static unsigned int iwl_hw_get_beacon_cmd ( struct iwl_priv * priv ,
2008-07-18 13:53:03 +08:00
struct iwl_frame * frame , u8 rate )
{
struct iwl_tx_beacon_cmd * tx_beacon_cmd ;
unsigned int frame_size ;
tx_beacon_cmd = & frame - > u . beacon ;
memset ( tx_beacon_cmd , 0 , sizeof ( * tx_beacon_cmd ) ) ;
tx_beacon_cmd - > tx . sta_id = priv - > hw_params . bcast_sta_id ;
tx_beacon_cmd - > tx . stop_time . life_time = TX_CMD_LIFE_TIME_INFINITE ;
frame_size = iwl_fill_beacon_frame ( priv , tx_beacon_cmd - > frame ,
sizeof ( frame - > u ) - sizeof ( * tx_beacon_cmd ) ) ;
BUG_ON ( frame_size > MAX_MPDU_SIZE ) ;
tx_beacon_cmd - > tx . len = cpu_to_le16 ( ( u16 ) frame_size ) ;
if ( ( rate = = IWL_RATE_1M_PLCP ) | | ( rate > = IWL_RATE_2M_PLCP ) )
tx_beacon_cmd - > tx . rate_n_flags =
iwl_hw_set_rate_n_flags ( rate , RATE_MCS_CCK_MSK ) ;
else
tx_beacon_cmd - > tx . rate_n_flags =
iwl_hw_set_rate_n_flags ( rate , 0 ) ;
tx_beacon_cmd - > tx . tx_flags = TX_CMD_FLG_SEQ_CTL_MSK |
TX_CMD_FLG_TSF_MSK |
TX_CMD_FLG_STA_RATE_MSK ;
return sizeof ( * tx_beacon_cmd ) + frame_size ;
}
2008-10-29 14:05:46 -07:00
static int iwl_send_beacon_cmd ( struct iwl_priv * priv )
2007-09-25 17:54:57 -07:00
{
2008-05-15 13:54:01 +08:00
struct iwl_frame * frame ;
2007-09-25 17:54:57 -07:00
unsigned int frame_size ;
int rc ;
u8 rate ;
2008-05-15 13:54:01 +08:00
frame = iwl_get_free_frame ( priv ) ;
2007-09-25 17:54:57 -07:00
if ( ! frame ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " Could not obtain free frame buffer for beacon "
2007-09-25 17:54:57 -07:00
" command. \n " ) ;
return - ENOMEM ;
}
2008-10-29 14:05:46 -07:00
rate = iwl_rate_get_lowest_plcp ( priv ) ;
2007-09-25 17:54:57 -07:00
2008-10-29 14:05:46 -07:00
frame_size = iwl_hw_get_beacon_cmd ( priv , frame , rate ) ;
2007-09-25 17:54:57 -07:00
2008-03-21 13:53:44 -07:00
rc = iwl_send_cmd_pdu ( priv , REPLY_TX_BEACON , frame_size ,
2007-09-25 17:54:57 -07:00
& frame - > u . cmd [ 0 ] ) ;
2008-05-15 13:54:01 +08:00
iwl_free_frame ( priv , frame ) ;
2007-09-25 17:54:57 -07:00
return rc ;
}
2009-01-19 15:30:26 -08:00
static inline dma_addr_t iwl_tfd_tb_get_addr ( struct iwl_tfd * tfd , u8 idx )
{
struct iwl_tfd_tb * tb = & tfd - > tbs [ idx ] ;
dma_addr_t addr = get_unaligned_le32 ( & tb - > lo ) ;
if ( sizeof ( dma_addr_t ) > sizeof ( u32 ) )
addr | =
( ( dma_addr_t ) ( le16_to_cpu ( tb - > hi_n_len ) & 0xF ) < < 16 ) < < 16 ;
return addr ;
}
static inline u16 iwl_tfd_tb_get_len ( struct iwl_tfd * tfd , u8 idx )
{
struct iwl_tfd_tb * tb = & tfd - > tbs [ idx ] ;
return le16_to_cpu ( tb - > hi_n_len ) > > 4 ;
}
static inline void iwl_tfd_set_tb ( struct iwl_tfd * tfd , u8 idx ,
dma_addr_t addr , u16 len )
{
struct iwl_tfd_tb * tb = & tfd - > tbs [ idx ] ;
u16 hi_n_len = len < < 4 ;
put_unaligned_le32 ( addr , & tb - > lo ) ;
if ( sizeof ( dma_addr_t ) > sizeof ( u32 ) )
hi_n_len | = ( ( addr > > 16 ) > > 16 ) & 0xF ;
tb - > hi_n_len = cpu_to_le16 ( hi_n_len ) ;
tfd - > num_tbs = idx + 1 ;
}
static inline u8 iwl_tfd_get_num_tbs ( struct iwl_tfd * tfd )
{
return tfd - > num_tbs & 0x1f ;
}
/**
* iwl_hw_txq_free_tfd - Free all chunks referenced by TFD [ txq - > q . read_ptr ]
* @ priv - driver private data
* @ txq - tx queue
*
* Does NOT advance any TFD circular buffer read / write indexes
* Does NOT free the TFD itself ( which is within circular buffer )
*/
void iwl_hw_txq_free_tfd ( struct iwl_priv * priv , struct iwl_tx_queue * txq )
{
2009-01-23 13:45:13 -08:00
struct iwl_tfd * tfd_tmp = ( struct iwl_tfd * ) txq - > tfds ;
2009-01-19 15:30:26 -08:00
struct iwl_tfd * tfd ;
struct pci_dev * dev = priv - > pci_dev ;
int index = txq - > q . read_ptr ;
int i ;
int num_tbs ;
tfd = & tfd_tmp [ index ] ;
/* Sanity check on number of chunks */
num_tbs = iwl_tfd_get_num_tbs ( tfd ) ;
if ( num_tbs > = IWL_NUM_OF_TBS ) {
IWL_ERR ( priv , " Too many chunks: %i \n " , num_tbs ) ;
/* @todo issue fatal error, it is quite serious situation */
return ;
}
/* Unmap tx_cmd */
if ( num_tbs )
pci_unmap_single ( dev ,
pci_unmap_addr ( & txq - > cmd [ index ] - > meta , mapping ) ,
pci_unmap_len ( & txq - > cmd [ index ] - > meta , len ) ,
2009-02-18 15:54:33 -08:00
PCI_DMA_BIDIRECTIONAL ) ;
2009-01-19 15:30:26 -08:00
/* Unmap chunks, if any. */
for ( i = 1 ; i < num_tbs ; i + + ) {
pci_unmap_single ( dev , iwl_tfd_tb_get_addr ( tfd , i ) ,
iwl_tfd_tb_get_len ( tfd , i ) , PCI_DMA_TODEVICE ) ;
if ( txq - > txb ) {
dev_kfree_skb ( txq - > txb [ txq - > q . read_ptr ] . skb [ i - 1 ] ) ;
txq - > txb [ txq - > q . read_ptr ] . skb [ i - 1 ] = NULL ;
}
}
}
int iwl_hw_txq_attach_buf_to_tfd ( struct iwl_priv * priv ,
struct iwl_tx_queue * txq ,
dma_addr_t addr , u16 len ,
u8 reset , u8 pad )
{
struct iwl_queue * q ;
2009-01-23 13:45:13 -08:00
struct iwl_tfd * tfd , * tfd_tmp ;
2009-01-19 15:30:26 -08:00
u32 num_tbs ;
q = & txq - > q ;
2009-01-23 13:45:13 -08:00
tfd_tmp = ( struct iwl_tfd * ) txq - > tfds ;
tfd = & tfd_tmp [ q - > write_ptr ] ;
2009-01-19 15:30:26 -08:00
if ( reset )
memset ( tfd , 0 , sizeof ( * tfd ) ) ;
num_tbs = iwl_tfd_get_num_tbs ( tfd ) ;
/* Each TFD can point to a maximum 20 Tx buffers */
if ( num_tbs > = IWL_NUM_OF_TBS ) {
IWL_ERR ( priv , " Error can not send more than %d chunks \n " ,
IWL_NUM_OF_TBS ) ;
return - EINVAL ;
}
BUG_ON ( addr & ~ DMA_BIT_MASK ( 36 ) ) ;
if ( unlikely ( addr & ~ IWL_TX_DMA_MASK ) )
IWL_ERR ( priv , " Unaligned address = %llx \n " ,
( unsigned long long ) addr ) ;
iwl_tfd_set_tb ( tfd , num_tbs , addr , len ) ;
return 0 ;
}
2009-01-23 13:45:14 -08:00
/*
* Tell nic where to find circular buffer of Tx Frame Descriptors for
* given Tx queue , and enable the DMA channel used for that queue .
*
* 4965 supports up to 16 Tx queues in DRAM , mapped to up to 8 Tx DMA
* channels supported in hardware .
*/
int iwl_hw_tx_queue_init ( struct iwl_priv * priv ,
struct iwl_tx_queue * txq )
{
int txq_id = txq - > q . id ;
/* Circular buffer (TFD queue in DRAM) physical base address */
iwl_write_direct32 ( priv , FH_MEM_CBBC_QUEUE ( txq_id ) ,
txq - > q . dma_addr > > 8 ) ;
return 0 ;
}
2007-09-25 17:54:57 -07:00
/******************************************************************************
*
* Misc . internal state and helper functions
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define MAX_UCODE_BEACON_INTERVAL 4096
2008-10-08 09:37:30 +08:00
static u16 iwl_adjust_beacon_interval ( u16 beacon_val )
2007-09-25 17:54:57 -07:00
{
u16 new_val = 0 ;
u16 beacon_factor = 0 ;
2008-10-08 09:37:30 +08:00
beacon_factor = ( beacon_val + MAX_UCODE_BEACON_INTERVAL )
/ MAX_UCODE_BEACON_INTERVAL ;
2007-09-25 17:54:57 -07:00
new_val = beacon_val / beacon_factor ;
2009-02-20 19:03:31 -05:00
if ( ! new_val )
new_val = MAX_UCODE_BEACON_INTERVAL ;
2008-10-08 09:37:30 +08:00
return new_val ;
2007-09-25 17:54:57 -07:00
}
2008-10-08 09:37:30 +08:00
static void iwl_setup_rxon_timing ( struct iwl_priv * priv )
2007-09-25 17:54:57 -07:00
{
2008-10-08 09:37:30 +08:00
u64 tsf ;
s32 interval_tm , rem ;
2007-09-25 17:54:57 -07:00
unsigned long flags ;
struct ieee80211_conf * conf = NULL ;
u16 beacon_int = 0 ;
conf = ieee80211_get_hw_conf ( priv - > hw ) ;
spin_lock_irqsave ( & priv - > lock , flags ) ;
2008-10-08 09:37:30 +08:00
priv - > rxon_timing . timestamp = cpu_to_le64 ( priv - > timestamp ) ;
2008-07-19 04:41:24 +03:00
priv - > rxon_timing . listen_interval = cpu_to_le16 ( conf - > listen_interval ) ;
2007-09-25 17:54:57 -07:00
2008-09-11 00:01:58 +02:00
if ( priv - > iw_mode = = NL80211_IFTYPE_STATION ) {
2008-10-08 09:37:30 +08:00
beacon_int = iwl_adjust_beacon_interval ( priv - > beacon_int ) ;
2007-09-25 17:54:57 -07:00
priv - > rxon_timing . atim_window = 0 ;
} else {
2009-04-23 16:10:04 +02:00
beacon_int = iwl_adjust_beacon_interval (
priv - > vif - > bss_conf . beacon_int ) ;
2008-10-08 09:37:30 +08:00
2007-09-25 17:54:57 -07:00
/* TODO: we need to get atim_window from upper stack
* for now we set to 0 */
priv - > rxon_timing . atim_window = 0 ;
}
2008-10-08 09:37:30 +08:00
priv - > rxon_timing . beacon_interval = cpu_to_le16 ( beacon_int ) ;
2007-09-25 17:54:57 -07:00
2008-10-08 09:37:30 +08:00
tsf = priv - > timestamp ; /* tsf is modifed by do_div: copy it */
interval_tm = beacon_int * 1024 ;
rem = do_div ( tsf , interval_tm ) ;
priv - > rxon_timing . beacon_init_val = cpu_to_le32 ( interval_tm - rem ) ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_ASSOC ( priv , " beacon interval %d beacon timer %d beacon tim %d \n " ,
2008-10-08 09:37:30 +08:00
le16_to_cpu ( priv - > rxon_timing . beacon_interval ) ,
le32_to_cpu ( priv - > rxon_timing . beacon_init_val ) ,
le16_to_cpu ( priv - > rxon_timing . atim_window ) ) ;
2007-09-25 17:54:57 -07:00
}
/******************************************************************************
*
* Generic RX handler implementations
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-05-29 16:34:55 +08:00
static void iwl_rx_reply_alive ( struct iwl_priv * priv ,
struct iwl_rx_mem_buffer * rxb )
2007-09-25 17:54:57 -07:00
{
2008-05-05 10:22:33 +08:00
struct iwl_rx_packet * pkt = ( struct iwl_rx_packet * ) rxb - > skb - > data ;
2008-05-29 16:34:55 +08:00
struct iwl_alive_resp * palive ;
2007-09-25 17:54:57 -07:00
struct delayed_work * pwork ;
palive = & pkt - > u . alive_frame ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " Alive ucode status 0x%08X revision "
2007-09-25 17:54:57 -07:00
" 0x%01X 0x%01X \n " ,
palive - > is_valid , palive - > ver_type ,
palive - > ver_subtype ) ;
if ( palive - > ver_subtype = = INITIALIZE_SUBTYPE ) {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " Initialization Alive received. \n " ) ;
2007-09-25 17:54:57 -07:00
memcpy ( & priv - > card_alive_init ,
& pkt - > u . alive_frame ,
2008-05-29 16:34:55 +08:00
sizeof ( struct iwl_init_alive_resp ) ) ;
2007-09-25 17:54:57 -07:00
pwork = & priv - > init_alive_start ;
} else {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " Runtime Alive received. \n " ) ;
2007-09-25 17:54:57 -07:00
memcpy ( & priv - > card_alive , & pkt - > u . alive_frame ,
2008-05-29 16:34:55 +08:00
sizeof ( struct iwl_alive_resp ) ) ;
2007-09-25 17:54:57 -07:00
pwork = & priv - > alive_start ;
}
/* We delay the ALIVE response by 5ms to
* give the HW RF Kill time to activate . . . */
if ( palive - > is_valid = = UCODE_VALID_OK )
queue_delayed_work ( priv - > workqueue , pwork ,
msecs_to_jiffies ( 5 ) ) ;
else
2008-12-19 10:37:32 +08:00
IWL_WARN ( priv , " uCode did not respond OK. \n " ) ;
2007-09-25 17:54:57 -07:00
}
2008-10-29 14:05:46 -07:00
static void iwl_bg_beacon_update ( struct work_struct * work )
2007-09-25 17:54:57 -07:00
{
2008-03-12 16:58:50 -07:00
struct iwl_priv * priv =
container_of ( work , struct iwl_priv , beacon_update ) ;
2007-09-25 17:54:57 -07:00
struct sk_buff * beacon ;
/* Pull updated AP beacon from mac80211. will fail if not in AP mode */
2008-05-15 12:55:29 +02:00
beacon = ieee80211_beacon_get ( priv - > hw , priv - > vif ) ;
2007-09-25 17:54:57 -07:00
if ( ! beacon ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " update beacon failed \n " ) ;
2007-09-25 17:54:57 -07:00
return ;
}
mutex_lock ( & priv - > mutex ) ;
/* new beacon skb is allocated every time; dispose previous.*/
if ( priv - > ibss_beacon )
dev_kfree_skb ( priv - > ibss_beacon ) ;
priv - > ibss_beacon = beacon ;
mutex_unlock ( & priv - > mutex ) ;
2008-10-29 14:05:46 -07:00
iwl_send_beacon_cmd ( priv ) ;
2007-09-25 17:54:57 -07:00
}
2008-06-12 09:46:53 +08:00
/**
2008-10-29 14:05:46 -07:00
* iwl_bg_statistics_periodic - Timer callback to queue statistics
2008-06-12 09:46:53 +08:00
*
* This callback is provided in order to send a statistics request .
*
* This timer function is continually reset to execute within
* REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION
* was received . We need to ensure we receive the statistics in order
* to update the temperature used for calibrating the TXPOWER .
*/
2008-10-29 14:05:46 -07:00
static void iwl_bg_statistics_periodic ( unsigned long data )
2008-06-12 09:46:53 +08:00
{
struct iwl_priv * priv = ( struct iwl_priv * ) data ;
if ( test_bit ( STATUS_EXIT_PENDING , & priv - > status ) )
return ;
2008-10-29 14:05:49 -07:00
/* dont send host command if rf-kill is on */
if ( ! iwl_is_ready_rf ( priv ) )
return ;
2008-06-12 09:46:53 +08:00
iwl_send_statistics_request ( priv , CMD_ASYNC ) ;
}
2008-10-29 14:05:46 -07:00
static void iwl_rx_beacon_notif ( struct iwl_priv * priv ,
2008-05-05 10:22:28 +08:00
struct iwl_rx_mem_buffer * rxb )
2007-09-25 17:54:57 -07:00
{
2008-03-12 16:58:49 -07:00
# ifdef CONFIG_IWLWIFI_DEBUG
2008-05-05 10:22:33 +08:00
struct iwl_rx_packet * pkt = ( struct iwl_rx_packet * ) rxb - > skb - > data ;
2008-12-11 10:33:40 -08:00
struct iwl4965_beacon_notif * beacon =
( struct iwl4965_beacon_notif * ) pkt - > u . raw ;
2008-06-12 09:47:11 +08:00
u8 rate = iwl_hw_get_rate ( beacon - > beacon_notify_hdr . rate_n_flags ) ;
2007-09-25 17:54:57 -07:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RX ( priv , " beacon status %x retries %d iss %d "
2007-09-25 17:54:57 -07:00
" tsf %d %d rate %d \n " ,
2008-06-12 09:47:07 +08:00
le32_to_cpu ( beacon - > beacon_notify_hdr . u . status ) & TX_STATUS_MSK ,
2007-09-25 17:54:57 -07:00
beacon - > beacon_notify_hdr . failure_frame ,
le32_to_cpu ( beacon - > ibss_mgr_status ) ,
le32_to_cpu ( beacon - > high_tsf ) ,
le32_to_cpu ( beacon - > low_tsf ) , rate ) ;
# endif
2008-09-11 00:01:58 +02:00
if ( ( priv - > iw_mode = = NL80211_IFTYPE_AP ) & &
2007-09-25 17:54:57 -07:00
( ! test_bit ( STATUS_EXIT_PENDING , & priv - > status ) ) )
queue_work ( priv - > workqueue , & priv - > beacon_update ) ;
}
/* Handle notification from uCode that card's power state is changing
* due to software , hardware , or critical temperature RFKILL */
2008-10-29 14:05:46 -07:00
static void iwl_rx_card_state_notif ( struct iwl_priv * priv ,
2008-05-05 10:22:28 +08:00
struct iwl_rx_mem_buffer * rxb )
2007-09-25 17:54:57 -07:00
{
2008-05-05 10:22:33 +08:00
struct iwl_rx_packet * pkt = ( struct iwl_rx_packet * ) rxb - > skb - > data ;
2007-09-25 17:54:57 -07:00
u32 flags = le32_to_cpu ( pkt - > u . card_state_notif . flags ) ;
unsigned long status = priv - > status ;
2009-05-22 11:01:47 -07:00
unsigned long reg_flags ;
2007-09-25 17:54:57 -07:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RF_KILL ( priv , " Card state received: HW:%s SW:%s \n " ,
2007-09-25 17:54:57 -07:00
( flags & HW_CARD_DISABLED ) ? " Kill " : " On " ,
( flags & SW_CARD_DISABLED ) ? " Kill " : " On " ) ;
if ( flags & ( SW_CARD_DISABLED | HW_CARD_DISABLED |
RF_CARD_DISABLED ) ) {
2008-03-25 16:33:37 -07:00
iwl_write32 ( priv , CSR_UCODE_DRV_GP1_SET ,
2007-09-25 17:54:57 -07:00
CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED ) ;
2009-05-22 11:01:47 -07:00
iwl_write_direct32 ( priv , HBUS_TARG_MBX_C ,
HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED ) ;
2007-09-25 17:54:57 -07:00
if ( ! ( flags & RXON_CARD_DISABLED ) ) {
2008-03-25 16:33:37 -07:00
iwl_write32 ( priv , CSR_UCODE_DRV_GP1_CLR ,
2007-09-25 17:54:57 -07:00
CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED ) ;
2009-05-22 11:01:47 -07:00
iwl_write_direct32 ( priv , HBUS_TARG_MBX_C ,
2007-09-25 17:54:57 -07:00
HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED ) ;
}
if ( flags & RF_CARD_DISABLED ) {
2008-03-25 16:33:37 -07:00
iwl_write32 ( priv , CSR_UCODE_DRV_GP1_SET ,
2007-09-25 17:54:57 -07:00
CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT ) ;
2008-03-25 16:33:37 -07:00
iwl_read32 ( priv , CSR_UCODE_DRV_GP1 ) ;
2009-05-22 11:01:47 -07:00
spin_lock_irqsave ( & priv - > reg_lock , reg_flags ) ;
2008-03-25 16:33:37 -07:00
if ( ! iwl_grab_nic_access ( priv ) )
iwl_release_nic_access ( priv ) ;
2009-05-22 11:01:47 -07:00
spin_unlock_irqrestore ( & priv - > reg_lock , reg_flags ) ;
2007-09-25 17:54:57 -07:00
}
}
if ( flags & HW_CARD_DISABLED )
set_bit ( STATUS_RF_KILL_HW , & priv - > status ) ;
else
clear_bit ( STATUS_RF_KILL_HW , & priv - > status ) ;
if ( ! ( flags & RXON_CARD_DISABLED ) )
2008-06-12 09:47:10 +08:00
iwl_scan_cancel ( priv ) ;
2007-09-25 17:54:57 -07:00
if ( ( test_bit ( STATUS_RF_KILL_HW , & status ) ! =
2009-06-04 18:26:06 +02:00
test_bit ( STATUS_RF_KILL_HW , & priv - > status ) ) )
wiphy_rfkill_set_hw_state ( priv - > hw - > wiphy ,
test_bit ( STATUS_RF_KILL_HW , & priv - > status ) ) ;
2007-09-25 17:54:57 -07:00
else
wake_up_interruptible ( & priv - > wait_command_queue ) ;
}
2008-10-29 14:05:46 -07:00
int iwl_set_pwr_src ( struct iwl_priv * priv , enum iwl_pwr_src src )
2008-07-18 13:53:04 +08:00
{
if ( src = = IWL_PWR_SRC_VAUX ) {
2009-02-10 15:19:02 -08:00
if ( pci_pme_capable ( priv - > pci_dev , PCI_D3cold ) )
2008-07-18 13:53:04 +08:00
iwl_set_bits_mask_prph ( priv , APMG_PS_CTRL_REG ,
APMG_PS_CTRL_VAL_PWR_SRC_VAUX ,
~ APMG_PS_CTRL_MSK_PWR_SRC ) ;
} else {
iwl_set_bits_mask_prph ( priv , APMG_PS_CTRL_REG ,
APMG_PS_CTRL_VAL_PWR_SRC_VMAIN ,
~ APMG_PS_CTRL_MSK_PWR_SRC ) ;
}
2009-05-22 11:01:47 -07:00
return 0 ;
2008-07-18 13:53:04 +08:00
}
2007-09-25 17:54:57 -07:00
/**
2008-10-29 14:05:46 -07:00
* iwl_setup_rx_handlers - Initialize Rx handler callbacks
2007-09-25 17:54:57 -07:00
*
* Setup the RX handlers for each of the reply types sent from the uCode
* to the host .
*
* This function chains into the hardware specific files for them to setup
* any hardware specific handlers as well .
*/
2008-06-30 17:23:11 +08:00
static void iwl_setup_rx_handlers ( struct iwl_priv * priv )
2007-09-25 17:54:57 -07:00
{
2008-05-29 16:34:55 +08:00
priv - > rx_handlers [ REPLY_ALIVE ] = iwl_rx_reply_alive ;
2008-10-29 14:05:46 -07:00
priv - > rx_handlers [ REPLY_ERROR ] = iwl_rx_reply_error ;
priv - > rx_handlers [ CHANNEL_SWITCH_NOTIFICATION ] = iwl_rx_csa ;
priv - > rx_handlers [ PM_SLEEP_NOTIFICATION ] = iwl_rx_pm_sleep_notif ;
2007-09-25 17:54:57 -07:00
priv - > rx_handlers [ PM_DEBUG_STATISTIC_NOTIFIC ] =
2008-10-29 14:05:46 -07:00
iwl_rx_pm_debug_statistics_notif ;
priv - > rx_handlers [ BEACON_NOTIFICATION ] = iwl_rx_beacon_notif ;
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:47 +08:00
/*
* The same handler is used for both the REPLY to a discrete
* statistics request from the host as well as for the periodic
* statistics notifications ( after received beacons ) from the uCode .
2007-09-25 17:54:57 -07:00
*/
2008-06-30 17:23:07 +08:00
priv - > rx_handlers [ REPLY_STATISTICS_CMD ] = iwl_rx_statistics ;
priv - > rx_handlers [ STATISTICS_NOTIFICATION ] = iwl_rx_statistics ;
2008-06-12 09:47:10 +08:00
2008-11-07 09:58:41 -08:00
iwl_setup_spectrum_handlers ( priv ) ;
2008-06-12 09:47:10 +08:00
iwl_setup_rx_scan_handlers ( priv ) ;
2008-05-29 16:35:18 +08:00
/* status change handler */
2008-10-29 14:05:46 -07:00
priv - > rx_handlers [ CARD_STATE_NOTIFICATION ] = iwl_rx_card_state_notif ;
2007-09-25 17:54:57 -07:00
2008-05-29 16:35:04 +08:00
priv - > rx_handlers [ MISSED_BEACONS_NOTIFICATION ] =
iwl_rx_missed_beacon_notif ;
2008-05-29 16:35:18 +08:00
/* Rx handlers */
2008-06-30 17:23:09 +08:00
priv - > rx_handlers [ REPLY_RX_PHY_CMD ] = iwl_rx_reply_rx_phy ;
priv - > rx_handlers [ REPLY_RX_MPDU_CMD ] = iwl_rx_reply_rx ;
2008-06-30 17:23:11 +08:00
/* block ack */
priv - > rx_handlers [ REPLY_COMPRESSED_BA ] = iwl_rx_reply_compressed_ba ;
2007-11-29 11:09:47 +08:00
/* Set up hardware specific Rx handlers */
2008-04-24 11:55:20 -07:00
priv - > cfg - > ops - > lib - > rx_handler_setup ( priv ) ;
2007-09-25 17:54:57 -07:00
}
/**
2008-05-05 10:22:28 +08:00
* iwl_rx_handle - Main entry function for receiving responses from uCode
2007-09-25 17:54:57 -07:00
*
* Uses the priv - > rx_handlers callback function array to invoke
* the appropriate handlers , including command responses ,
* frame - received notifications , and other notifications .
*/
2008-05-05 10:22:28 +08:00
void iwl_rx_handle ( struct iwl_priv * priv )
2007-09-25 17:54:57 -07:00
{
2008-05-05 10:22:28 +08:00
struct iwl_rx_mem_buffer * rxb ;
2008-05-05 10:22:33 +08:00
struct iwl_rx_packet * pkt ;
2008-05-05 10:22:28 +08:00
struct iwl_rx_queue * rxq = & priv - > rxq ;
2007-09-25 17:54:57 -07:00
u32 r , i ;
int reclaim ;
unsigned long flags ;
2007-11-29 11:10:14 +08:00
u8 fill_rx = 0 ;
2008-02-07 13:16:33 -08:00
u32 count = 8 ;
2009-05-22 11:01:51 -07:00
int total_empty ;
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:55 +08:00
/* uCode's read index (stored in shared DRAM) indicates the last Rx
* buffer that the driver may process ( last buffer filled by ucode ) . */
2008-11-07 09:58:39 -08:00
r = le16_to_cpu ( rxq - > rb_stts - > closed_rb_num ) & 0x0FFF ;
2007-09-25 17:54:57 -07:00
i = rxq - > read ;
/* Rx interrupt, but nothing sent from uCode */
if ( i = = r )
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RX ( priv , " r = %d, i = %d \n " , r , i ) ;
2007-09-25 17:54:57 -07:00
2009-05-22 11:01:51 -07:00
/* calculate total frames need to be restock after handling RX */
total_empty = r - priv - > rxq . write_actual ;
if ( total_empty < 0 )
total_empty + = RX_QUEUE_SIZE ;
if ( total_empty > ( RX_QUEUE_SIZE / 2 ) )
2007-11-29 11:10:14 +08:00
fill_rx = 1 ;
2007-09-25 17:54:57 -07:00
while ( i ! = r ) {
rxb = rxq - > queue [ i ] ;
2007-11-29 11:09:47 +08:00
/* If an RXB doesn't have a Rx queue slot associated with it,
2007-09-25 17:54:57 -07:00
* then a bug has been introduced in the queue refilling
* routines - - catch it here */
BUG_ON ( rxb = = NULL ) ;
rxq - > queue [ i ] = NULL ;
2009-04-21 10:55:48 -07:00
pci_unmap_single ( priv - > pci_dev , rxb - > real_dma_addr ,
priv - > hw_params . rx_buf_size + 256 ,
PCI_DMA_FROMDEVICE ) ;
2008-05-05 10:22:33 +08:00
pkt = ( struct iwl_rx_packet * ) rxb - > skb - > data ;
2007-09-25 17:54:57 -07:00
/* Reclaim a command buffer only if this packet is a response
* to a ( driver - originated ) command .
* If the packet ( e . g . Rx frame ) originated from uCode ,
* there is no command buffer to reclaim .
* Ucode should set SEQ_RX_FRAME bit if ucode - originated ,
* but apparently a few don ' t get set ; catch them here . */
reclaim = ! ( pkt - > hdr . sequence & SEQ_RX_FRAME ) & &
( pkt - > hdr . cmd ! = REPLY_RX_PHY_CMD ) & &
2008-03-21 13:53:44 -07:00
( pkt - > hdr . cmd ! = REPLY_RX ) & &
2008-10-23 23:48:58 -07:00
( pkt - > hdr . cmd ! = REPLY_RX_MPDU_CMD ) & &
2007-09-27 11:27:31 +08:00
( pkt - > hdr . cmd ! = REPLY_COMPRESSED_BA ) & &
2007-09-25 17:54:57 -07:00
( pkt - > hdr . cmd ! = STATISTICS_NOTIFICATION ) & &
( pkt - > hdr . cmd ! = REPLY_TX ) ;
/* Based on type of command response or notification,
* handle those that need handling via function in
2008-10-29 14:05:46 -07:00
* rx_handlers table . See iwl_setup_rx_handlers ( ) */
2007-09-25 17:54:57 -07:00
if ( priv - > rx_handlers [ pkt - > hdr . cmd ] ) {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RX ( priv , " r = %d, i = %d, %s, 0x%02x \n " , r ,
2008-05-06 11:05:12 +08:00
i , get_cmd_string ( pkt - > hdr . cmd ) , pkt - > hdr . cmd ) ;
2007-09-25 17:54:57 -07:00
priv - > rx_handlers [ pkt - > hdr . cmd ] ( priv , rxb ) ;
2009-04-08 11:39:32 -07:00
priv - > isr_stats . rx_handlers [ pkt - > hdr . cmd ] + + ;
2007-09-25 17:54:57 -07:00
} else {
/* No handling needed */
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RX ( priv ,
2007-09-25 17:54:57 -07:00
" r %d i %d No handler needed for %s, 0x%02x \n " ,
r , i , get_cmd_string ( pkt - > hdr . cmd ) ,
pkt - > hdr . cmd ) ;
}
if ( reclaim ) {
2007-11-29 11:09:47 +08:00
/* Invoke any callbacks, transfer the skb to caller, and
2008-03-21 13:53:44 -07:00
* fire off the ( possibly ) blocking iwl_send_cmd ( )
2007-09-25 17:54:57 -07:00
* as we reclaim the driver command queue */
if ( rxb & & rxb - > skb )
2008-05-29 16:35:12 +08:00
iwl_tx_cmd_complete ( priv , rxb ) ;
2007-09-25 17:54:57 -07:00
else
2008-12-19 10:37:32 +08:00
IWL_WARN ( priv , " Claim null rxb? \n " ) ;
2007-09-25 17:54:57 -07:00
}
/* For now we just don't re-use anything. We can tweak this
* later to try and re - use notification packets and SKBs that
* fail to Rx correctly */
if ( rxb - > skb ! = NULL ) {
priv - > alloc_rxb_skb - - ;
dev_kfree_skb_any ( rxb - > skb ) ;
rxb - > skb = NULL ;
}
spin_lock_irqsave ( & rxq - > lock , flags ) ;
list_add_tail ( & rxb - > list , & priv - > rxq . rx_used ) ;
spin_unlock_irqrestore ( & rxq - > lock , flags ) ;
i = ( i + 1 ) & RX_QUEUE_MASK ;
2007-11-29 11:10:14 +08:00
/* If there are a lot of unused frames,
* restock the Rx queue so ucode wont assert . */
if ( fill_rx ) {
count + + ;
if ( count > = 8 ) {
priv - > rxq . read = i ;
2009-05-22 11:01:51 -07:00
iwl_rx_replenish_now ( priv ) ;
2007-11-29 11:10:14 +08:00
count = 0 ;
}
}
2007-09-25 17:54:57 -07:00
}
/* Backtrack one entry */
priv - > rxq . read = i ;
2009-05-22 11:01:51 -07:00
if ( fill_rx )
iwl_rx_replenish_now ( priv ) ;
else
iwl_rx_queue_restock ( priv ) ;
2008-05-05 10:22:28 +08:00
}
2008-03-28 16:21:08 -07:00
/* call this function to flush any scheduled tasklet */
static inline void iwl_synchronize_irq ( struct iwl_priv * priv )
{
2008-10-23 23:48:56 -07:00
/* wait to make sure we flush pending tasklet*/
2008-03-28 16:21:08 -07:00
synchronize_irq ( priv - > pci_dev - > irq ) ;
tasklet_kill ( & priv - > irq_tasklet ) ;
}
2009-05-22 11:01:50 -07:00
static void iwl_irq_tasklet_legacy ( struct iwl_priv * priv )
2007-09-25 17:54:57 -07:00
{
u32 inta , handled = 0 ;
u32 inta_fh ;
unsigned long flags ;
2008-03-12 16:58:49 -07:00
# ifdef CONFIG_IWLWIFI_DEBUG
2007-09-25 17:54:57 -07:00
u32 inta_mask ;
# endif
spin_lock_irqsave ( & priv - > lock , flags ) ;
/* Ack/clear/reset pending uCode interrupts.
* Note : Some bits in CSR_INT are " OR " of bits in CSR_FH_INT_STATUS ,
* and will clear only when CSR_FH_INT_STATUS gets cleared . */
2008-03-25 16:33:37 -07:00
inta = iwl_read32 ( priv , CSR_INT ) ;
iwl_write32 ( priv , CSR_INT , inta ) ;
2007-09-25 17:54:57 -07:00
/* Ack/clear/reset pending flow-handler (DMA) interrupts.
* Any new interrupts that happen after this , either while we ' re
* in this tasklet , or later , will show up in next ISR / tasklet . */
2008-03-25 16:33:37 -07:00
inta_fh = iwl_read32 ( priv , CSR_FH_INT_STATUS ) ;
iwl_write32 ( priv , CSR_FH_INT_STATUS , inta_fh ) ;
2007-09-25 17:54:57 -07:00
2008-03-12 16:58:49 -07:00
# ifdef CONFIG_IWLWIFI_DEBUG
2008-05-05 10:22:40 +08:00
if ( priv - > debug_level & IWL_DL_ISR ) {
2007-11-29 11:09:47 +08:00
/* just for debug */
2008-03-25 16:33:37 -07:00
inta_mask = iwl_read32 ( priv , CSR_INT_MASK ) ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_ISR ( priv , " inta 0x%08x, enabled 0x%08x, fh 0x%08x \n " ,
2007-09-25 17:54:57 -07:00
inta , inta_mask , inta_fh ) ;
}
# endif
/* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not
* atomic , make sure that inta covers all the interrupts that
* we ' ve discovered , even if FH interrupt came in just after
* reading CSR_INT . */
2008-03-04 18:09:28 -08:00
if ( inta_fh & CSR49_FH_INT_RX_MASK )
2007-09-25 17:54:57 -07:00
inta | = CSR_INT_BIT_FH_RX ;
2008-03-04 18:09:28 -08:00
if ( inta_fh & CSR49_FH_INT_TX_MASK )
2007-09-25 17:54:57 -07:00
inta | = CSR_INT_BIT_FH_TX ;
/* Now service all interrupt bits discovered above. */
if ( inta & CSR_INT_BIT_HW_ERR ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " Microcode HW error detected. Restarting. \n " ) ;
2007-09-25 17:54:57 -07:00
/* Tell the device to stop sending interrupts */
2008-10-29 14:05:46 -07:00
iwl_disable_interrupts ( priv ) ;
2007-09-25 17:54:57 -07:00
2009-04-08 11:39:32 -07:00
priv - > isr_stats . hw + + ;
2008-10-29 14:05:46 -07:00
iwl_irq_handle_error ( priv ) ;
2007-09-25 17:54:57 -07:00
handled | = CSR_INT_BIT_HW_ERR ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
return ;
}
2008-03-12 16:58:49 -07:00
# ifdef CONFIG_IWLWIFI_DEBUG
2008-05-05 10:22:40 +08:00
if ( priv - > debug_level & ( IWL_DL_ISR ) ) {
2007-09-25 17:54:57 -07:00
/* NIC fires this, but we don't use it, redundant with WAKEUP */
2009-04-08 11:39:32 -07:00
if ( inta & CSR_INT_BIT_SCD ) {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_ISR ( priv , " Scheduler finished to transmit "
2008-01-23 10:15:20 -08:00
" the frame/frames. \n " ) ;
2009-04-08 11:39:32 -07:00
priv - > isr_stats . sch + + ;
}
2007-09-25 17:54:57 -07:00
/* Alive notification via Rx interrupt will do the real work */
2009-04-08 11:39:32 -07:00
if ( inta & CSR_INT_BIT_ALIVE ) {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_ISR ( priv , " Alive interrupt \n " ) ;
2009-04-08 11:39:32 -07:00
priv - > isr_stats . alive + + ;
}
2007-09-25 17:54:57 -07:00
}
# endif
/* Safely ignore these bits for debug checks below */
2008-01-23 10:15:20 -08:00
inta & = ~ ( CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE ) ;
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:47 +08:00
/* HW RF KILL switch toggled */
2007-09-25 17:54:57 -07:00
if ( inta & CSR_INT_BIT_RF_KILL ) {
int hw_rf_kill = 0 ;
2008-03-25 16:33:37 -07:00
if ( ! ( iwl_read32 ( priv , CSR_GP_CNTRL ) &
2007-09-25 17:54:57 -07:00
CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW ) )
hw_rf_kill = 1 ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_RF_KILL ( priv , " RF_KILL bit toggled to %s. \n " ,
2008-11-12 13:14:08 -08:00
hw_rf_kill ? " disable radio " : " enable radio " ) ;
2007-09-25 17:54:57 -07:00
2009-04-08 11:39:32 -07:00
priv - > isr_stats . rfkill + + ;
2008-06-30 17:23:25 +08:00
/* driver only loads ucode once setting the interface up.
2009-01-19 13:10:07 +01:00
* the driver allows loading the ucode even if the radio
* is killed . Hence update the killswitch state here . The
* rfkill handler will care about restarting if needed .
2008-06-30 17:23:25 +08:00
*/
2009-01-19 13:10:07 +01:00
if ( ! test_bit ( STATUS_ALIVE , & priv - > status ) ) {
if ( hw_rf_kill )
set_bit ( STATUS_RF_KILL_HW , & priv - > status ) ;
else
clear_bit ( STATUS_RF_KILL_HW , & priv - > status ) ;
2009-06-04 18:26:06 +02:00
wiphy_rfkill_set_hw_state ( priv - > hw - > wiphy , hw_rf_kill ) ;
2008-12-11 10:33:37 -08:00
}
2007-09-25 17:54:57 -07:00
handled | = CSR_INT_BIT_RF_KILL ;
}
2007-11-29 11:09:47 +08:00
/* Chip got too hot and stopped itself */
2007-09-25 17:54:57 -07:00
if ( inta & CSR_INT_BIT_CT_KILL ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " Microcode CT kill error detected. \n " ) ;
2009-04-08 11:39:32 -07:00
priv - > isr_stats . ctkill + + ;
2007-09-25 17:54:57 -07:00
handled | = CSR_INT_BIT_CT_KILL ;
}
/* Error detected by uCode */
if ( inta & CSR_INT_BIT_SW_ERR ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " Microcode SW error detected. "
" Restarting 0x%X. \n " , inta ) ;
2009-04-08 11:39:32 -07:00
priv - > isr_stats . sw + + ;
priv - > isr_stats . sw_err = inta ;
2008-10-29 14:05:46 -07:00
iwl_irq_handle_error ( priv ) ;
2007-09-25 17:54:57 -07:00
handled | = CSR_INT_BIT_SW_ERR ;
}
/* uCode wakes up after power-down sleep */
if ( inta & CSR_INT_BIT_WAKEUP ) {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_ISR ( priv , " Wakeup interrupt \n " ) ;
2008-05-05 10:22:28 +08:00
iwl_rx_queue_update_write_ptr ( priv , & priv - > rxq ) ;
2008-05-15 13:54:00 +08:00
iwl_txq_update_write_ptr ( priv , & priv - > txq [ 0 ] ) ;
iwl_txq_update_write_ptr ( priv , & priv - > txq [ 1 ] ) ;
iwl_txq_update_write_ptr ( priv , & priv - > txq [ 2 ] ) ;
iwl_txq_update_write_ptr ( priv , & priv - > txq [ 3 ] ) ;
iwl_txq_update_write_ptr ( priv , & priv - > txq [ 4 ] ) ;
iwl_txq_update_write_ptr ( priv , & priv - > txq [ 5 ] ) ;
2007-09-25 17:54:57 -07:00
2009-04-08 11:39:32 -07:00
priv - > isr_stats . wakeup + + ;
2007-09-25 17:54:57 -07:00
handled | = CSR_INT_BIT_WAKEUP ;
}
/* All uCode command responses, including Tx command responses,
* Rx " responses " ( frame - received notification ) , and other
* notifications from uCode come through here */
if ( inta & ( CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX ) ) {
2008-05-05 10:22:28 +08:00
iwl_rx_handle ( priv ) ;
2009-04-08 11:39:32 -07:00
priv - > isr_stats . rx + + ;
2007-09-25 17:54:57 -07:00
handled | = ( CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX ) ;
}
if ( inta & CSR_INT_BIT_FH_TX ) {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_ISR ( priv , " Tx interrupt \n " ) ;
2009-04-08 11:39:32 -07:00
priv - > isr_stats . tx + + ;
2007-09-25 17:54:57 -07:00
handled | = CSR_INT_BIT_FH_TX ;
2008-05-15 13:54:12 +08:00
/* FH finished to write, send event */
priv - > ucode_write_complete = 1 ;
wake_up_interruptible ( & priv - > wait_command_queue ) ;
2007-09-25 17:54:57 -07:00
}
2009-04-08 11:39:32 -07:00
if ( inta & ~ handled ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " Unhandled INTA bits 0x%08x \n " , inta & ~ handled ) ;
2009-04-08 11:39:32 -07:00
priv - > isr_stats . unhandled + + ;
}
2007-09-25 17:54:57 -07:00
2009-05-22 11:01:52 -07:00
if ( inta & ~ ( priv - > inta_mask ) ) {
2008-12-19 10:37:32 +08:00
IWL_WARN ( priv , " Disabled INTA bits 0x%08x were pending \n " ,
2009-05-22 11:01:52 -07:00
inta & ~ priv - > inta_mask ) ;
2008-12-19 10:37:32 +08:00
IWL_WARN ( priv , " with FH_INT = 0x%08x \n " , inta_fh ) ;
2007-09-25 17:54:57 -07:00
}
/* Re-enable all interrupts */
2008-03-28 16:21:08 -07:00
/* only Re-enable if diabled by irq */
if ( test_bit ( STATUS_INT_ENABLED , & priv - > status ) )
2008-10-29 14:05:46 -07:00
iwl_enable_interrupts ( priv ) ;
2007-09-25 17:54:57 -07:00
2008-03-12 16:58:49 -07:00
# ifdef CONFIG_IWLWIFI_DEBUG
2008-05-05 10:22:40 +08:00
if ( priv - > debug_level & ( IWL_DL_ISR ) ) {
2008-03-25 16:33:37 -07:00
inta = iwl_read32 ( priv , CSR_INT ) ;
inta_mask = iwl_read32 ( priv , CSR_INT_MASK ) ;
inta_fh = iwl_read32 ( priv , CSR_FH_INT_STATUS ) ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_ISR ( priv , " End inta 0x%08x, enabled 0x%08x, fh 0x%08x, "
2007-09-25 17:54:57 -07:00
" flags 0x%08lx \n " , inta , inta_mask , inta_fh , flags ) ;
}
# endif
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
}
2009-05-22 11:01:50 -07:00
/* tasklet for iwlagn interrupt */
static void iwl_irq_tasklet ( struct iwl_priv * priv )
{
u32 inta = 0 ;
u32 handled = 0 ;
unsigned long flags ;
# ifdef CONFIG_IWLWIFI_DEBUG
u32 inta_mask ;
# endif
spin_lock_irqsave ( & priv - > lock , flags ) ;
/* Ack/clear/reset pending uCode interrupts.
* Note : Some bits in CSR_INT are " OR " of bits in CSR_FH_INT_STATUS ,
*/
iwl_write32 ( priv , CSR_INT , priv - > inta ) ;
inta = priv - > inta ;
# ifdef CONFIG_IWLWIFI_DEBUG
if ( priv - > debug_level & IWL_DL_ISR ) {
/* just for debug */
inta_mask = iwl_read32 ( priv , CSR_INT_MASK ) ;
IWL_DEBUG_ISR ( priv , " inta 0x%08x, enabled 0x%08x \n " ,
inta , inta_mask ) ;
}
# endif
/* saved interrupt in inta variable now we can reset priv->inta */
priv - > inta = 0 ;
/* Now service all interrupt bits discovered above. */
if ( inta & CSR_INT_BIT_HW_ERR ) {
IWL_ERR ( priv , " Microcode HW error detected. Restarting. \n " ) ;
/* Tell the device to stop sending interrupts */
iwl_disable_interrupts ( priv ) ;
priv - > isr_stats . hw + + ;
iwl_irq_handle_error ( priv ) ;
handled | = CSR_INT_BIT_HW_ERR ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
return ;
}
# ifdef CONFIG_IWLWIFI_DEBUG
if ( priv - > debug_level & ( IWL_DL_ISR ) ) {
/* NIC fires this, but we don't use it, redundant with WAKEUP */
if ( inta & CSR_INT_BIT_SCD ) {
IWL_DEBUG_ISR ( priv , " Scheduler finished to transmit "
" the frame/frames. \n " ) ;
priv - > isr_stats . sch + + ;
}
/* Alive notification via Rx interrupt will do the real work */
if ( inta & CSR_INT_BIT_ALIVE ) {
IWL_DEBUG_ISR ( priv , " Alive interrupt \n " ) ;
priv - > isr_stats . alive + + ;
}
}
# endif
/* Safely ignore these bits for debug checks below */
inta & = ~ ( CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE ) ;
/* HW RF KILL switch toggled */
if ( inta & CSR_INT_BIT_RF_KILL ) {
int hw_rf_kill = 0 ;
if ( ! ( iwl_read32 ( priv , CSR_GP_CNTRL ) &
CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW ) )
hw_rf_kill = 1 ;
IWL_DEBUG_RF_KILL ( priv , " RF_KILL bit toggled to %s. \n " ,
hw_rf_kill ? " disable radio " : " enable radio " ) ;
priv - > isr_stats . rfkill + + ;
/* driver only loads ucode once setting the interface up.
* the driver allows loading the ucode even if the radio
* is killed . Hence update the killswitch state here . The
* rfkill handler will care about restarting if needed .
*/
if ( ! test_bit ( STATUS_ALIVE , & priv - > status ) ) {
if ( hw_rf_kill )
set_bit ( STATUS_RF_KILL_HW , & priv - > status ) ;
else
clear_bit ( STATUS_RF_KILL_HW , & priv - > status ) ;
2009-06-04 18:26:06 +02:00
wiphy_rfkill_set_hw_state ( priv - > hw - > wiphy , hw_rf_kill ) ;
2009-05-22 11:01:50 -07:00
}
handled | = CSR_INT_BIT_RF_KILL ;
}
/* Chip got too hot and stopped itself */
if ( inta & CSR_INT_BIT_CT_KILL ) {
IWL_ERR ( priv , " Microcode CT kill error detected. \n " ) ;
priv - > isr_stats . ctkill + + ;
handled | = CSR_INT_BIT_CT_KILL ;
}
/* Error detected by uCode */
if ( inta & CSR_INT_BIT_SW_ERR ) {
IWL_ERR ( priv , " Microcode SW error detected. "
" Restarting 0x%X. \n " , inta ) ;
priv - > isr_stats . sw + + ;
priv - > isr_stats . sw_err = inta ;
iwl_irq_handle_error ( priv ) ;
handled | = CSR_INT_BIT_SW_ERR ;
}
/* uCode wakes up after power-down sleep */
if ( inta & CSR_INT_BIT_WAKEUP ) {
IWL_DEBUG_ISR ( priv , " Wakeup interrupt \n " ) ;
iwl_rx_queue_update_write_ptr ( priv , & priv - > rxq ) ;
iwl_txq_update_write_ptr ( priv , & priv - > txq [ 0 ] ) ;
iwl_txq_update_write_ptr ( priv , & priv - > txq [ 1 ] ) ;
iwl_txq_update_write_ptr ( priv , & priv - > txq [ 2 ] ) ;
iwl_txq_update_write_ptr ( priv , & priv - > txq [ 3 ] ) ;
iwl_txq_update_write_ptr ( priv , & priv - > txq [ 4 ] ) ;
iwl_txq_update_write_ptr ( priv , & priv - > txq [ 5 ] ) ;
priv - > isr_stats . wakeup + + ;
handled | = CSR_INT_BIT_WAKEUP ;
}
/* All uCode command responses, including Tx command responses,
* Rx " responses " ( frame - received notification ) , and other
* notifications from uCode come through here */
2009-05-22 11:01:52 -07:00
if ( inta & ( CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX |
CSR_INT_BIT_RX_PERIODIC ) ) {
2009-05-22 11:01:50 -07:00
IWL_DEBUG_ISR ( priv , " Rx interrupt \n " ) ;
2009-05-22 11:01:52 -07:00
if ( inta & ( CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX ) ) {
handled | = ( CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX ) ;
iwl_write32 ( priv , CSR_FH_INT_STATUS ,
CSR49_FH_INT_RX_MASK ) ;
}
if ( inta & CSR_INT_BIT_RX_PERIODIC ) {
handled | = CSR_INT_BIT_RX_PERIODIC ;
iwl_write32 ( priv , CSR_INT , CSR_INT_BIT_RX_PERIODIC ) ;
}
/* Sending RX interrupt require many steps to be done in the
* the device :
* 1 - write interrupt to current index in ICT table .
* 2 - dma RX frame .
* 3 - update RX shared data to indicate last write index .
* 4 - send interrupt .
* This could lead to RX race , driver could receive RX interrupt
* but the shared data changes does not reflect this .
* this could lead to RX race , RX periodic will solve this race
*/
iwl_write32 ( priv , CSR_INT_PERIODIC_REG ,
CSR_INT_PERIODIC_DIS ) ;
2009-05-22 11:01:50 -07:00
iwl_rx_handle ( priv ) ;
2009-05-22 11:01:52 -07:00
/* Only set RX periodic if real RX is received. */
if ( inta & ( CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX ) )
iwl_write32 ( priv , CSR_INT_PERIODIC_REG ,
CSR_INT_PERIODIC_ENA ) ;
2009-05-22 11:01:50 -07:00
priv - > isr_stats . rx + + ;
}
if ( inta & CSR_INT_BIT_FH_TX ) {
iwl_write32 ( priv , CSR_FH_INT_STATUS , CSR49_FH_INT_TX_MASK ) ;
IWL_DEBUG_ISR ( priv , " Tx interrupt \n " ) ;
priv - > isr_stats . tx + + ;
handled | = CSR_INT_BIT_FH_TX ;
/* FH finished to write, send event */
priv - > ucode_write_complete = 1 ;
wake_up_interruptible ( & priv - > wait_command_queue ) ;
}
if ( inta & ~ handled ) {
IWL_ERR ( priv , " Unhandled INTA bits 0x%08x \n " , inta & ~ handled ) ;
priv - > isr_stats . unhandled + + ;
}
2009-05-22 11:01:52 -07:00
if ( inta & ~ ( priv - > inta_mask ) ) {
2009-05-22 11:01:50 -07:00
IWL_WARN ( priv , " Disabled INTA bits 0x%08x were pending \n " ,
2009-05-22 11:01:52 -07:00
inta & ~ priv - > inta_mask ) ;
2009-05-22 11:01:50 -07:00
}
/* Re-enable all interrupts */
/* only Re-enable if diabled by irq */
if ( test_bit ( STATUS_INT_ENABLED , & priv - > status ) )
iwl_enable_interrupts ( priv ) ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
}
2009-04-08 11:39:32 -07:00
2007-09-25 17:54:57 -07:00
/******************************************************************************
*
* uCode download functions
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-10-29 14:05:46 -07:00
static void iwl_dealloc_ucode_pci ( struct iwl_priv * priv )
2007-09-25 17:54:57 -07:00
{
2008-01-14 17:46:20 -08:00
iwl_free_fw_desc ( priv - > pci_dev , & priv - > ucode_code ) ;
iwl_free_fw_desc ( priv - > pci_dev , & priv - > ucode_data ) ;
iwl_free_fw_desc ( priv - > pci_dev , & priv - > ucode_data_backup ) ;
iwl_free_fw_desc ( priv - > pci_dev , & priv - > ucode_init ) ;
iwl_free_fw_desc ( priv - > pci_dev , & priv - > ucode_init_data ) ;
iwl_free_fw_desc ( priv - > pci_dev , & priv - > ucode_boot ) ;
2007-09-25 17:54:57 -07:00
}
2008-10-29 14:05:46 -07:00
static void iwl_nic_start ( struct iwl_priv * priv )
2008-05-15 13:53:55 +08:00
{
/* Remove all resets to allow NIC to operate */
iwl_write32 ( priv , CSR_RESET , 0 ) ;
}
2007-09-25 17:54:57 -07:00
/**
2008-10-29 14:05:46 -07:00
* iwl_read_ucode - Read uCode images from disk file .
2007-09-25 17:54:57 -07:00
*
* Copy into buffers for card to fetch via bus - mastering
*/
2008-10-29 14:05:46 -07:00
static int iwl_read_ucode ( struct iwl_priv * priv )
2007-09-25 17:54:57 -07:00
{
2008-06-13 15:44:54 +08:00
struct iwl_ucode * ucode ;
2008-12-02 12:14:06 -08:00
int ret = - EINVAL , index ;
2007-09-25 17:54:57 -07:00
const struct firmware * ucode_raw ;
2008-12-02 12:14:06 -08:00
const char * name_pre = priv - > cfg - > fw_name_pre ;
const unsigned int api_max = priv - > cfg - > ucode_api_max ;
const unsigned int api_min = priv - > cfg - > ucode_api_min ;
char buf [ 25 ] ;
2007-09-25 17:54:57 -07:00
u8 * src ;
size_t len ;
2008-12-02 12:14:06 -08:00
u32 api_ver , inst_size , data_size , init_size , init_data_size , boot_size ;
2007-09-25 17:54:57 -07:00
/* Ask kernel firmware_class module to get the boot firmware off disk.
* request_firmware ( ) is synchronous , file is in memory on return . */
2008-12-02 12:14:06 -08:00
for ( index = api_max ; index > = api_min ; index - - ) {
sprintf ( buf , " %s%d%s " , name_pre , index , " .ucode " ) ;
ret = request_firmware ( & ucode_raw , buf , & priv - > pci_dev - > dev ) ;
if ( ret < 0 ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " %s firmware file req failed: %d \n " ,
2008-12-02 12:14:06 -08:00
buf , ret ) ;
if ( ret = = - ENOENT )
continue ;
else
goto error ;
} else {
if ( index < api_max )
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " Loaded firmware %s, "
" which is deprecated. "
" Please use API v%u instead. \n " ,
2008-12-02 12:14:06 -08:00
buf , api_max ) ;
2008-12-19 10:37:33 +08:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " Got firmware '%s' file (%zd bytes) from disk \n " ,
2008-12-02 12:14:06 -08:00
buf , ucode_raw - > size ) ;
break ;
}
2007-09-25 17:54:57 -07:00
}
2008-12-02 12:14:06 -08:00
if ( ret < 0 )
goto error ;
2007-09-25 17:54:57 -07:00
/* Make sure that we got at least our header! */
if ( ucode_raw - > size < sizeof ( * ucode ) ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " File size way too small! \n " ) ;
2007-11-29 11:09:41 +08:00
ret = - EINVAL ;
2007-09-25 17:54:57 -07:00
goto err_release ;
}
/* Data from ucode file: header followed by uCode images */
ucode = ( void * ) ucode_raw - > data ;
2008-12-02 12:14:05 -08:00
priv - > ucode_ver = le32_to_cpu ( ucode - > ver ) ;
2008-12-02 12:14:06 -08:00
api_ver = IWL_UCODE_API ( priv - > ucode_ver ) ;
2007-09-25 17:54:57 -07:00
inst_size = le32_to_cpu ( ucode - > inst_size ) ;
data_size = le32_to_cpu ( ucode - > data_size ) ;
init_size = le32_to_cpu ( ucode - > init_size ) ;
init_data_size = le32_to_cpu ( ucode - > init_data_size ) ;
boot_size = le32_to_cpu ( ucode - > boot_size ) ;
2008-12-02 12:14:06 -08:00
/* api_ver should match the api version forming part of the
* firmware filename . . . but we don ' t check for that and only rely
2009-01-26 11:06:57 +01:00
* on the API version read from firmware header from here on forward */
2008-12-02 12:14:06 -08:00
if ( api_ver < api_min | | api_ver > api_max ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " Driver unable to support your firmware API. "
2008-12-02 12:14:06 -08:00
" Driver supports v%u, firmware is v%u. \n " ,
api_max , api_ver ) ;
priv - > ucode_ver = 0 ;
ret = - EINVAL ;
goto err_release ;
}
if ( api_ver ! = api_max )
2008-12-19 10:37:31 +08:00
IWL_ERR ( priv , " Firmware has old API version. Expected v%u, "
2008-12-02 12:14:06 -08:00
" got v%u. New firmware can be obtained "
" from http://www.intellinuxwireless.org. \n " ,
api_max , api_ver ) ;
2008-12-19 10:37:31 +08:00
IWL_INFO ( priv , " loaded firmware version %u.%u.%u.%u \n " ,
IWL_UCODE_MAJOR ( priv - > ucode_ver ) ,
IWL_UCODE_MINOR ( priv - > ucode_ver ) ,
IWL_UCODE_API ( priv - > ucode_ver ) ,
IWL_UCODE_SERIAL ( priv - > ucode_ver ) ) ;
2008-12-02 12:14:06 -08:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " f/w package hdr ucode version raw = 0x%x \n " ,
2008-12-02 12:14:06 -08:00
priv - > ucode_ver ) ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " f/w package hdr runtime inst size = %u \n " ,
2007-09-25 17:54:57 -07:00
inst_size ) ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " f/w package hdr runtime data size = %u \n " ,
2007-09-25 17:54:57 -07:00
data_size ) ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " f/w package hdr init inst size = %u \n " ,
2007-09-25 17:54:57 -07:00
init_size ) ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " f/w package hdr init data size = %u \n " ,
2007-09-25 17:54:57 -07:00
init_data_size ) ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " f/w package hdr boot inst size = %u \n " ,
2007-09-25 17:54:57 -07:00
boot_size ) ;
/* Verify size of file vs. image size info in file's header */
if ( ucode_raw - > size < sizeof ( * ucode ) +
inst_size + data_size + init_size +
init_data_size + boot_size ) {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " uCode file size %d too small \n " ,
2007-09-25 17:54:57 -07:00
( int ) ucode_raw - > size ) ;
2007-11-29 11:09:41 +08:00
ret = - EINVAL ;
2007-09-25 17:54:57 -07:00
goto err_release ;
}
/* Verify that uCode images will fit in card's SRAM */
2008-04-21 15:41:53 -07:00
if ( inst_size > priv - > hw_params . max_inst_size ) {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " uCode instr len %d too large to fit in \n " ,
2007-11-29 11:09:41 +08:00
inst_size ) ;
ret = - EINVAL ;
2007-09-25 17:54:57 -07:00
goto err_release ;
}
2008-04-21 15:41:53 -07:00
if ( data_size > priv - > hw_params . max_data_size ) {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " uCode data len %d too large to fit in \n " ,
2007-11-29 11:09:41 +08:00
data_size ) ;
ret = - EINVAL ;
2007-09-25 17:54:57 -07:00
goto err_release ;
}
2008-04-21 15:41:53 -07:00
if ( init_size > priv - > hw_params . max_inst_size ) {
2009-01-27 14:27:56 -08:00
IWL_INFO ( priv , " uCode init instr len %d too large to fit in \n " ,
init_size ) ;
2007-11-29 11:09:41 +08:00
ret = - EINVAL ;
2007-09-25 17:54:57 -07:00
goto err_release ;
}
2008-04-21 15:41:53 -07:00
if ( init_data_size > priv - > hw_params . max_data_size ) {
2009-01-27 14:27:56 -08:00
IWL_INFO ( priv , " uCode init data len %d too large to fit in \n " ,
2007-11-29 11:09:41 +08:00
init_data_size ) ;
ret = - EINVAL ;
2007-09-25 17:54:57 -07:00
goto err_release ;
}
2008-04-21 15:41:53 -07:00
if ( boot_size > priv - > hw_params . max_bsm_size ) {
2009-01-27 14:27:56 -08:00
IWL_INFO ( priv , " uCode boot instr len %d too large to fit in \n " ,
boot_size ) ;
2007-11-29 11:09:41 +08:00
ret = - EINVAL ;
2007-09-25 17:54:57 -07:00
goto err_release ;
}
/* Allocate ucode buffers for card's bus-master loading ... */
/* Runtime instructions and 2 copies of data:
* 1 ) unmodified from disk
* 2 ) backup cache for save / restore during power - downs */
priv - > ucode_code . len = inst_size ;
2008-01-14 17:46:20 -08:00
iwl_alloc_fw_desc ( priv - > pci_dev , & priv - > ucode_code ) ;
2007-09-25 17:54:57 -07:00
priv - > ucode_data . len = data_size ;
2008-01-14 17:46:20 -08:00
iwl_alloc_fw_desc ( priv - > pci_dev , & priv - > ucode_data ) ;
2007-09-25 17:54:57 -07:00
priv - > ucode_data_backup . len = data_size ;
2008-01-14 17:46:20 -08:00
iwl_alloc_fw_desc ( priv - > pci_dev , & priv - > ucode_data_backup ) ;
2007-09-25 17:54:57 -07:00
2009-01-23 13:45:22 -08:00
if ( ! priv - > ucode_code . v_addr | | ! priv - > ucode_data . v_addr | |
! priv - > ucode_data_backup . v_addr )
goto err_pci_alloc ;
2007-09-25 17:54:57 -07:00
/* Initialization instructions and data */
2007-11-29 11:09:41 +08:00
if ( init_size & & init_data_size ) {
priv - > ucode_init . len = init_size ;
2008-01-14 17:46:20 -08:00
iwl_alloc_fw_desc ( priv - > pci_dev , & priv - > ucode_init ) ;
2007-11-29 11:09:41 +08:00
priv - > ucode_init_data . len = init_data_size ;
2008-01-14 17:46:20 -08:00
iwl_alloc_fw_desc ( priv - > pci_dev , & priv - > ucode_init_data ) ;
2007-11-29 11:09:41 +08:00
if ( ! priv - > ucode_init . v_addr | | ! priv - > ucode_init_data . v_addr )
goto err_pci_alloc ;
}
2007-09-25 17:54:57 -07:00
/* Bootstrap (instructions only, no data) */
2007-11-29 11:09:41 +08:00
if ( boot_size ) {
priv - > ucode_boot . len = boot_size ;
2008-01-14 17:46:20 -08:00
iwl_alloc_fw_desc ( priv - > pci_dev , & priv - > ucode_boot ) ;
2007-09-25 17:54:57 -07:00
2007-11-29 11:09:41 +08:00
if ( ! priv - > ucode_boot . v_addr )
goto err_pci_alloc ;
}
2007-09-25 17:54:57 -07:00
/* Copy images into buffers for card's bus-master reads ... */
/* Runtime instructions (first block of data in file) */
src = & ucode - > data [ 0 ] ;
len = priv - > ucode_code . len ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " Copying (but not loading) uCode instr len %Zd \n " , len ) ;
2007-09-25 17:54:57 -07:00
memcpy ( priv - > ucode_code . v_addr , src , len ) ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " uCode instr buf vaddr = 0x%p, paddr = 0x%08x \n " ,
2007-09-25 17:54:57 -07:00
priv - > ucode_code . v_addr , ( u32 ) priv - > ucode_code . p_addr ) ;
/* Runtime data (2nd block)
2008-10-29 14:05:46 -07:00
* NOTE : Copy into backup buffer will be done in iwl_up ( ) */
2007-09-25 17:54:57 -07:00
src = & ucode - > data [ inst_size ] ;
len = priv - > ucode_data . len ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " Copying (but not loading) uCode data len %Zd \n " , len ) ;
2007-09-25 17:54:57 -07:00
memcpy ( priv - > ucode_data . v_addr , src , len ) ;
memcpy ( priv - > ucode_data_backup . v_addr , src , len ) ;
/* Initialization instructions (3rd block) */
if ( init_size ) {
src = & ucode - > data [ inst_size + data_size ] ;
len = priv - > ucode_init . len ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " Copying (but not loading) init instr len %Zd \n " ,
2007-11-29 11:09:41 +08:00
len ) ;
2007-09-25 17:54:57 -07:00
memcpy ( priv - > ucode_init . v_addr , src , len ) ;
}
/* Initialization data (4th block) */
if ( init_data_size ) {
src = & ucode - > data [ inst_size + data_size + init_size ] ;
len = priv - > ucode_init_data . len ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " Copying (but not loading) init data len %Zd \n " ,
2007-11-29 11:09:41 +08:00
len ) ;
2007-09-25 17:54:57 -07:00
memcpy ( priv - > ucode_init_data . v_addr , src , len ) ;
}
/* Bootstrap instructions (5th block) */
src = & ucode - > data [ inst_size + data_size + init_size + init_data_size ] ;
len = priv - > ucode_boot . len ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " Copying (but not loading) boot instr len %Zd \n " , len ) ;
2007-09-25 17:54:57 -07:00
memcpy ( priv - > ucode_boot . v_addr , src , len ) ;
/* We have our copies now, allow OS release its copies */
release_firmware ( ucode_raw ) ;
return 0 ;
err_pci_alloc :
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " failed to allocate pci memory \n " ) ;
2007-11-29 11:09:41 +08:00
ret = - ENOMEM ;
2008-10-29 14:05:46 -07:00
iwl_dealloc_ucode_pci ( priv ) ;
2007-09-25 17:54:57 -07:00
err_release :
release_firmware ( ucode_raw ) ;
error :
2007-11-29 11:09:41 +08:00
return ret ;
2007-09-25 17:54:57 -07:00
}
/**
2008-05-29 16:34:54 +08:00
* iwl_alive_start - called after REPLY_ALIVE notification received
2007-09-25 17:54:57 -07:00
* from protocol / runtime uCode ( initialization uCode ' s
2008-05-29 16:34:54 +08:00
* Alive gets handled by iwl_init_alive_start ( ) ) .
2007-09-25 17:54:57 -07:00
*/
2008-05-29 16:34:54 +08:00
static void iwl_alive_start ( struct iwl_priv * priv )
2007-09-25 17:54:57 -07:00
{
2008-04-14 21:16:03 -07:00
int ret = 0 ;
2007-09-25 17:54:57 -07:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " Runtime Alive received. \n " ) ;
2007-09-25 17:54:57 -07:00
if ( priv - > card_alive . is_valid ! = UCODE_VALID_OK ) {
/* We had an error bringing up the hardware, so take it
* all the way back down so we can try again */
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " Alive failed. \n " ) ;
2007-09-25 17:54:57 -07:00
goto restart ;
}
/* Initialize uCode has loaded Runtime uCode ... verify inst image.
* This is a paranoid check , because we would not have gotten the
* " runtime " alive if code weren ' t properly loaded . */
2008-04-24 11:55:18 -07:00
if ( iwl_verify_ucode ( priv ) ) {
2007-09-25 17:54:57 -07:00
/* Runtime instruction load was bad;
* take it all the way back down so we can try again */
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " Bad runtime uCode load. \n " ) ;
2007-09-25 17:54:57 -07:00
goto restart ;
}
2009-06-03 11:44:07 -07:00
iwl_clear_stations_table ( priv ) ;
2008-04-14 21:16:03 -07:00
ret = priv - > cfg - > ops - > lib - > alive_notify ( priv ) ;
if ( ret ) {
2008-12-19 10:37:32 +08:00
IWL_WARN ( priv ,
" Could not complete ALIVE transition [ntf]: %d \n " , ret ) ;
2007-09-25 17:54:57 -07:00
goto restart ;
}
2008-10-29 14:05:46 -07:00
/* After the ALIVE response, we can send host commands to the uCode */
2007-09-25 17:54:57 -07:00
set_bit ( STATUS_ALIVE , & priv - > status ) ;
2008-04-03 16:05:21 -07:00
if ( iwl_is_rfkill ( priv ) )
2007-09-25 17:54:57 -07:00
return ;
2008-05-15 12:55:26 +02:00
ieee80211_wake_queues ( priv - > hw ) ;
2007-09-25 17:54:57 -07:00
priv - > active_rate = priv - > rates_mask ;
priv - > active_rate_basic = priv - > rates_mask & IWL_BASIC_RATES_MASK ;
2008-03-28 16:33:35 -07:00
if ( iwl_is_associated ( priv ) ) {
2008-05-15 13:53:59 +08:00
struct iwl_rxon_cmd * active_rxon =
( struct iwl_rxon_cmd * ) & priv - > active_rxon ;
2009-03-17 21:59:18 -07:00
/* apply any changes in staging */
priv - > staging_rxon . filter_flags | = RXON_FILTER_ASSOC_MSK ;
2007-09-25 17:54:57 -07:00
active_rxon - > filter_flags & = ~ RXON_FILTER_ASSOC_MSK ;
} else {
/* Initialize our rx_config data */
2008-10-29 14:05:46 -07:00
iwl_connection_init_rx_config ( priv , priv - > iw_mode ) ;
2009-04-08 11:26:44 -07:00
if ( priv - > cfg - > ops - > hcmd - > set_rxon_chain )
priv - > cfg - > ops - > hcmd - > set_rxon_chain ( priv ) ;
2007-09-25 17:54:57 -07:00
memcpy ( priv - > staging_rxon . node_addr , priv - > mac_addr , ETH_ALEN ) ;
}
2007-11-29 11:09:47 +08:00
/* Configure Bluetooth device coexistence support */
2008-10-29 14:05:46 -07:00
iwl_send_bt_config ( priv ) ;
2007-09-25 17:54:57 -07:00
2008-05-29 16:34:54 +08:00
iwl_reset_run_time_calib ( priv ) ;
2007-09-25 17:54:57 -07:00
/* Configure the adapter for unassociated operation */
2009-04-08 11:26:37 -07:00
iwlcore_commit_rxon ( priv ) ;
2007-09-25 17:54:57 -07:00
/* At this point, the NIC is initialized and operational */
2008-06-12 09:47:13 +08:00
iwl_rf_kill_ct_config ( priv ) ;
2008-01-14 17:46:18 -08:00
2008-04-03 16:05:23 -07:00
iwl_leds_register ( priv ) ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " ALIVE processing complete. \n " ) ;
2008-03-18 14:57:49 -07:00
set_bit ( STATUS_READY , & priv - > status ) ;
2008-01-14 17:46:18 -08:00
wake_up_interruptible ( & priv - > wait_command_queue ) ;
2007-09-25 17:54:57 -07:00
2008-06-12 09:47:19 +08:00
iwl_power_update_mode ( priv , 1 ) ;
2008-06-12 09:47:05 +08:00
2008-11-07 09:58:34 -08:00
/* reassociate for ADHOC mode */
if ( priv - > vif & & ( priv - > iw_mode = = NL80211_IFTYPE_ADHOC ) ) {
struct sk_buff * beacon = ieee80211_beacon_get ( priv - > hw ,
priv - > vif ) ;
if ( beacon )
iwl_mac_beacon_update ( priv - > hw , beacon ) ;
}
2008-06-12 09:47:05 +08:00
if ( test_and_clear_bit ( STATUS_MODE_PENDING , & priv - > status ) )
2008-10-29 14:05:46 -07:00
iwl_set_mode ( priv , priv - > iw_mode ) ;
2008-06-12 09:47:05 +08:00
2007-09-25 17:54:57 -07:00
return ;
restart :
queue_work ( priv - > workqueue , & priv - > restart ) ;
}
2008-06-12 09:46:53 +08:00
static void iwl_cancel_deferred_work ( struct iwl_priv * priv ) ;
2007-09-25 17:54:57 -07:00
2008-10-29 14:05:46 -07:00
static void __iwl_down ( struct iwl_priv * priv )
2007-09-25 17:54:57 -07:00
{
unsigned long flags ;
int exit_pending = test_bit ( STATUS_EXIT_PENDING , & priv - > status ) ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , DRV_NAME " is going down \n " ) ;
2007-09-25 17:54:57 -07:00
if ( ! exit_pending )
set_bit ( STATUS_EXIT_PENDING , & priv - > status ) ;
2008-03-25 16:33:36 -07:00
iwl_leds_unregister ( priv ) ;
2009-06-03 11:44:07 -07:00
iwl_clear_stations_table ( priv ) ;
2007-09-25 17:54:57 -07:00
/* Unblock any waiting calls */
wake_up_interruptible_all ( & priv - > wait_command_queue ) ;
/* Wipe out the EXIT_PENDING status bit if we are not actually
* exiting the module */
if ( ! exit_pending )
clear_bit ( STATUS_EXIT_PENDING , & priv - > status ) ;
/* stop and reset the on-board processor */
2008-03-25 16:33:37 -07:00
iwl_write32 ( priv , CSR_RESET , CSR_RESET_REG_FLAG_NEVO_RESET ) ;
2007-09-25 17:54:57 -07:00
/* tell the device to stop sending interrupts */
2008-03-28 16:21:08 -07:00
spin_lock_irqsave ( & priv - > lock , flags ) ;
2008-10-29 14:05:46 -07:00
iwl_disable_interrupts ( priv ) ;
2008-03-28 16:21:08 -07:00
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
iwl_synchronize_irq ( priv ) ;
2007-09-25 17:54:57 -07:00
if ( priv - > mac80211_registered )
ieee80211_stop_queues ( priv - > hw ) ;
2008-10-29 14:05:46 -07:00
/* If we have not previously called iwl_init() then
2009-06-04 18:26:06 +02:00
* clear all bits but the RF Kill bit and return */
2008-04-03 16:05:21 -07:00
if ( ! iwl_is_init ( priv ) ) {
2007-09-25 17:54:57 -07:00
priv - > status = test_bit ( STATUS_RF_KILL_HW , & priv - > status ) < <
STATUS_RF_KILL_HW |
2008-02-06 11:20:38 -08:00
test_bit ( STATUS_GEO_CONFIGURED , & priv - > status ) < <
STATUS_GEO_CONFIGURED |
2008-06-30 17:23:15 +08:00
test_bit ( STATUS_EXIT_PENDING , & priv - > status ) < <
STATUS_EXIT_PENDING ;
2007-09-25 17:54:57 -07:00
goto exit ;
}
2009-03-26 10:14:08 -07:00
/* ...otherwise clear out all the status bits but the RF Kill
2009-06-04 18:26:06 +02:00
* bit and continue taking the NIC down . */
2007-09-25 17:54:57 -07:00
priv - > status & = test_bit ( STATUS_RF_KILL_HW , & priv - > status ) < <
STATUS_RF_KILL_HW |
2008-02-06 11:20:38 -08:00
test_bit ( STATUS_GEO_CONFIGURED , & priv - > status ) < <
STATUS_GEO_CONFIGURED |
2007-09-25 17:54:57 -07:00
test_bit ( STATUS_FW_ERROR , & priv - > status ) < <
2008-06-30 17:23:15 +08:00
STATUS_FW_ERROR |
test_bit ( STATUS_EXIT_PENDING , & priv - > status ) < <
STATUS_EXIT_PENDING ;
2007-09-25 17:54:57 -07:00
2009-05-22 11:01:50 -07:00
/* device going down, Stop using ICT table */
iwl_disable_ict ( priv ) ;
2007-09-25 17:54:57 -07:00
spin_lock_irqsave ( & priv - > lock , flags ) ;
2008-03-25 16:33:37 -07:00
iwl_clear_bit ( priv , CSR_GP_CNTRL ,
2007-11-29 11:09:47 +08:00
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ ) ;
2007-09-25 17:54:57 -07:00
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2008-05-29 16:35:00 +08:00
iwl_txq_ctx_stop ( priv ) ;
2008-05-29 16:35:01 +08:00
iwl_rxq_stop ( priv ) ;
2007-09-25 17:54:57 -07:00
2009-05-22 11:01:47 -07:00
iwl_write_prph ( priv , APMG_CLK_DIS_REG ,
APMG_CLK_VAL_DMA_CLK_RQT ) ;
2007-09-25 17:54:57 -07:00
udelay ( 5 ) ;
2008-05-29 16:34:57 +08:00
/* FIXME: apm_ops.suspend(priv) */
2009-03-26 10:14:08 -07:00
if ( exit_pending )
2008-09-03 11:18:49 +08:00
priv - > cfg - > ops - > lib - > apm_ops . stop ( priv ) ;
else
priv - > cfg - > ops - > lib - > apm_ops . reset ( priv ) ;
2007-09-25 17:54:57 -07:00
exit :
2008-05-29 16:34:55 +08:00
memset ( & priv - > card_alive , 0 , sizeof ( struct iwl_alive_resp ) ) ;
2007-09-25 17:54:57 -07:00
if ( priv - > ibss_beacon )
dev_kfree_skb ( priv - > ibss_beacon ) ;
priv - > ibss_beacon = NULL ;
/* clear out any free frames */
2008-05-15 13:54:01 +08:00
iwl_clear_free_frames ( priv ) ;
2007-09-25 17:54:57 -07:00
}
2008-10-29 14:05:46 -07:00
static void iwl_down ( struct iwl_priv * priv )
2007-09-25 17:54:57 -07:00
{
mutex_lock ( & priv - > mutex ) ;
2008-10-29 14:05:46 -07:00
__iwl_down ( priv ) ;
2007-09-25 17:54:57 -07:00
mutex_unlock ( & priv - > mutex ) ;
2007-12-19 13:59:52 +08:00
2008-06-12 09:46:53 +08:00
iwl_cancel_deferred_work ( priv ) ;
2007-09-25 17:54:57 -07:00
}
2009-05-22 11:01:54 -07:00
# define HW_READY_TIMEOUT (50)
static int iwl_set_hw_ready ( struct iwl_priv * priv )
{
int ret = 0 ;
iwl_set_bit ( priv , CSR_HW_IF_CONFIG_REG ,
CSR_HW_IF_CONFIG_REG_BIT_NIC_READY ) ;
/* See if we got it */
ret = iwl_poll_bit ( priv , CSR_HW_IF_CONFIG_REG ,
CSR_HW_IF_CONFIG_REG_BIT_NIC_READY ,
CSR_HW_IF_CONFIG_REG_BIT_NIC_READY ,
HW_READY_TIMEOUT ) ;
if ( ret ! = - ETIMEDOUT )
priv - > hw_ready = true ;
else
priv - > hw_ready = false ;
IWL_DEBUG_INFO ( priv , " hardware %s \n " ,
( priv - > hw_ready = = 1 ) ? " ready " : " not ready " ) ;
return ret ;
}
static int iwl_prepare_card_hw ( struct iwl_priv * priv )
{
int ret = 0 ;
IWL_DEBUG_INFO ( priv , " iwl_prepare_card_hw enter \n " ) ;
iwl_set_bit ( priv , CSR_HW_IF_CONFIG_REG ,
CSR_HW_IF_CONFIG_REG_PREPARE ) ;
ret = iwl_poll_bit ( priv , CSR_HW_IF_CONFIG_REG ,
~ CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE ,
CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE , 150000 ) ;
if ( ret ! = - ETIMEDOUT )
iwl_set_hw_ready ( priv ) ;
return ret ;
}
2007-09-25 17:54:57 -07:00
# define MAX_HW_RESTARTS 5
2008-10-29 14:05:46 -07:00
static int __iwl_up ( struct iwl_priv * priv )
2007-09-25 17:54:57 -07:00
{
2008-04-14 21:16:03 -07:00
int i ;
int ret ;
2007-09-25 17:54:57 -07:00
if ( test_bit ( STATUS_EXIT_PENDING , & priv - > status ) ) {
2008-12-19 10:37:32 +08:00
IWL_WARN ( priv , " Exit pending; will not bring the NIC up \n " ) ;
2007-09-25 17:54:57 -07:00
return - EIO ;
}
2008-01-30 22:05:15 -08:00
if ( ! priv - > ucode_data_backup . v_addr | | ! priv - > ucode_data . v_addr ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " ucode not available for device bringup \n " ) ;
2008-01-30 22:05:15 -08:00
return - EIO ;
}
2009-05-22 11:01:54 -07:00
iwl_prepare_card_hw ( priv ) ;
if ( ! priv - > hw_ready ) {
IWL_WARN ( priv , " Exit HW not ready \n " ) ;
return - EIO ;
}
2008-01-24 02:19:38 -08:00
/* If platform's RF_KILL switch is NOT set to KILL */
2008-08-04 16:00:43 +08:00
if ( iwl_read32 ( priv , CSR_GP_CNTRL ) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW )
2008-01-24 02:19:38 -08:00
clear_bit ( STATUS_RF_KILL_HW , & priv - > status ) ;
2008-06-30 17:23:19 +08:00
else
2008-01-24 02:19:38 -08:00
set_bit ( STATUS_RF_KILL_HW , & priv - > status ) ;
2008-06-30 17:23:19 +08:00
2008-08-04 16:00:43 +08:00
if ( iwl_is_rfkill ( priv ) ) {
2009-06-04 18:26:06 +02:00
wiphy_rfkill_set_hw_state ( priv - > hw - > wiphy , true ) ;
2008-10-29 14:05:46 -07:00
iwl_enable_interrupts ( priv ) ;
2009-06-04 18:26:06 +02:00
IWL_WARN ( priv , " Radio disabled by HW RF Kill switch \n " ) ;
2008-08-04 16:00:43 +08:00
return 0 ;
2007-09-25 17:54:57 -07:00
}
2008-03-25 16:33:37 -07:00
iwl_write32 ( priv , CSR_INT , 0xFFFFFFFF ) ;
2007-09-25 17:54:57 -07:00
2008-05-05 10:22:43 +08:00
ret = iwl_hw_nic_init ( priv ) ;
2008-04-14 21:16:03 -07:00
if ( ret ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " Unable to init nic \n " ) ;
2008-04-14 21:16:03 -07:00
return ret ;
2007-09-25 17:54:57 -07:00
}
/* make sure rfkill handshake bits are cleared */
2008-03-25 16:33:37 -07:00
iwl_write32 ( priv , CSR_UCODE_DRV_GP1_CLR , CSR_UCODE_SW_BIT_RFKILL ) ;
iwl_write32 ( priv , CSR_UCODE_DRV_GP1_CLR ,
2007-09-25 17:54:57 -07:00
CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED ) ;
/* clear (again), then enable host interrupts */
2008-03-25 16:33:37 -07:00
iwl_write32 ( priv , CSR_INT , 0xFFFFFFFF ) ;
2008-10-29 14:05:46 -07:00
iwl_enable_interrupts ( priv ) ;
2007-09-25 17:54:57 -07:00
/* really make sure rfkill handshake bits are cleared */
2008-03-25 16:33:37 -07:00
iwl_write32 ( priv , CSR_UCODE_DRV_GP1_CLR , CSR_UCODE_SW_BIT_RFKILL ) ;
iwl_write32 ( priv , CSR_UCODE_DRV_GP1_CLR , CSR_UCODE_SW_BIT_RFKILL ) ;
2007-09-25 17:54:57 -07:00
/* Copy original ucode data image from disk into backup cache.
* This will be used to initialize the on - board processor ' s
* data SRAM for a clean start when the runtime program first loads . */
memcpy ( priv - > ucode_data_backup . v_addr , priv - > ucode_data . v_addr ,
2008-01-14 17:46:18 -08:00
priv - > ucode_data . len ) ;
2007-09-25 17:54:57 -07:00
for ( i = 0 ; i < MAX_HW_RESTARTS ; i + + ) {
2009-06-03 11:44:07 -07:00
iwl_clear_stations_table ( priv ) ;
2007-09-25 17:54:57 -07:00
/* load bootstrap state machine,
* load bootstrap program into processor ' s memory ,
* prepare to load the " initialize " uCode */
2008-04-14 21:16:03 -07:00
ret = priv - > cfg - > ops - > lib - > load_ucode ( priv ) ;
2007-09-25 17:54:57 -07:00
2008-04-14 21:16:03 -07:00
if ( ret ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " Unable to set up bootstrap uCode: %d \n " ,
ret ) ;
2007-09-25 17:54:57 -07:00
continue ;
}
/* start card; "initialize" will load runtime ucode */
2008-10-29 14:05:46 -07:00
iwl_nic_start ( priv ) ;
2007-09-25 17:54:57 -07:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , DRV_NAME " is coming up \n " ) ;
2007-09-25 17:54:57 -07:00
return 0 ;
}
set_bit ( STATUS_EXIT_PENDING , & priv - > status ) ;
2008-10-29 14:05:46 -07:00
__iwl_down ( priv ) ;
2008-06-12 09:47:03 +08:00
clear_bit ( STATUS_EXIT_PENDING , & priv - > status ) ;
2007-09-25 17:54:57 -07:00
/* tried to restart and config the device for as long as our
* patience could withstand */
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " Unable to initialize device after %d attempts. \n " , i ) ;
2007-09-25 17:54:57 -07:00
return - EIO ;
}
/*****************************************************************************
*
* Workqueue callbacks
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-05-29 16:34:54 +08:00
static void iwl_bg_init_alive_start ( struct work_struct * data )
2007-09-25 17:54:57 -07:00
{
2008-03-12 16:58:50 -07:00
struct iwl_priv * priv =
container_of ( data , struct iwl_priv , init_alive_start . work ) ;
2007-09-25 17:54:57 -07:00
if ( test_bit ( STATUS_EXIT_PENDING , & priv - > status ) )
return ;
mutex_lock ( & priv - > mutex ) ;
2008-05-05 10:22:45 +08:00
priv - > cfg - > ops - > lib - > init_alive_start ( priv ) ;
2007-09-25 17:54:57 -07:00
mutex_unlock ( & priv - > mutex ) ;
}
2008-05-29 16:34:54 +08:00
static void iwl_bg_alive_start ( struct work_struct * data )
2007-09-25 17:54:57 -07:00
{
2008-03-12 16:58:50 -07:00
struct iwl_priv * priv =
container_of ( data , struct iwl_priv , alive_start . work ) ;
2007-09-25 17:54:57 -07:00
if ( test_bit ( STATUS_EXIT_PENDING , & priv - > status ) )
return ;
2009-06-03 11:44:10 -07:00
/* enable dram interrupt */
iwl_reset_ict ( priv ) ;
2007-09-25 17:54:57 -07:00
mutex_lock ( & priv - > mutex ) ;
2008-05-29 16:34:54 +08:00
iwl_alive_start ( priv ) ;
2007-09-25 17:54:57 -07:00
mutex_unlock ( & priv - > mutex ) ;
}
2008-06-12 09:46:52 +08:00
static void iwl_bg_run_time_calib_work ( struct work_struct * work )
{
struct iwl_priv * priv = container_of ( work , struct iwl_priv ,
run_time_calib_work ) ;
mutex_lock ( & priv - > mutex ) ;
if ( test_bit ( STATUS_EXIT_PENDING , & priv - > status ) | |
test_bit ( STATUS_SCANNING , & priv - > status ) ) {
mutex_unlock ( & priv - > mutex ) ;
return ;
}
if ( priv - > start_calib ) {
iwl_chain_noise_calibration ( priv , & priv - > statistics ) ;
iwl_sensitivity_calibration ( priv , & priv - > statistics ) ;
}
mutex_unlock ( & priv - > mutex ) ;
return ;
}
2008-10-29 14:05:46 -07:00
static void iwl_bg_up ( struct work_struct * data )
2007-09-25 17:54:57 -07:00
{
2008-03-12 16:58:50 -07:00
struct iwl_priv * priv = container_of ( data , struct iwl_priv , up ) ;
2007-09-25 17:54:57 -07:00
if ( test_bit ( STATUS_EXIT_PENDING , & priv - > status ) )
return ;
mutex_lock ( & priv - > mutex ) ;
2008-10-29 14:05:46 -07:00
__iwl_up ( priv ) ;
2007-09-25 17:54:57 -07:00
mutex_unlock ( & priv - > mutex ) ;
}
2008-10-29 14:05:46 -07:00
static void iwl_bg_restart ( struct work_struct * data )
2007-09-25 17:54:57 -07:00
{
2008-03-12 16:58:50 -07:00
struct iwl_priv * priv = container_of ( data , struct iwl_priv , restart ) ;
2007-09-25 17:54:57 -07:00
if ( test_bit ( STATUS_EXIT_PENDING , & priv - > status ) )
return ;
2009-05-08 13:44:36 -07:00
if ( test_and_clear_bit ( STATUS_FW_ERROR , & priv - > status ) ) {
mutex_lock ( & priv - > mutex ) ;
priv - > vif = NULL ;
priv - > is_open = 0 ;
mutex_unlock ( & priv - > mutex ) ;
iwl_down ( priv ) ;
ieee80211_restart_hw ( priv - > hw ) ;
} else {
iwl_down ( priv ) ;
queue_work ( priv - > workqueue , & priv - > up ) ;
}
2007-09-25 17:54:57 -07:00
}
2008-10-29 14:05:46 -07:00
static void iwl_bg_rx_replenish ( struct work_struct * data )
2007-09-25 17:54:57 -07:00
{
2008-03-12 16:58:50 -07:00
struct iwl_priv * priv =
container_of ( data , struct iwl_priv , rx_replenish ) ;
2007-09-25 17:54:57 -07:00
if ( test_bit ( STATUS_EXIT_PENDING , & priv - > status ) )
return ;
mutex_lock ( & priv - > mutex ) ;
2008-05-05 10:22:28 +08:00
iwl_rx_replenish ( priv ) ;
2007-09-25 17:54:57 -07:00
mutex_unlock ( & priv - > mutex ) ;
}
2007-11-29 11:10:13 +08:00
# define IWL_DELAY_NEXT_SCAN (HZ*2)
2009-04-08 11:26:35 -07:00
void iwl_post_associate ( struct iwl_priv * priv )
2007-09-25 17:54:57 -07:00
{
struct ieee80211_conf * conf = NULL ;
2008-03-21 13:53:44 -07:00
int ret = 0 ;
2008-07-11 11:53:34 +08:00
unsigned long flags ;
2007-09-25 17:54:57 -07:00
2008-09-11 00:01:58 +02:00
if ( priv - > iw_mode = = NL80211_IFTYPE_AP ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " %s Should not be called in AP mode \n " , __func__ ) ;
2007-09-25 17:54:57 -07:00
return ;
}
2009-01-27 14:27:56 -08:00
IWL_DEBUG_ASSOC ( priv , " Associated as %d to: %pM \n " ,
2008-10-27 15:59:26 -07:00
priv - > assoc_id , priv - > active_rxon . bssid_addr ) ;
2007-09-25 17:54:57 -07:00
if ( test_bit ( STATUS_EXIT_PENDING , & priv - > status ) )
return ;
2008-04-14 21:16:13 -07:00
if ( ! priv - > vif | | ! priv - > is_open )
2007-10-25 17:15:45 +08:00
return ;
2008-04-14 21:16:13 -07:00
2008-06-12 09:47:10 +08:00
iwl_scan_cancel_timeout ( priv , 200 ) ;
2007-10-25 17:15:43 +08:00
2007-09-25 17:54:57 -07:00
conf = ieee80211_get_hw_conf ( priv - > hw ) ;
priv - > staging_rxon . filter_flags & = ~ RXON_FILTER_ASSOC_MSK ;
2009-04-08 11:26:37 -07:00
iwlcore_commit_rxon ( priv ) ;
2007-09-25 17:54:57 -07:00
2008-10-08 09:37:30 +08:00
iwl_setup_rxon_timing ( priv ) ;
2008-03-21 13:53:44 -07:00
ret = iwl_send_cmd_pdu ( priv , REPLY_RXON_TIMING ,
2007-09-25 17:54:57 -07:00
sizeof ( priv - > rxon_timing ) , & priv - > rxon_timing ) ;
2008-03-21 13:53:44 -07:00
if ( ret )
2008-12-19 10:37:32 +08:00
IWL_WARN ( priv , " REPLY_RXON_TIMING failed - "
2007-09-25 17:54:57 -07:00
" Attempting to continue. \n " ) ;
priv - > staging_rxon . filter_flags | = RXON_FILTER_ASSOC_MSK ;
2008-09-17 10:10:05 +08:00
iwl_set_rxon_ht ( priv , & priv - > current_ht_config ) ;
2008-06-09 22:54:35 +03:00
2009-04-08 11:26:44 -07:00
if ( priv - > cfg - > ops - > hcmd - > set_rxon_chain )
priv - > cfg - > ops - > hcmd - > set_rxon_chain ( priv ) ;
2007-09-25 17:54:57 -07:00
priv - > staging_rxon . assoc_id = cpu_to_le16 ( priv - > assoc_id ) ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_ASSOC ( priv , " assoc id %d beacon interval %d \n " ,
2007-09-25 17:54:57 -07:00
priv - > assoc_id , priv - > beacon_int ) ;
if ( priv - > assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE )
priv - > staging_rxon . flags | = RXON_FLG_SHORT_PREAMBLE_MSK ;
else
priv - > staging_rxon . flags & = ~ RXON_FLG_SHORT_PREAMBLE_MSK ;
if ( priv - > staging_rxon . flags & RXON_FLG_BAND_24G_MSK ) {
if ( priv - > assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME )
priv - > staging_rxon . flags | = RXON_FLG_SHORT_SLOT_MSK ;
else
priv - > staging_rxon . flags & = ~ RXON_FLG_SHORT_SLOT_MSK ;
2008-09-11 00:01:58 +02:00
if ( priv - > iw_mode = = NL80211_IFTYPE_ADHOC )
2007-09-25 17:54:57 -07:00
priv - > staging_rxon . flags & = ~ RXON_FLG_SHORT_SLOT_MSK ;
}
2009-04-08 11:26:37 -07:00
iwlcore_commit_rxon ( priv ) ;
2007-09-25 17:54:57 -07:00
switch ( priv - > iw_mode ) {
2008-09-11 00:01:58 +02:00
case NL80211_IFTYPE_STATION :
2007-09-25 17:54:57 -07:00
break ;
2008-09-11 00:01:58 +02:00
case NL80211_IFTYPE_ADHOC :
2007-09-25 17:54:57 -07:00
2008-06-12 09:47:05 +08:00
/* assume default assoc id */
priv - > assoc_id = 1 ;
2007-09-25 17:54:57 -07:00
2008-05-15 13:54:04 +08:00
iwl_rxon_add_station ( priv , priv - > bssid , 0 ) ;
2008-10-29 14:05:46 -07:00
iwl_send_beacon_cmd ( priv ) ;
2007-09-25 17:54:57 -07:00
break ;
default :
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " %s Should not be called in %d mode \n " ,
2008-07-21 02:40:14 +03:00
__func__ , priv - > iw_mode ) ;
2007-09-25 17:54:57 -07:00
break ;
}
2008-09-11 00:01:58 +02:00
if ( priv - > iw_mode = = NL80211_IFTYPE_ADHOC )
2007-09-25 17:54:57 -07:00
priv - > assoc_station_added = 1 ;
2008-07-11 11:53:34 +08:00
spin_lock_irqsave ( & priv - > lock , flags ) ;
iwl_activate_qos ( priv , 0 ) ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2008-02-06 11:20:39 -08:00
2008-09-03 11:26:53 +08:00
/* the chain noise calibration will enabled PM upon completion
* If chain noise has already been run , then we need to enable
* power management here */
if ( priv - > chain_noise_data . state = = IWL_CHAIN_NOISE_DONE )
2009-05-08 13:44:38 -07:00
iwl_power_update_mode ( priv , 0 ) ;
2008-09-03 11:26:50 +08:00
/* Enable Rx differential gain and sensitivity calibrations */
iwl_chain_noise_reset ( priv ) ;
priv - > start_calib = 1 ;
2008-04-14 21:16:13 -07:00
}
2007-09-25 17:54:57 -07:00
/*****************************************************************************
*
* mac80211 entry point functions
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-06-30 17:23:24 +08:00
# define UCODE_READY_TIMEOUT (4 * HZ)
2008-01-14 17:46:18 -08:00
2008-10-29 14:05:46 -07:00
static int iwl_mac_start ( struct ieee80211_hw * hw )
2007-09-25 17:54:57 -07:00
{
2008-03-12 16:58:50 -07:00
struct iwl_priv * priv = hw - > priv ;
2008-01-14 17:46:18 -08:00
int ret ;
2007-09-25 17:54:57 -07:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_MAC80211 ( priv , " enter \n " ) ;
2007-09-25 17:54:57 -07:00
/* we should be verifying the device is ready to be opened */
mutex_lock ( & priv - > mutex ) ;
2008-01-14 17:46:18 -08:00
/* fetch ucode file from disk, alloc and copy to bus-master buffers ...
* ucode filename and max sizes are card - specific . */
2007-09-25 17:54:57 -07:00
2008-01-14 17:46:18 -08:00
if ( ! priv - > ucode_code . len ) {
2008-10-29 14:05:46 -07:00
ret = iwl_read_ucode ( priv ) ;
2008-01-14 17:46:18 -08:00
if ( ret ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " Could not read microcode: %d \n " , ret ) ;
2008-01-14 17:46:18 -08:00
mutex_unlock ( & priv - > mutex ) ;
2009-01-19 13:10:07 +01:00
return ret ;
2008-01-14 17:46:18 -08:00
}
}
2007-09-25 17:54:57 -07:00
2008-10-29 14:05:46 -07:00
ret = __iwl_up ( priv ) ;
2008-01-14 17:46:18 -08:00
2007-09-25 17:54:57 -07:00
mutex_unlock ( & priv - > mutex ) ;
2008-01-14 17:46:18 -08:00
2008-01-24 02:19:38 -08:00
if ( ret )
2009-01-19 13:10:07 +01:00
return ret ;
2008-01-24 02:19:38 -08:00
2008-08-04 16:00:43 +08:00
if ( iwl_is_rfkill ( priv ) )
goto out ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " Start UP work done. \n " ) ;
2008-01-24 02:19:38 -08:00
2008-05-29 16:35:06 +08:00
/* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from
2008-01-14 17:46:18 -08:00
* mac80211 will not be run successfully . */
2008-06-30 17:23:24 +08:00
ret = wait_event_interruptible_timeout ( priv - > wait_command_queue ,
test_bit ( STATUS_READY , & priv - > status ) ,
UCODE_READY_TIMEOUT ) ;
if ( ! ret ) {
if ( ! test_bit ( STATUS_READY , & priv - > status ) ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " START_ALIVE timeout after %dms. \n " ,
2008-06-30 17:23:24 +08:00
jiffies_to_msecs ( UCODE_READY_TIMEOUT ) ) ;
2009-01-19 13:10:07 +01:00
return - ETIMEDOUT ;
2008-01-14 17:46:18 -08:00
}
2008-05-29 16:35:06 +08:00
}
2008-06-30 17:23:26 +08:00
2008-08-04 16:00:43 +08:00
out :
2008-06-30 17:23:26 +08:00
priv - > is_open = 1 ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_MAC80211 ( priv , " leave \n " ) ;
2007-09-25 17:54:57 -07:00
return 0 ;
}
2008-10-29 14:05:46 -07:00
static void iwl_mac_stop ( struct ieee80211_hw * hw )
2007-09-25 17:54:57 -07:00
{
2008-03-12 16:58:50 -07:00
struct iwl_priv * priv = hw - > priv ;
2007-09-25 17:54:57 -07:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_MAC80211 ( priv , " enter \n " ) ;
2007-10-25 17:15:45 +08:00
2009-05-08 13:44:36 -07:00
if ( ! priv - > is_open )
2008-01-24 02:19:38 -08:00
return ;
2007-09-25 17:54:57 -07:00
priv - > is_open = 0 ;
2008-01-14 17:46:18 -08:00
2008-04-03 16:05:21 -07:00
if ( iwl_is_ready_rf ( priv ) ) {
2008-01-24 02:19:38 -08:00
/* stop mac, cancel any scan request and clear
* RXON_FILTER_ASSOC_MSK BIT
*/
2008-01-14 17:46:18 -08:00
mutex_lock ( & priv - > mutex ) ;
2008-06-12 09:47:10 +08:00
iwl_scan_cancel_timeout ( priv , 100 ) ;
2007-11-29 11:10:15 +08:00
mutex_unlock ( & priv - > mutex ) ;
}
2008-10-29 14:05:46 -07:00
iwl_down ( priv ) ;
2008-01-14 17:46:18 -08:00
flush_workqueue ( priv - > workqueue ) ;
2009-01-19 13:10:07 +01:00
/* enable interrupts again in order to receive rfkill changes */
iwl_write32 ( priv , CSR_INT , 0xFFFFFFFF ) ;
iwl_enable_interrupts ( priv ) ;
2007-10-25 17:15:45 +08:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_MAC80211 ( priv , " leave \n " ) ;
2007-09-25 17:54:57 -07:00
}
2008-10-29 14:05:46 -07:00
static int iwl_mac_tx ( struct ieee80211_hw * hw , struct sk_buff * skb )
2007-09-25 17:54:57 -07:00
{
2008-03-12 16:58:50 -07:00
struct iwl_priv * priv = hw - > priv ;
2007-09-25 17:54:57 -07:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_MACDUMP ( priv , " enter \n " ) ;
2007-09-25 17:54:57 -07:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_TX ( priv , " dev->xmit(%d bytes) at rate 0x%02x \n " , skb - > len ,
2008-05-15 12:55:29 +02:00
ieee80211_get_tx_rate ( hw , IEEE80211_SKB_CB ( skb ) ) - > bitrate ) ;
2007-09-25 17:54:57 -07:00
2008-05-15 12:55:29 +02:00
if ( iwl_tx_skb ( priv , skb ) )
2007-09-25 17:54:57 -07:00
dev_kfree_skb_any ( skb ) ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_MACDUMP ( priv , " leave \n " ) ;
2009-01-19 15:30:32 -08:00
return NETDEV_TX_OK ;
2007-09-25 17:54:57 -07:00
}
2009-04-08 11:26:49 -07:00
void iwl_config_ap ( struct iwl_priv * priv )
2007-09-25 17:54:57 -07:00
{
2008-03-21 13:53:44 -07:00
int ret = 0 ;
2008-07-11 11:53:34 +08:00
unsigned long flags ;
2007-09-25 17:54:57 -07:00
2008-01-23 10:15:16 -08:00
if ( test_bit ( STATUS_EXIT_PENDING , & priv - > status ) )
2007-09-25 17:54:57 -07:00
return ;
/* The following should be done only at AP bring up */
2008-10-08 09:37:30 +08:00
if ( ! iwl_is_associated ( priv ) ) {
2007-09-25 17:54:57 -07:00
/* RXON - unassoc (to set timing command) */
priv - > staging_rxon . filter_flags & = ~ RXON_FILTER_ASSOC_MSK ;
2009-04-08 11:26:37 -07:00
iwlcore_commit_rxon ( priv ) ;
2007-09-25 17:54:57 -07:00
/* RXON Timing */
2008-10-08 09:37:30 +08:00
iwl_setup_rxon_timing ( priv ) ;
2008-03-21 13:53:44 -07:00
ret = iwl_send_cmd_pdu ( priv , REPLY_RXON_TIMING ,
2007-09-25 17:54:57 -07:00
sizeof ( priv - > rxon_timing ) , & priv - > rxon_timing ) ;
2008-03-21 13:53:44 -07:00
if ( ret )
2008-12-19 10:37:32 +08:00
IWL_WARN ( priv , " REPLY_RXON_TIMING failed - "
2007-09-25 17:54:57 -07:00
" Attempting to continue. \n " ) ;
2009-04-08 11:26:44 -07:00
if ( priv - > cfg - > ops - > hcmd - > set_rxon_chain )
priv - > cfg - > ops - > hcmd - > set_rxon_chain ( priv ) ;
2007-09-25 17:54:57 -07:00
/* FIXME: what should be the assoc_id for AP? */
priv - > staging_rxon . assoc_id = cpu_to_le16 ( priv - > assoc_id ) ;
if ( priv - > assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE )
priv - > staging_rxon . flags | =
RXON_FLG_SHORT_PREAMBLE_MSK ;
else
priv - > staging_rxon . flags & =
~ RXON_FLG_SHORT_PREAMBLE_MSK ;
if ( priv - > staging_rxon . flags & RXON_FLG_BAND_24G_MSK ) {
if ( priv - > assoc_capability &
WLAN_CAPABILITY_SHORT_SLOT_TIME )
priv - > staging_rxon . flags | =
RXON_FLG_SHORT_SLOT_MSK ;
else
priv - > staging_rxon . flags & =
~ RXON_FLG_SHORT_SLOT_MSK ;
2008-09-11 00:01:58 +02:00
if ( priv - > iw_mode = = NL80211_IFTYPE_ADHOC )
2007-09-25 17:54:57 -07:00
priv - > staging_rxon . flags & =
~ RXON_FLG_SHORT_SLOT_MSK ;
}
/* restore RXON assoc */
priv - > staging_rxon . filter_flags | = RXON_FILTER_ASSOC_MSK ;
2009-04-08 11:26:37 -07:00
iwlcore_commit_rxon ( priv ) ;
2008-07-11 11:53:34 +08:00
spin_lock_irqsave ( & priv - > lock , flags ) ;
iwl_activate_qos ( priv , 1 ) ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2008-05-15 13:54:04 +08:00
iwl_rxon_add_station ( priv , iwl_bcast_addr , 0 ) ;
2007-09-27 11:27:32 +08:00
}
2008-10-29 14:05:46 -07:00
iwl_send_beacon_cmd ( priv ) ;
2007-09-25 17:54:57 -07:00
/* FIXME - we need to add code here to detect a totally new
* configuration , reset the AP , unassoc , rxon timing , assoc ,
* clear sta table , add BCAST sta . . . */
}
2008-10-29 14:05:46 -07:00
static void iwl_mac_update_tkip_key ( struct ieee80211_hw * hw ,
2008-03-20 15:06:43 +02:00
struct ieee80211_key_conf * keyconf , const u8 * addr ,
u32 iv32 , u16 * phase1key )
{
2008-11-12 13:14:05 -08:00
struct iwl_priv * priv = hw - > priv ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_MAC80211 ( priv , " enter \n " ) ;
2008-03-20 15:06:43 +02:00
2008-11-12 13:14:05 -08:00
iwl_update_tkip_key ( priv , keyconf , addr , iv32 , phase1key ) ;
2008-03-20 15:06:43 +02:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_MAC80211 ( priv , " leave \n " ) ;
2008-03-20 15:06:43 +02:00
}
2008-10-29 14:05:46 -07:00
static int iwl_mac_set_key ( struct ieee80211_hw * hw , enum set_key_cmd cmd ,
2008-12-29 12:55:09 +01:00
struct ieee80211_vif * vif ,
struct ieee80211_sta * sta ,
2007-09-25 17:54:57 -07:00
struct ieee80211_key_conf * key )
{
2008-03-12 16:58:50 -07:00
struct iwl_priv * priv = hw - > priv ;
2009-01-19 15:30:22 -08:00
const u8 * addr ;
int ret ;
u8 sta_id ;
bool is_default_wep_key = false ;
2007-09-25 17:54:57 -07:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_MAC80211 ( priv , " enter \n " ) ;
2007-09-25 17:54:57 -07:00
2008-04-21 15:41:53 -07:00
if ( priv - > hw_params . sw_crypto ) {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_MAC80211 ( priv , " leave - hwcrypto disabled \n " ) ;
2007-09-25 17:54:57 -07:00
return - EOPNOTSUPP ;
}
2009-01-19 15:30:22 -08:00
addr = sta ? sta - > addr : iwl_bcast_addr ;
2009-06-03 11:44:07 -07:00
sta_id = iwl_find_station ( priv , addr ) ;
2008-04-14 21:16:06 -07:00
if ( sta_id = = IWL_INVALID_STATION ) {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_MAC80211 ( priv , " leave - %pM not in station map. \n " ,
2008-10-27 15:59:26 -07:00
addr ) ;
2008-04-14 21:16:06 -07:00
return - EINVAL ;
2007-09-25 17:54:57 -07:00
2008-03-19 16:41:41 -07:00
}
2007-09-25 17:54:57 -07:00
2008-04-14 21:16:06 -07:00
mutex_lock ( & priv - > mutex ) ;
2008-06-12 09:47:10 +08:00
iwl_scan_cancel_timeout ( priv , 100 ) ;
2008-04-14 21:16:06 -07:00
mutex_unlock ( & priv - > mutex ) ;
/* If we are getting WEP group key and we didn't receive any key mapping
* so far , we are in legacy wep mode ( group key only ) , otherwise we are
* in 1 X mode .
* In legacy wep mode , we use another host command to the uCode */
2008-04-15 16:01:38 -07:00
if ( key - > alg = = ALG_WEP & & sta_id = = priv - > hw_params . bcast_sta_id & &
2008-09-11 00:01:58 +02:00
priv - > iw_mode ! = NL80211_IFTYPE_AP ) {
2008-04-14 21:16:06 -07:00
if ( cmd = = SET_KEY )
is_default_wep_key = ! priv - > key_mapping_key ;
else
2008-05-15 13:54:09 +08:00
is_default_wep_key =
( key - > hw_key_idx = = HW_KEY_DEFAULT ) ;
2008-04-14 21:16:06 -07:00
}
2007-10-25 17:15:43 +08:00
2007-09-25 17:54:57 -07:00
switch ( cmd ) {
2008-03-19 16:41:41 -07:00
case SET_KEY :
2008-04-14 21:16:06 -07:00
if ( is_default_wep_key )
ret = iwl_set_default_wep_key ( priv , key ) ;
2008-03-19 16:41:41 -07:00
else
2008-04-14 21:16:09 -07:00
ret = iwl_set_dynamic_key ( priv , key , sta_id ) ;
2008-03-19 16:41:41 -07:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_MAC80211 ( priv , " enable hwcrypto key \n " ) ;
2007-09-25 17:54:57 -07:00
break ;
case DISABLE_KEY :
2008-04-14 21:16:06 -07:00
if ( is_default_wep_key )
ret = iwl_remove_default_wep_key ( priv , key ) ;
2008-03-19 16:41:41 -07:00
else
2008-04-17 16:03:36 -07:00
ret = iwl_remove_dynamic_key ( priv , key , sta_id ) ;
2008-03-19 16:41:41 -07:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_MAC80211 ( priv , " disable hwcrypto key \n " ) ;
2007-09-25 17:54:57 -07:00
break ;
default :
2008-03-19 16:41:41 -07:00
ret = - EINVAL ;
2007-09-25 17:54:57 -07:00
}
2009-01-27 14:27:56 -08:00
IWL_DEBUG_MAC80211 ( priv , " leave \n " ) ;
2007-09-25 17:54:57 -07:00
2008-03-19 16:41:41 -07:00
return ret ;
2007-09-25 17:54:57 -07:00
}
2008-10-29 14:05:46 -07:00
static int iwl_mac_ampdu_action ( struct ieee80211_hw * hw ,
2008-07-18 13:53:02 +08:00
enum ieee80211_ampdu_mlme_action action ,
2008-09-11 00:02:02 +02:00
struct ieee80211_sta * sta , u16 tid , u16 * ssn )
2008-07-18 13:53:02 +08:00
{
struct iwl_priv * priv = hw - > priv ;
2009-03-17 21:51:43 -07:00
int ret ;
2008-07-18 13:53:02 +08:00
2009-01-27 14:27:56 -08:00
IWL_DEBUG_HT ( priv , " A-MPDU action on addr %pM tid %d \n " ,
2008-10-27 15:59:26 -07:00
sta - > addr , tid ) ;
2008-07-18 13:53:02 +08:00
if ( ! ( priv - > cfg - > sku & IWL_SKU_N ) )
return - EACCES ;
switch ( action ) {
case IEEE80211_AMPDU_RX_START :
2009-01-27 14:27:56 -08:00
IWL_DEBUG_HT ( priv , " start Rx \n " ) ;
2008-11-12 13:14:05 -08:00
return iwl_sta_rx_agg_start ( priv , sta - > addr , tid , * ssn ) ;
2008-07-18 13:53:02 +08:00
case IEEE80211_AMPDU_RX_STOP :
2009-01-27 14:27:56 -08:00
IWL_DEBUG_HT ( priv , " stop Rx \n " ) ;
2009-03-17 21:51:43 -07:00
ret = iwl_sta_rx_agg_stop ( priv , sta - > addr , tid ) ;
if ( test_bit ( STATUS_EXIT_PENDING , & priv - > status ) )
return 0 ;
else
return ret ;
2008-07-18 13:53:02 +08:00
case IEEE80211_AMPDU_TX_START :
2009-01-27 14:27:56 -08:00
IWL_DEBUG_HT ( priv , " start Tx \n " ) ;
2008-09-11 00:02:02 +02:00
return iwl_tx_agg_start ( priv , sta - > addr , tid , ssn ) ;
2008-07-18 13:53:02 +08:00
case IEEE80211_AMPDU_TX_STOP :
2009-01-27 14:27:56 -08:00
IWL_DEBUG_HT ( priv , " stop Tx \n " ) ;
2009-03-17 21:51:43 -07:00
ret = iwl_tx_agg_stop ( priv , sta - > addr , tid ) ;
if ( test_bit ( STATUS_EXIT_PENDING , & priv - > status ) )
return 0 ;
else
return ret ;
2008-07-18 13:53:02 +08:00
default :
2009-01-27 14:27:56 -08:00
IWL_DEBUG_HT ( priv , " unknown \n " ) ;
2008-07-18 13:53:02 +08:00
return - EINVAL ;
break ;
}
return 0 ;
}
2008-11-12 13:14:05 -08:00
2008-10-29 14:05:46 -07:00
static int iwl_mac_get_stats ( struct ieee80211_hw * hw ,
2007-09-25 17:54:57 -07:00
struct ieee80211_low_level_stats * stats )
{
2008-05-05 10:22:40 +08:00
struct iwl_priv * priv = hw - > priv ;
priv = hw - > priv ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_MAC80211 ( priv , " enter \n " ) ;
IWL_DEBUG_MAC80211 ( priv , " leave \n " ) ;
2007-09-25 17:54:57 -07:00
return 0 ;
}
/*****************************************************************************
*
* sysfs attributes
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-03-12 16:58:49 -07:00
# ifdef CONFIG_IWLWIFI_DEBUG
2007-09-25 17:54:57 -07:00
/*
* The following adds a new attribute to the sysfs representation
2008-12-17 16:52:29 +08:00
* of this device driver ( i . e . a new file in / sys / class / net / wlan0 / device / )
2007-09-25 17:54:57 -07:00
* used for controlling the debug level .
*
* See the level definitions in iwl for details .
*/
2008-05-06 11:05:11 +08:00
static ssize_t show_debug_level ( struct device * d ,
struct device_attribute * attr , char * buf )
2007-09-25 17:54:57 -07:00
{
2009-04-30 23:02:47 -07:00
struct iwl_priv * priv = dev_get_drvdata ( d ) ;
2008-05-06 11:05:11 +08:00
return sprintf ( buf , " 0x%08X \n " , priv - > debug_level ) ;
2007-09-25 17:54:57 -07:00
}
2008-05-06 11:05:11 +08:00
static ssize_t store_debug_level ( struct device * d ,
struct device_attribute * attr ,
2007-09-25 17:54:57 -07:00
const char * buf , size_t count )
{
2009-04-30 23:02:47 -07:00
struct iwl_priv * priv = dev_get_drvdata ( d ) ;
2008-09-03 11:26:32 +08:00
unsigned long val ;
int ret ;
2007-09-25 17:54:57 -07:00
2008-09-03 11:26:32 +08:00
ret = strict_strtoul ( buf , 0 , & val ) ;
if ( ret )
2008-12-19 10:37:31 +08:00
IWL_ERR ( priv , " %s is not in hex or decimal form. \n " , buf ) ;
2007-09-25 17:54:57 -07:00
else
2008-05-06 11:05:11 +08:00
priv - > debug_level = val ;
2007-09-25 17:54:57 -07:00
return strnlen ( buf , count ) ;
}
2008-05-06 11:05:11 +08:00
static DEVICE_ATTR ( debug_level , S_IWUSR | S_IRUGO ,
show_debug_level , store_debug_level ) ;
2007-09-25 17:54:57 -07:00
2008-03-12 16:58:49 -07:00
# endif /* CONFIG_IWLWIFI_DEBUG */
2007-09-25 17:54:57 -07:00
2008-05-06 11:05:13 +08:00
static ssize_t show_version ( struct device * d ,
struct device_attribute * attr , char * buf )
{
2009-04-30 23:02:47 -07:00
struct iwl_priv * priv = dev_get_drvdata ( d ) ;
2008-05-29 16:34:55 +08:00
struct iwl_alive_resp * palive = & priv - > card_alive ;
2008-06-30 17:23:02 +08:00
ssize_t pos = 0 ;
u16 eeprom_ver ;
2008-05-06 11:05:13 +08:00
if ( palive - > is_valid )
2008-06-30 17:23:02 +08:00
pos + = sprintf ( buf + pos ,
" fw version: 0x%01X.0x%01X.0x%01X.0x%01X \n "
" fw type: 0x%01X 0x%01X \n " ,
2008-05-06 11:05:13 +08:00
palive - > ucode_major , palive - > ucode_minor ,
palive - > sw_rev [ 0 ] , palive - > sw_rev [ 1 ] ,
palive - > ver_type , palive - > ver_subtype ) ;
else
2008-06-30 17:23:02 +08:00
pos + = sprintf ( buf + pos , " fw not loaded \n " ) ;
if ( priv - > eeprom ) {
eeprom_ver = iwl_eeprom_query16 ( priv , EEPROM_VERSION ) ;
2009-05-22 11:01:46 -07:00
pos + = sprintf ( buf + pos , " NVM Type: %s, version: 0x%x \n " ,
( priv - > nvm_device_type = = NVM_DEVICE_TYPE_OTP )
? " OTP " : " EEPROM " , eeprom_ver ) ;
2008-06-30 17:23:02 +08:00
} else {
pos + = sprintf ( buf + pos , " EEPROM not initialzed \n " ) ;
}
return pos ;
2008-05-06 11:05:13 +08:00
}
static DEVICE_ATTR ( version , S_IWUSR | S_IRUGO , show_version , NULL ) ;
2007-09-25 17:54:57 -07:00
static ssize_t show_temperature ( struct device * d ,
struct device_attribute * attr , char * buf )
{
2009-04-30 23:02:47 -07:00
struct iwl_priv * priv = dev_get_drvdata ( d ) ;
2007-09-25 17:54:57 -07:00
2008-04-03 16:05:21 -07:00
if ( ! iwl_is_alive ( priv ) )
2007-09-25 17:54:57 -07:00
return - EAGAIN ;
2008-06-12 09:47:14 +08:00
return sprintf ( buf , " %d \n " , priv - > temperature ) ;
2007-09-25 17:54:57 -07:00
}
static DEVICE_ATTR ( temperature , S_IRUGO , show_temperature , NULL ) ;
static ssize_t show_tx_power ( struct device * d ,
struct device_attribute * attr , char * buf )
{
2009-04-30 23:02:47 -07:00
struct iwl_priv * priv = dev_get_drvdata ( d ) ;
2008-12-17 16:52:34 +08:00
if ( ! iwl_is_ready_rf ( priv ) )
return sprintf ( buf , " off \n " ) ;
else
return sprintf ( buf , " %d \n " , priv - > tx_power_user_lmt ) ;
2007-09-25 17:54:57 -07:00
}
static ssize_t store_tx_power ( struct device * d ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
2009-04-30 23:02:47 -07:00
struct iwl_priv * priv = dev_get_drvdata ( d ) ;
2008-09-03 11:26:32 +08:00
unsigned long val ;
int ret ;
2007-09-25 17:54:57 -07:00
2008-09-03 11:26:32 +08:00
ret = strict_strtoul ( buf , 10 , & val ) ;
if ( ret )
2008-12-19 10:37:31 +08:00
IWL_INFO ( priv , " %s is not in decimal form. \n " , buf ) ;
2007-09-25 17:54:57 -07:00
else
2008-06-12 09:47:08 +08:00
iwl_set_tx_power ( priv , val , false ) ;
2007-09-25 17:54:57 -07:00
return count ;
}
static DEVICE_ATTR ( tx_power , S_IWUSR | S_IRUGO , show_tx_power , store_tx_power ) ;
static ssize_t show_flags ( struct device * d ,
struct device_attribute * attr , char * buf )
{
2009-04-30 23:02:47 -07:00
struct iwl_priv * priv = dev_get_drvdata ( d ) ;
2007-09-25 17:54:57 -07:00
return sprintf ( buf , " 0x%04X \n " , priv - > active_rxon . flags ) ;
}
static ssize_t store_flags ( struct device * d ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
2009-04-30 23:02:47 -07:00
struct iwl_priv * priv = dev_get_drvdata ( d ) ;
2008-09-03 11:26:32 +08:00
unsigned long val ;
u32 flags ;
int ret = strict_strtoul ( buf , 0 , & val ) ;
2008-09-03 11:26:39 +08:00
if ( ret )
2008-09-03 11:26:32 +08:00
return ret ;
flags = ( u32 ) val ;
2007-09-25 17:54:57 -07:00
mutex_lock ( & priv - > mutex ) ;
if ( le32_to_cpu ( priv - > staging_rxon . flags ) ! = flags ) {
/* Cancel any currently running scans... */
2008-06-12 09:47:10 +08:00
if ( iwl_scan_cancel_timeout ( priv , 100 ) )
2008-12-19 10:37:32 +08:00
IWL_WARN ( priv , " Could not cancel scan. \n " ) ;
2007-09-25 17:54:57 -07:00
else {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " Commit rxon.flags = 0x%04X \n " , flags ) ;
2007-09-25 17:54:57 -07:00
priv - > staging_rxon . flags = cpu_to_le32 ( flags ) ;
2009-04-08 11:26:37 -07:00
iwlcore_commit_rxon ( priv ) ;
2007-09-25 17:54:57 -07:00
}
}
mutex_unlock ( & priv - > mutex ) ;
return count ;
}
static DEVICE_ATTR ( flags , S_IWUSR | S_IRUGO , show_flags , store_flags ) ;
static ssize_t show_filter_flags ( struct device * d ,
struct device_attribute * attr , char * buf )
{
2009-04-30 23:02:47 -07:00
struct iwl_priv * priv = dev_get_drvdata ( d ) ;
2007-09-25 17:54:57 -07:00
return sprintf ( buf , " 0x%04X \n " ,
le32_to_cpu ( priv - > active_rxon . filter_flags ) ) ;
}
static ssize_t store_filter_flags ( struct device * d ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
2009-04-30 23:02:47 -07:00
struct iwl_priv * priv = dev_get_drvdata ( d ) ;
2008-09-03 11:26:32 +08:00
unsigned long val ;
u32 filter_flags ;
int ret = strict_strtoul ( buf , 0 , & val ) ;
2008-09-03 11:26:39 +08:00
if ( ret )
2008-09-03 11:26:32 +08:00
return ret ;
filter_flags = ( u32 ) val ;
2007-09-25 17:54:57 -07:00
mutex_lock ( & priv - > mutex ) ;
if ( le32_to_cpu ( priv - > staging_rxon . filter_flags ) ! = filter_flags ) {
/* Cancel any currently running scans... */
2008-06-12 09:47:10 +08:00
if ( iwl_scan_cancel_timeout ( priv , 100 ) )
2008-12-19 10:37:32 +08:00
IWL_WARN ( priv , " Could not cancel scan. \n " ) ;
2007-09-25 17:54:57 -07:00
else {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " Committing rxon.filter_flags = "
2007-09-25 17:54:57 -07:00
" 0x%04X \n " , filter_flags ) ;
priv - > staging_rxon . filter_flags =
cpu_to_le32 ( filter_flags ) ;
2009-04-08 11:26:37 -07:00
iwlcore_commit_rxon ( priv ) ;
2007-09-25 17:54:57 -07:00
}
}
mutex_unlock ( & priv - > mutex ) ;
return count ;
}
static DEVICE_ATTR ( filter_flags , S_IWUSR | S_IRUGO , show_filter_flags ,
store_filter_flags ) ;
static ssize_t store_power_level ( struct device * d ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
2008-03-12 16:58:50 -07:00
struct iwl_priv * priv = dev_get_drvdata ( d ) ;
2008-07-18 13:52:58 +08:00
int ret ;
2008-09-03 11:26:32 +08:00
unsigned long mode ;
2007-09-25 17:54:57 -07:00
mutex_lock ( & priv - > mutex ) ;
2008-09-03 11:26:32 +08:00
ret = strict_strtoul ( buf , 10 , & mode ) ;
2008-09-03 11:26:39 +08:00
if ( ret )
2008-09-03 11:26:32 +08:00
goto out ;
2008-07-18 13:52:58 +08:00
ret = iwl_power_set_user_mode ( priv , mode ) ;
if ( ret ) {
2009-01-27 14:27:56 -08:00
IWL_DEBUG_MAC80211 ( priv , " failed setting power mode. \n " ) ;
2008-04-21 15:41:51 -07:00
goto out ;
2007-09-25 17:54:57 -07:00
}
2008-07-18 13:52:58 +08:00
ret = count ;
2007-09-25 17:54:57 -07:00
out :
mutex_unlock ( & priv - > mutex ) ;
2008-07-18 13:52:58 +08:00
return ret ;
2007-09-25 17:54:57 -07:00
}
static ssize_t show_power_level ( struct device * d ,
struct device_attribute * attr , char * buf )
{
2008-03-12 16:58:50 -07:00
struct iwl_priv * priv = dev_get_drvdata ( d ) ;
2008-07-18 13:52:58 +08:00
int mode = priv - > power_data . user_power_setting ;
2008-04-21 15:41:51 -07:00
int level = priv - > power_data . power_mode ;
2007-09-25 17:54:57 -07:00
char * p = buf ;
2009-05-08 13:44:38 -07:00
p + = sprintf ( p , " INDEX:%d \t " , level ) ;
p + = sprintf ( p , " USER:%d \n " , mode ) ;
2008-07-21 02:40:14 +03:00
return p - buf + 1 ;
2007-09-25 17:54:57 -07:00
}
static DEVICE_ATTR ( power_level , S_IWUSR | S_IRUSR , show_power_level ,
store_power_level ) ;
2009-05-08 13:44:44 -07:00
static ssize_t show_qos ( struct device * d ,
struct device_attribute * attr , char * buf )
{
2009-05-17 11:28:42 +02:00
struct iwl_priv * priv = dev_get_drvdata ( d ) ;
2009-05-08 13:44:44 -07:00
char * p = buf ;
int q ;
for ( q = 0 ; q < AC_NUM ; q + + ) {
p + = sprintf ( p , " \t cw_min \t cw_max \t aifsn \t txop \n " ) ;
p + = sprintf ( p , " AC[%d] \t %u \t %u \t %u \t %u \n " , q ,
priv - > qos_data . def_qos_parm . ac [ q ] . cw_min ,
priv - > qos_data . def_qos_parm . ac [ q ] . cw_max ,
priv - > qos_data . def_qos_parm . ac [ q ] . aifsn ,
priv - > qos_data . def_qos_parm . ac [ q ] . edca_txop ) ;
}
return p - buf + 1 ;
}
static DEVICE_ATTR ( qos , S_IRUGO , show_qos , NULL ) ;
2007-09-25 17:54:57 -07:00
static ssize_t show_statistics ( struct device * d ,
struct device_attribute * attr , char * buf )
{
2008-03-12 16:58:50 -07:00
struct iwl_priv * priv = dev_get_drvdata ( d ) ;
2008-06-30 17:23:07 +08:00
u32 size = sizeof ( struct iwl_notif_statistics ) ;
2007-09-25 17:54:57 -07:00
u32 len = 0 , ofs = 0 ;
2008-07-21 02:40:14 +03:00
u8 * data = ( u8 * ) & priv - > statistics ;
2007-09-25 17:54:57 -07:00
int rc = 0 ;
2008-04-03 16:05:21 -07:00
if ( ! iwl_is_alive ( priv ) )
2007-09-25 17:54:57 -07:00
return - EAGAIN ;
mutex_lock ( & priv - > mutex ) ;
2008-04-15 16:01:37 -07:00
rc = iwl_send_statistics_request ( priv , 0 ) ;
2007-09-25 17:54:57 -07:00
mutex_unlock ( & priv - > mutex ) ;
if ( rc ) {
len = sprintf ( buf ,
" Error sending statistics request: 0x%08X \n " , rc ) ;
return len ;
}
while ( size & & ( PAGE_SIZE - len ) ) {
hex_dump_to_buffer ( data + ofs , size , 16 , 1 , buf + len ,
PAGE_SIZE - len , 1 ) ;
len = strlen ( buf ) ;
if ( PAGE_SIZE - len )
buf [ len + + ] = ' \n ' ;
ofs + = 16 ;
size - = min ( size , 16U ) ;
}
return len ;
}
static DEVICE_ATTR ( statistics , S_IRUGO , show_statistics , NULL ) ;
/*****************************************************************************
*
* driver setup and teardown
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-06-12 09:46:53 +08:00
static void iwl_setup_deferred_work ( struct iwl_priv * priv )
2007-09-25 17:54:57 -07:00
{
2009-02-13 11:51:18 -08:00
priv - > workqueue = create_singlethread_workqueue ( DRV_NAME ) ;
2007-09-25 17:54:57 -07:00
init_waitqueue_head ( & priv - > wait_command_queue ) ;
2008-10-29 14:05:46 -07:00
INIT_WORK ( & priv - > up , iwl_bg_up ) ;
INIT_WORK ( & priv - > restart , iwl_bg_restart ) ;
INIT_WORK ( & priv - > rx_replenish , iwl_bg_rx_replenish ) ;
INIT_WORK ( & priv - > beacon_update , iwl_bg_beacon_update ) ;
2008-06-12 09:46:52 +08:00
INIT_WORK ( & priv - > run_time_calib_work , iwl_bg_run_time_calib_work ) ;
2008-05-29 16:34:54 +08:00
INIT_DELAYED_WORK ( & priv - > init_alive_start , iwl_bg_init_alive_start ) ;
INIT_DELAYED_WORK ( & priv - > alive_start , iwl_bg_alive_start ) ;
2008-06-12 09:47:10 +08:00
iwl_setup_scan_deferred_work ( priv ) ;
2008-01-27 16:41:47 -08:00
2008-06-12 09:46:53 +08:00
if ( priv - > cfg - > ops - > lib - > setup_deferred_work )
priv - > cfg - > ops - > lib - > setup_deferred_work ( priv ) ;
init_timer ( & priv - > statistics_periodic ) ;
priv - > statistics_periodic . data = ( unsigned long ) priv ;
2008-10-29 14:05:46 -07:00
priv - > statistics_periodic . function = iwl_bg_statistics_periodic ;
2007-09-25 17:54:57 -07:00
2009-05-22 11:01:50 -07:00
if ( ! priv - > cfg - > use_isr_legacy )
tasklet_init ( & priv - > irq_tasklet , ( void ( * ) ( unsigned long ) )
iwl_irq_tasklet , ( unsigned long ) priv ) ;
else
tasklet_init ( & priv - > irq_tasklet , ( void ( * ) ( unsigned long ) )
iwl_irq_tasklet_legacy , ( unsigned long ) priv ) ;
2007-09-25 17:54:57 -07:00
}
2008-06-12 09:46:53 +08:00
static void iwl_cancel_deferred_work ( struct iwl_priv * priv )
2007-09-25 17:54:57 -07:00
{
2008-06-12 09:46:53 +08:00
if ( priv - > cfg - > ops - > lib - > cancel_deferred_work )
priv - > cfg - > ops - > lib - > cancel_deferred_work ( priv ) ;
2007-09-25 17:54:57 -07:00
2007-11-29 10:43:16 +09:00
cancel_delayed_work_sync ( & priv - > init_alive_start ) ;
2007-09-25 17:54:57 -07:00
cancel_delayed_work ( & priv - > scan_check ) ;
cancel_delayed_work ( & priv - > alive_start ) ;
cancel_work_sync ( & priv - > beacon_update ) ;
2008-06-12 09:46:53 +08:00
del_timer_sync ( & priv - > statistics_periodic ) ;
2007-09-25 17:54:57 -07:00
}
2008-10-29 14:05:46 -07:00
static struct attribute * iwl_sysfs_entries [ ] = {
2007-09-25 17:54:57 -07:00
& dev_attr_flags . attr ,
& dev_attr_filter_flags . attr ,
& dev_attr_power_level . attr ,
& dev_attr_statistics . attr ,
& dev_attr_temperature . attr ,
& dev_attr_tx_power . attr ,
2008-05-06 11:05:11 +08:00
# ifdef CONFIG_IWLWIFI_DEBUG
& dev_attr_debug_level . attr ,
# endif
2008-05-06 11:05:13 +08:00
& dev_attr_version . attr ,
2009-05-08 13:44:44 -07:00
& dev_attr_qos . attr ,
2007-09-25 17:54:57 -07:00
NULL
} ;
2008-10-29 14:05:46 -07:00
static struct attribute_group iwl_attribute_group = {
2007-09-25 17:54:57 -07:00
. name = NULL , /* put in device directory */
2008-10-29 14:05:46 -07:00
. attrs = iwl_sysfs_entries ,
2007-09-25 17:54:57 -07:00
} ;
2008-10-29 14:05:46 -07:00
static struct ieee80211_ops iwl_hw_ops = {
. tx = iwl_mac_tx ,
. start = iwl_mac_start ,
. stop = iwl_mac_stop ,
. add_interface = iwl_mac_add_interface ,
. remove_interface = iwl_mac_remove_interface ,
. config = iwl_mac_config ,
. configure_filter = iwl_configure_filter ,
. set_key = iwl_mac_set_key ,
. update_tkip_key = iwl_mac_update_tkip_key ,
. get_stats = iwl_mac_get_stats ,
. get_tx_stats = iwl_mac_get_tx_stats ,
. conf_tx = iwl_mac_conf_tx ,
. reset_tsf = iwl_mac_reset_tsf ,
. bss_info_changed = iwl_bss_info_changed ,
. ampdu_action = iwl_mac_ampdu_action ,
2008-09-03 11:26:23 +08:00
. hw_scan = iwl_mac_hw_scan
2007-09-25 17:54:57 -07:00
} ;
2008-10-29 14:05:46 -07:00
static int iwl_pci_probe ( struct pci_dev * pdev , const struct pci_device_id * ent )
2007-09-25 17:54:57 -07:00
{
int err = 0 ;
2008-03-12 16:58:50 -07:00
struct iwl_priv * priv ;
2007-09-25 17:54:57 -07:00
struct ieee80211_hw * hw ;
2008-03-04 18:09:30 -08:00
struct iwl_cfg * cfg = ( struct iwl_cfg * ) ( ent - > driver_data ) ;
2008-03-28 16:21:08 -07:00
unsigned long flags ;
2009-01-19 13:10:07 +01:00
u16 pci_cmd ;
2007-09-25 17:54:57 -07:00
2008-03-14 10:38:46 -07:00
/************************
* 1. Allocating HW data
* * * * * * * * * * * * * * * * * * * * * * * */
2007-11-29 11:09:55 +08:00
/* Disabling hardware scan means that mac80211 will perform scans
* " the hard way " , rather than using device ' s scan . */
2008-03-18 14:57:50 -07:00
if ( cfg - > mod_params - > disable_hw_scan ) {
2008-05-05 10:22:40 +08:00
if ( cfg - > mod_params - > debug & IWL_DL_INFO )
dev_printk ( KERN_DEBUG , & ( pdev - > dev ) ,
" Disabling hw_scan \n " ) ;
2008-10-29 14:05:46 -07:00
iwl_hw_ops . hw_scan = NULL ;
2007-09-25 17:54:57 -07:00
}
2008-10-29 14:05:46 -07:00
hw = iwl_alloc_all ( cfg , & iwl_hw_ops ) ;
2008-03-14 10:38:48 -07:00
if ( ! hw ) {
2007-09-25 17:54:57 -07:00
err = - ENOMEM ;
goto out ;
}
2008-03-14 10:38:48 -07:00
priv = hw - > priv ;
/* At this point both hw and priv are allocated. */
2007-09-25 17:54:57 -07:00
SET_IEEE80211_DEV ( hw , & pdev - > dev ) ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " *** LOAD DRIVER *** \n " ) ;
2008-03-04 18:09:30 -08:00
priv - > cfg = cfg ;
2007-09-25 17:54:57 -07:00
priv - > pci_dev = pdev ;
2009-05-22 11:01:52 -07:00
priv - > inta_mask = CSR_INI_SET_MASK ;
2008-03-14 10:38:46 -07:00
2008-03-12 16:58:49 -07:00
# ifdef CONFIG_IWLWIFI_DEBUG
2008-05-05 10:22:40 +08:00
priv - > debug_level = priv - > cfg - > mod_params - > debug ;
2007-09-25 17:54:57 -07:00
atomic_set ( & priv - > restrict_refcnt , 0 ) ;
# endif
2008-03-14 10:38:46 -07:00
/**************************
* 2. Initializing PCI bus
* * * * * * * * * * * * * * * * * * * * * * * * * */
if ( pci_enable_device ( pdev ) ) {
err = - ENODEV ;
goto out_ieee80211_free_hw ;
}
pci_set_master ( pdev ) ;
2008-09-26 15:09:34 +08:00
err = pci_set_dma_mask ( pdev , DMA_BIT_MASK ( 36 ) ) ;
2008-03-14 10:38:46 -07:00
if ( ! err )
2008-09-26 15:09:34 +08:00
err = pci_set_consistent_dma_mask ( pdev , DMA_BIT_MASK ( 36 ) ) ;
2008-04-21 15:41:59 -07:00
if ( err ) {
2008-09-26 15:09:34 +08:00
err = pci_set_dma_mask ( pdev , DMA_BIT_MASK ( 32 ) ) ;
2008-04-21 15:41:59 -07:00
if ( ! err )
2008-09-26 15:09:34 +08:00
err = pci_set_consistent_dma_mask ( pdev , DMA_BIT_MASK ( 32 ) ) ;
2008-04-21 15:41:59 -07:00
/* both attempts failed: */
2008-03-14 10:38:46 -07:00
if ( err ) {
2008-12-19 10:37:31 +08:00
IWL_WARN ( priv , " No suitable DMA available. \n " ) ;
2008-03-14 10:38:46 -07:00
goto out_pci_disable_device ;
2008-04-21 15:41:59 -07:00
}
2008-03-14 10:38:46 -07:00
}
err = pci_request_regions ( pdev , DRV_NAME ) ;
if ( err )
goto out_pci_disable_device ;
pci_set_drvdata ( pdev , priv ) ;
/***********************
* 3. Read REV register
* * * * * * * * * * * * * * * * * * * * * * */
priv - > hw_base = pci_iomap ( pdev , 0 , 0 ) ;
if ( ! priv - > hw_base ) {
err = - ENODEV ;
goto out_pci_release_regions ;
}
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " pci_resource_len = 0x%08llx \n " ,
2008-03-14 10:38:46 -07:00
( unsigned long long ) pci_resource_len ( pdev , 0 ) ) ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " pci_resource_base = %p \n " , priv - > hw_base ) ;
2008-03-14 10:38:46 -07:00
2009-05-22 11:01:47 -07:00
/* this spin lock will be used in apm_ops.init and EEPROM access
* we should init now
*/
spin_lock_init ( & priv - > reg_lock ) ;
2008-04-23 17:14:54 -07:00
iwl_hw_detect ( priv ) ;
2008-12-19 10:37:31 +08:00
IWL_INFO ( priv , " Detected Intel Wireless WiFi Link %s REV=0x%X \n " ,
2008-04-23 17:14:54 -07:00
priv - > cfg - > name , priv - > hw_rev ) ;
2008-03-14 10:38:46 -07:00
2008-09-03 11:26:49 +08:00
/* We disable the RETRY_TIMEOUT register (0x41) to keep
* PCI Tx retries from interfering with C3 CPU state */
pci_write_config_byte ( pdev , PCI_CFG_RETRY_TIMEOUT , 0x00 ) ;
2009-05-22 11:01:54 -07:00
iwl_prepare_card_hw ( priv ) ;
if ( ! priv - > hw_ready ) {
IWL_WARN ( priv , " Failed, HW not ready \n " ) ;
goto out_iounmap ;
}
2008-04-23 17:14:53 -07:00
/* amp init */
err = priv - > cfg - > ops - > lib - > apm_ops . init ( priv ) ;
2008-03-14 10:38:46 -07:00
if ( err < 0 ) {
2009-03-11 11:18:01 -07:00
IWL_ERR ( priv , " Failed to init APMG \n " ) ;
2008-03-14 10:38:46 -07:00
goto out_iounmap ;
}
2008-04-23 17:14:53 -07:00
/*****************
* 4. Read EEPROM
* * * * * * * * * * * * * * * * */
2008-03-14 10:38:46 -07:00
/* Read the EEPROM */
err = iwl_eeprom_init ( priv ) ;
if ( err ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " Unable to init EEPROM \n " ) ;
2008-03-14 10:38:46 -07:00
goto out_iounmap ;
}
2008-04-23 17:14:55 -07:00
err = iwl_eeprom_check_version ( priv ) ;
if ( err )
2009-02-27 16:21:22 -08:00
goto out_free_eeprom ;
2008-04-23 17:14:55 -07:00
2008-05-15 13:53:53 +08:00
/* extract MAC Address */
2008-03-14 10:38:46 -07:00
iwl_eeprom_get_mac ( priv , priv - > mac_addr ) ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " MAC address: %pM \n " , priv - > mac_addr ) ;
2008-03-14 10:38:46 -07:00
SET_IEEE80211_PERM_ADDR ( priv - > hw , priv - > mac_addr ) ;
/************************
* 5. Setup HW constants
* * * * * * * * * * * * * * * * * * * * * * * */
2008-06-30 17:23:20 +08:00
if ( iwl_set_hw_params ( priv ) ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " failed to set hw parameters \n " ) ;
2008-04-21 15:41:52 -07:00
goto out_free_eeprom ;
2008-03-14 10:38:46 -07:00
}
/*******************
2008-05-15 13:54:17 +08:00
* 6. Setup priv
2008-03-14 10:38:46 -07:00
* * * * * * * * * * * * * * * * * * */
2007-09-25 17:54:57 -07:00
2008-05-15 13:54:17 +08:00
err = iwl_init_drv ( priv ) ;
2008-03-14 10:38:49 -07:00
if ( err )
2008-04-23 17:14:56 -07:00
goto out_free_eeprom ;
2008-03-14 10:38:49 -07:00
/* At this point both hw and priv are initialized. */
2008-03-14 10:38:46 -07:00
/********************
2009-04-20 14:37:03 -07:00
* 7. Setup services
2008-03-14 10:38:46 -07:00
* * * * * * * * * * * * * * * * * * * */
2008-03-28 16:21:08 -07:00
spin_lock_irqsave ( & priv - > lock , flags ) ;
2008-10-29 14:05:46 -07:00
iwl_disable_interrupts ( priv ) ;
2008-03-28 16:21:08 -07:00
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2008-03-14 10:38:46 -07:00
2009-01-19 13:10:07 +01:00
pci_enable_msi ( priv - > pci_dev ) ;
2009-05-22 11:01:50 -07:00
iwl_alloc_isr_ict ( priv ) ;
err = request_irq ( priv - > pci_dev - > irq , priv - > cfg - > ops - > lib - > isr ,
IRQF_SHARED , DRV_NAME , priv ) ;
2009-01-19 13:10:07 +01:00
if ( err ) {
IWL_ERR ( priv , " Error allocating IRQ %d \n " , priv - > pci_dev - > irq ) ;
goto out_disable_msi ;
}
2008-10-29 14:05:46 -07:00
err = sysfs_create_group ( & pdev - > dev . kobj , & iwl_attribute_group ) ;
2008-03-14 10:38:46 -07:00
if ( err ) {
2008-12-19 10:37:33 +08:00
IWL_ERR ( priv , " failed to create sysfs device attributes \n " ) ;
2009-02-12 18:51:03 +01:00
goto out_free_irq ;
2008-03-14 10:38:46 -07:00
}
2008-06-12 09:46:53 +08:00
iwl_setup_deferred_work ( priv ) ;
2008-06-30 17:23:11 +08:00
iwl_setup_rx_handlers ( priv ) ;
2008-03-14 10:38:46 -07:00
2008-05-15 13:54:17 +08:00
/**********************************
2009-04-20 14:37:03 -07:00
* 8. Setup and register mac80211
2008-05-15 13:54:17 +08:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-01-19 13:10:07 +01:00
/* enable interrupts if needed: hw bug w/a */
pci_read_config_word ( priv - > pci_dev , PCI_COMMAND , & pci_cmd ) ;
if ( pci_cmd & PCI_COMMAND_INTX_DISABLE ) {
pci_cmd & = ~ PCI_COMMAND_INTX_DISABLE ;
pci_write_config_word ( priv - > pci_dev , PCI_COMMAND , pci_cmd ) ;
}
iwl_enable_interrupts ( priv ) ;
2008-05-15 13:54:17 +08:00
err = iwl_setup_mac ( priv ) ;
if ( err )
goto out_remove_sysfs ;
err = iwl_dbgfs_register ( priv , DRV_NAME ) ;
if ( err )
2009-04-20 14:36:58 -07:00
IWL_ERR ( priv , " failed to create debugfs files. Ignoring error: %d \n " , err ) ;
2008-05-15 13:54:17 +08:00
2009-01-19 13:10:07 +01:00
/* If platform's RF_KILL switch is NOT set to KILL */
if ( iwl_read32 ( priv , CSR_GP_CNTRL ) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW )
clear_bit ( STATUS_RF_KILL_HW , & priv - > status ) ;
else
set_bit ( STATUS_RF_KILL_HW , & priv - > status ) ;
2008-05-15 13:54:17 +08:00
2009-06-04 18:26:06 +02:00
wiphy_rfkill_set_hw_state ( priv - > hw - > wiphy ,
test_bit ( STATUS_RF_KILL_HW , & priv - > status ) ) ;
2009-01-19 13:10:07 +01:00
2008-06-12 09:47:19 +08:00
iwl_power_initialize ( priv ) ;
2007-09-25 17:54:57 -07:00
return 0 ;
2008-03-14 10:38:46 -07:00
out_remove_sysfs :
2009-02-27 16:21:22 -08:00
destroy_workqueue ( priv - > workqueue ) ;
priv - > workqueue = NULL ;
2008-10-29 14:05:46 -07:00
sysfs_remove_group ( & pdev - > dev . kobj , & iwl_attribute_group ) ;
2009-02-12 18:51:03 +01:00
out_free_irq :
free_irq ( priv - > pci_dev - > irq , priv ) ;
2009-05-22 11:01:50 -07:00
iwl_free_isr_ict ( priv ) ;
2009-01-19 13:10:07 +01:00
out_disable_msi :
pci_disable_msi ( priv - > pci_dev ) ;
2008-05-15 13:54:17 +08:00
iwl_uninit_drv ( priv ) ;
2008-04-21 15:41:52 -07:00
out_free_eeprom :
iwl_eeprom_free ( priv ) ;
2007-09-25 17:54:57 -07:00
out_iounmap :
pci_iounmap ( pdev , priv - > hw_base ) ;
out_pci_release_regions :
2008-03-14 10:38:46 -07:00
pci_set_drvdata ( pdev , NULL ) ;
2009-03-03 11:37:04 -08:00
pci_release_regions ( pdev ) ;
2007-09-25 17:54:57 -07:00
out_pci_disable_device :
pci_disable_device ( pdev ) ;
out_ieee80211_free_hw :
ieee80211_free_hw ( priv - > hw ) ;
out :
return err ;
}
2008-10-29 14:05:46 -07:00
static void __devexit iwl_pci_remove ( struct pci_dev * pdev )
2007-09-25 17:54:57 -07:00
{
2008-03-12 16:58:50 -07:00
struct iwl_priv * priv = pci_get_drvdata ( pdev ) ;
2008-03-28 16:21:08 -07:00
unsigned long flags ;
2007-09-25 17:54:57 -07:00
if ( ! priv )
return ;
2009-01-27 14:27:56 -08:00
IWL_DEBUG_INFO ( priv , " *** UNLOAD DRIVER *** \n " ) ;
2007-09-25 17:54:57 -07:00
2008-05-29 16:35:26 +08:00
iwl_dbgfs_unregister ( priv ) ;
2008-10-29 14:05:46 -07:00
sysfs_remove_group ( & pdev - > dev . kobj , & iwl_attribute_group ) ;
2008-05-29 16:35:26 +08:00
2008-10-29 14:05:46 -07:00
/* ieee80211_unregister_hw call wil cause iwl_mac_stop to
* to be called and iwl_down since we are removing the device
2008-09-03 11:18:50 +08:00
* we need to set STATUS_EXIT_PENDING bit .
*/
set_bit ( STATUS_EXIT_PENDING , & priv - > status ) ;
2008-03-28 16:21:10 -07:00
if ( priv - > mac80211_registered ) {
ieee80211_unregister_hw ( priv - > hw ) ;
priv - > mac80211_registered = 0 ;
2008-09-03 11:18:50 +08:00
} else {
2008-10-29 14:05:46 -07:00
iwl_down ( priv ) ;
2008-03-28 16:21:10 -07:00
}
2008-03-28 16:21:08 -07:00
/* make sure we flush any pending irq or
* tasklet for the driver
*/
spin_lock_irqsave ( & priv - > lock , flags ) ;
2008-10-29 14:05:46 -07:00
iwl_disable_interrupts ( priv ) ;
2008-03-28 16:21:08 -07:00
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
iwl_synchronize_irq ( priv ) ;
2008-10-29 14:05:46 -07:00
iwl_dealloc_ucode_pci ( priv ) ;
2007-09-25 17:54:57 -07:00
if ( priv - > rxq . bd )
2008-05-05 10:22:28 +08:00
iwl_rx_queue_free ( priv , & priv - > rxq ) ;
2008-05-05 10:22:43 +08:00
iwl_hw_txq_ctx_free ( priv ) ;
2007-09-25 17:54:57 -07:00
2009-06-03 11:44:07 -07:00
iwl_clear_stations_table ( priv ) ;
2008-04-21 15:41:52 -07:00
iwl_eeprom_free ( priv ) ;
2007-09-25 17:54:57 -07:00
2007-10-25 17:15:45 +08:00
/*netif_stop_queue(dev); */
flush_workqueue ( priv - > workqueue ) ;
2008-10-29 14:05:46 -07:00
/* ieee80211_unregister_hw calls iwl_mac_stop, which flushes
2007-09-25 17:54:57 -07:00
* priv - > workqueue . . . so we can ' t take down the workqueue
* until now . . . */
destroy_workqueue ( priv - > workqueue ) ;
priv - > workqueue = NULL ;
2009-01-19 13:10:07 +01:00
free_irq ( priv - > pci_dev - > irq , priv ) ;
pci_disable_msi ( priv - > pci_dev ) ;
2007-09-25 17:54:57 -07:00
pci_iounmap ( pdev , priv - > hw_base ) ;
pci_release_regions ( pdev ) ;
pci_disable_device ( pdev ) ;
pci_set_drvdata ( pdev , NULL ) ;
2008-05-15 13:54:17 +08:00
iwl_uninit_drv ( priv ) ;
2007-09-25 17:54:57 -07:00
2009-05-22 11:01:50 -07:00
iwl_free_isr_ict ( priv ) ;
2007-09-25 17:54:57 -07:00
if ( priv - > ibss_beacon )
dev_kfree_skb ( priv - > ibss_beacon ) ;
ieee80211_free_hw ( priv - > hw ) ;
}
/*****************************************************************************
*
* driver and module entry point
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-04-15 16:01:41 -07:00
/* Hardware specific file defines the PCI IDs table for that hardware module */
static struct pci_device_id iwl_hw_card_ids [ ] = {
2008-07-21 18:54:42 +03:00
# ifdef CONFIG_IWL4965
2008-04-15 16:01:41 -07:00
{ IWL_PCI_DEVICE ( 0x4229 , PCI_ANY_ID , iwl4965_agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x4230 , PCI_ANY_ID , iwl4965_agn_cfg ) } ,
2008-07-21 18:54:42 +03:00
# endif /* CONFIG_IWL4965 */
2008-04-24 11:55:23 -07:00
# ifdef CONFIG_IWL5000
2008-07-11 11:53:30 +08:00
{ IWL_PCI_DEVICE ( 0x4232 , 0x1205 , iwl5100_bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x4232 , 0x1305 , iwl5100_bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x4232 , 0x1206 , iwl5100_abg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x4232 , 0x1306 , iwl5100_abg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x4232 , 0x1326 , iwl5100_abg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x4237 , 0x1216 , iwl5100_abg_cfg ) } ,
2008-04-24 11:55:23 -07:00
{ IWL_PCI_DEVICE ( 0x4232 , PCI_ANY_ID , iwl5100_agn_cfg ) } ,
2008-07-11 11:53:30 +08:00
{ IWL_PCI_DEVICE ( 0x4235 , PCI_ANY_ID , iwl5300_agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x4236 , PCI_ANY_ID , iwl5300_agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x4237 , PCI_ANY_ID , iwl5100_agn_cfg ) } ,
2008-09-11 11:45:20 +08:00
/* 5350 WiFi/WiMax */
{ IWL_PCI_DEVICE ( 0x423A , 0x1001 , iwl5350_agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x423A , 0x1021 , iwl5350_agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x423B , 0x1011 , iwl5350_agn_cfg ) } ,
2008-12-01 16:32:18 -08:00
/* 5150 Wifi/WiMax */
{ IWL_PCI_DEVICE ( 0x423C , PCI_ANY_ID , iwl5150_agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x423D , PCI_ANY_ID , iwl5150_agn_cfg ) } ,
2009-01-19 15:30:34 -08:00
/* 6000/6050 Series */
{ IWL_PCI_DEVICE ( 0x0082 , 0x1102 , iwl6000_2ag_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0085 , 0x1112 , iwl6000_2ag_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0082 , 0x1122 , iwl6000_2ag_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x422B , PCI_ANY_ID , iwl6000_3agn_cfg ) } ,
2009-05-08 13:44:46 -07:00
{ IWL_PCI_DEVICE ( 0x422C , PCI_ANY_ID , iwl6000_2agn_cfg ) } ,
2009-01-19 15:30:34 -08:00
{ IWL_PCI_DEVICE ( 0x4238 , PCI_ANY_ID , iwl6000_3agn_cfg ) } ,
2009-05-08 13:44:46 -07:00
{ IWL_PCI_DEVICE ( 0x4239 , PCI_ANY_ID , iwl6000_2agn_cfg ) } ,
2009-01-19 15:30:34 -08:00
{ IWL_PCI_DEVICE ( 0x0082 , PCI_ANY_ID , iwl6000_2agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0085 , PCI_ANY_ID , iwl6000_3agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0086 , PCI_ANY_ID , iwl6050_3agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0087 , PCI_ANY_ID , iwl6050_2agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0088 , PCI_ANY_ID , iwl6050_3agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0089 , PCI_ANY_ID , iwl6050_2agn_cfg ) } ,
2009-03-06 13:52:55 -08:00
/* 1000 Series WiFi */
{ IWL_PCI_DEVICE ( 0x0083 , PCI_ANY_ID , iwl1000_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0084 , PCI_ANY_ID , iwl1000_bgn_cfg ) } ,
2008-04-24 11:55:23 -07:00
# endif /* CONFIG_IWL5000 */
2008-12-01 16:32:18 -08:00
2008-04-15 16:01:41 -07:00
{ 0 }
} ;
MODULE_DEVICE_TABLE ( pci , iwl_hw_card_ids ) ;
static struct pci_driver iwl_driver = {
2007-09-25 17:54:57 -07:00
. name = DRV_NAME ,
2008-04-15 16:01:41 -07:00
. id_table = iwl_hw_card_ids ,
2008-10-29 14:05:46 -07:00
. probe = iwl_pci_probe ,
. remove = __devexit_p ( iwl_pci_remove ) ,
2007-09-25 17:54:57 -07:00
# ifdef CONFIG_PM
2008-10-29 14:05:46 -07:00
. suspend = iwl_pci_suspend ,
. resume = iwl_pci_resume ,
2007-09-25 17:54:57 -07:00
# endif
} ;
2008-10-29 14:05:46 -07:00
static int __init iwl_init ( void )
2007-09-25 17:54:57 -07:00
{
int ret ;
printk ( KERN_INFO DRV_NAME " : " DRV_DESCRIPTION " , " DRV_VERSION " \n " ) ;
printk ( KERN_INFO DRV_NAME " : " DRV_COPYRIGHT " \n " ) ;
2008-03-28 16:21:09 -07:00
2008-07-18 13:53:05 +08:00
ret = iwlagn_rate_control_register ( ) ;
2008-03-28 16:21:09 -07:00
if ( ret ) {
2008-12-19 10:37:09 +08:00
printk ( KERN_ERR DRV_NAME
" Unable to register rate control algorithm: %d \n " , ret ) ;
2008-03-28 16:21:09 -07:00
return ret ;
}
2008-04-15 16:01:41 -07:00
ret = pci_register_driver ( & iwl_driver ) ;
2007-09-25 17:54:57 -07:00
if ( ret ) {
2008-12-19 10:37:09 +08:00
printk ( KERN_ERR DRV_NAME " Unable to initialize PCI module \n " ) ;
2008-03-28 16:21:09 -07:00
goto error_register ;
2007-09-25 17:54:57 -07:00
}
return ret ;
2008-03-28 16:21:09 -07:00
error_register :
2008-07-18 13:53:05 +08:00
iwlagn_rate_control_unregister ( ) ;
2008-03-28 16:21:09 -07:00
return ret ;
2007-09-25 17:54:57 -07:00
}
2008-10-29 14:05:46 -07:00
static void __exit iwl_exit ( void )
2007-09-25 17:54:57 -07:00
{
2008-04-15 16:01:41 -07:00
pci_unregister_driver ( & iwl_driver ) ;
2008-07-18 13:53:05 +08:00
iwlagn_rate_control_unregister ( ) ;
2007-09-25 17:54:57 -07:00
}
2008-10-29 14:05:46 -07:00
module_exit ( iwl_exit ) ;
module_init ( iwl_init ) ;