2012-02-07 14:18:40 +02:00
/******************************************************************************
*
* This file is provided under a dual BSD / GPLv2 license . When using or
* redistributing this file , you may do so under either license .
*
* GPL LICENSE SUMMARY
*
2013-12-30 13:15:54 +02:00
* Copyright ( c ) 2007 - 2014 Intel Corporation . All rights reserved .
2014-07-24 14:05:26 +02:00
* Copyright ( c ) 2013 - 2014 Intel Mobile Communications GmbH
2012-02-07 14:18:40 +02:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 ,
* USA
*
* The full GNU General Public License is included in this distribution
2013-02-18 09:22:28 +02:00
* in the file called COPYING .
2012-02-07 14:18:40 +02:00
*
* Contact Information :
* Intel Linux Wireless < ilw @ linux . intel . com >
* Intel Corporation , 5200 N . E . Elam Young Parkway , Hillsboro , OR 97124 - 6497
*
* BSD LICENSE
*
2013-12-30 13:15:54 +02:00
* Copyright ( c ) 2005 - 2014 Intel Corporation . All rights reserved .
2014-07-24 14:05:26 +02:00
* Copyright ( c ) 2013 - 2014 Intel Mobile Communications GmbH
2012-02-07 14:18:40 +02:00
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
*
* * Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* * Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in
* the documentation and / or other materials provided with the
* distribution .
* * Neither the name Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
* SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT
* LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <linux/completion.h>
2012-03-05 11:24:50 -08:00
# include <linux/dma-mapping.h>
# include <linux/firmware.h>
# include <linux/module.h>
2012-09-10 11:50:18 +02:00
# include <linux/vmalloc.h>
2012-02-07 14:18:40 +02:00
# include "iwl-drv.h"
2014-09-18 17:22:58 +03:00
# include "iwl-csr.h"
2012-04-19 10:29:58 +03:00
# include "iwl-debug.h"
2012-02-07 14:18:40 +02:00
# include "iwl-trans.h"
2012-02-09 16:08:15 +02:00
# include "iwl-op-mode.h"
2012-03-10 13:00:12 -08:00
# include "iwl-agn-hw.h"
2012-04-02 15:04:33 +02:00
# include "iwl-fw.h"
# include "iwl-config.h"
2012-04-17 07:36:30 -07:00
# include "iwl-modparams.h"
2012-02-07 14:18:40 +02:00
2012-05-16 22:54:27 +02:00
/******************************************************************************
*
* module boiler plate
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define DRV_DESCRIPTION "Intel(R) Wireless WiFi driver for Linux"
MODULE_DESCRIPTION ( DRV_DESCRIPTION ) ;
MODULE_AUTHOR ( DRV_COPYRIGHT " " DRV_AUTHOR ) ;
MODULE_LICENSE ( " GPL " ) ;
2012-07-16 18:43:56 -07:00
# ifdef CONFIG_IWLWIFI_DEBUGFS
static struct dentry * iwl_dbgfs_root ;
# endif
2012-03-06 13:30:38 -08:00
/**
* struct iwl_drv - drv common data
2012-05-16 22:54:27 +02:00
* @ list : list of drv structures using this opmode
2012-03-06 13:30:38 -08:00
* @ fw : the iwl_fw structure
* @ op_mode : the running op_mode
2012-03-22 17:51:44 +02:00
* @ trans : transport layer
2012-03-22 23:59:52 +02:00
* @ dev : for debug prints only
2012-03-22 17:51:44 +02:00
* @ cfg : configuration struct
2012-03-06 13:30:38 -08:00
* @ fw_index : firmware revision to try loading
* @ firmware_name : composite filename of ucode file to load
* @ request_firmware_complete : the firmware has been obtained from user space
*/
struct iwl_drv {
2012-05-16 22:54:27 +02:00
struct list_head list ;
2012-03-06 13:30:38 -08:00
struct iwl_fw fw ;
struct iwl_op_mode * op_mode ;
2012-03-26 08:51:09 -07:00
struct iwl_trans * trans ;
2012-03-22 23:59:52 +02:00
struct device * dev ;
2012-03-22 17:51:44 +02:00
const struct iwl_cfg * cfg ;
2012-03-06 13:30:38 -08:00
int fw_index ; /* firmware we're trying to load */
2014-01-27 16:34:23 +02:00
char firmware_name [ 32 ] ; /* name of firmware file to load */
2012-03-06 13:30:38 -08:00
struct completion request_firmware_complete ;
2012-07-16 18:43:56 -07:00
# ifdef CONFIG_IWLWIFI_DEBUGFS
struct dentry * dbgfs_drv ;
struct dentry * dbgfs_trans ;
struct dentry * dbgfs_op_mode ;
# endif
2012-03-06 13:30:38 -08:00
} ;
2013-01-24 14:25:36 +01:00
enum {
DVM_OP_MODE = 0 ,
MVM_OP_MODE = 1 ,
} ;
2012-03-06 13:30:38 -08:00
2012-06-06 09:42:57 +02:00
/* Protects the table contents, i.e. the ops pointer & drv list */
static struct mutex iwlwifi_opmode_table_mtx ;
2012-05-16 22:54:27 +02:00
static struct iwlwifi_opmode_table {
const char * name ; /* name: iwldvm, iwlmvm, etc */
const struct iwl_op_mode_ops * ops ; /* pointer to op_mode ops */
struct list_head drv ; /* list of devices using this op_mode */
} iwlwifi_opmode_table [ ] = { /* ops set when driver is initialized */
2013-01-24 14:25:36 +01:00
[ DVM_OP_MODE ] = { . name = " iwldvm " , . ops = NULL } ,
[ MVM_OP_MODE ] = { . name = " iwlmvm " , . ops = NULL } ,
2012-05-16 22:54:27 +02:00
} ;
2012-03-06 13:30:38 -08:00
2014-06-05 11:20:43 +03:00
# define IWL_DEFAULT_SCAN_CHANNELS 40
2012-03-10 13:00:12 -08:00
/*
* struct fw_sec : Just for the image parsing proccess .
* For the fw storage we are using struct fw_desc .
*/
struct fw_sec {
const void * data ; /* the sec data */
size_t size ; /* section size */
u32 offset ; /* offset of writing in the device */
} ;
2012-03-06 13:30:38 -08:00
static void iwl_free_fw_desc ( struct iwl_drv * drv , struct fw_desc * desc )
2012-03-05 11:24:50 -08:00
{
2012-09-10 11:50:18 +02:00
vfree ( desc - > data ) ;
desc - > data = NULL ;
2012-03-05 11:24:50 -08:00
desc - > len = 0 ;
}
2012-03-06 13:30:38 -08:00
static void iwl_free_fw_img ( struct iwl_drv * drv , struct fw_img * img )
2012-03-05 11:24:50 -08:00
{
2012-03-10 13:00:14 -08:00
int i ;
for ( i = 0 ; i < IWL_UCODE_SECTION_MAX ; i + + )
iwl_free_fw_desc ( drv , & img - > sec [ i ] ) ;
2012-03-05 11:24:50 -08:00
}
2012-03-06 13:30:38 -08:00
static void iwl_dealloc_ucode ( struct iwl_drv * drv )
2012-03-05 11:24:50 -08:00
{
2012-03-10 13:00:14 -08:00
int i ;
2014-09-16 15:06:54 +03:00
kfree ( drv - > fw . dbg_dest_tlv ) ;
for ( i = 0 ; i < ARRAY_SIZE ( drv - > fw . dbg_conf_tlv ) ; i + + )
kfree ( drv - > fw . dbg_conf_tlv [ i ] ) ;
2015-01-29 14:58:06 +02:00
for ( i = 0 ; i < ARRAY_SIZE ( drv - > fw . dbg_trigger_tlv ) ; i + + )
kfree ( drv - > fw . dbg_trigger_tlv [ i ] ) ;
2014-09-16 15:06:54 +03:00
2012-03-10 13:00:14 -08:00
for ( i = 0 ; i < IWL_UCODE_TYPE_MAX ; i + + )
iwl_free_fw_img ( drv , drv - > fw . img + i ) ;
2012-03-05 11:24:50 -08:00
}
2012-03-06 13:30:38 -08:00
static int iwl_alloc_fw_desc ( struct iwl_drv * drv , struct fw_desc * desc ,
2012-09-10 11:50:18 +02:00
struct fw_sec * sec )
2012-03-05 11:24:50 -08:00
{
2012-09-10 11:50:18 +02:00
void * data ;
desc - > data = NULL ;
if ( ! sec | | ! sec - > size )
2012-03-05 11:24:50 -08:00
return - EINVAL ;
2012-09-10 11:50:18 +02:00
data = vmalloc ( sec - > size ) ;
if ( ! data )
2012-03-05 11:24:50 -08:00
return - ENOMEM ;
2012-03-10 13:00:12 -08:00
desc - > len = sec - > size ;
desc - > offset = sec - > offset ;
2012-09-10 11:50:18 +02:00
memcpy ( data , sec - > data , desc - > len ) ;
desc - > data = data ;
2012-03-05 11:24:50 -08:00
return 0 ;
}
2012-07-16 12:31:28 +03:00
static void iwl_req_fw_callback ( const struct firmware * ucode_raw ,
void * context ) ;
2012-03-05 11:24:50 -08:00
# define UCODE_EXPERIMENTAL_INDEX 100
# define UCODE_EXPERIMENTAL_TAG "exp"
2012-03-06 13:30:38 -08:00
static int iwl_request_firmware ( struct iwl_drv * drv , bool first )
2012-03-05 11:24:50 -08:00
{
2012-03-22 17:51:44 +02:00
const char * name_pre = drv - > cfg - > fw_name_pre ;
2012-03-05 11:24:50 -08:00
char tag [ 8 ] ;
if ( first ) {
# ifdef CONFIG_IWLWIFI_DEBUG_EXPERIMENTAL_UCODE
2012-03-06 13:30:38 -08:00
drv - > fw_index = UCODE_EXPERIMENTAL_INDEX ;
2012-03-05 11:24:50 -08:00
strcpy ( tag , UCODE_EXPERIMENTAL_TAG ) ;
2012-03-06 13:30:38 -08:00
} else if ( drv - > fw_index = = UCODE_EXPERIMENTAL_INDEX ) {
2012-03-05 11:24:50 -08:00
# endif
2012-03-22 17:51:44 +02:00
drv - > fw_index = drv - > cfg - > ucode_api_max ;
2012-03-06 13:30:38 -08:00
sprintf ( tag , " %d " , drv - > fw_index ) ;
2012-03-05 11:24:50 -08:00
} else {
2012-03-06 13:30:38 -08:00
drv - > fw_index - - ;
sprintf ( tag , " %d " , drv - > fw_index ) ;
2012-03-05 11:24:50 -08:00
}
2012-03-22 17:51:44 +02:00
if ( drv - > fw_index < drv - > cfg - > ucode_api_min ) {
2012-03-06 13:30:38 -08:00
IWL_ERR ( drv , " no suitable firmware found! \n " ) ;
2012-03-05 11:24:50 -08:00
return - ENOENT ;
}
2014-01-27 16:34:23 +02:00
snprintf ( drv - > firmware_name , sizeof ( drv - > firmware_name ) , " %s%s.ucode " ,
name_pre , tag ) ;
2012-03-05 11:24:50 -08:00
2014-09-18 17:22:58 +03:00
/*
* Starting 8000 B - FW name format has changed . This overwrites the
* previous name and uses the new format .
*/
if ( drv - > trans - > cfg - > device_family = = IWL_DEVICE_FAMILY_8000 ) {
char rev_step [ 2 ] = {
' A ' + CSR_HW_REV_STEP ( drv - > trans - > hw_rev ) , 0
} ;
/* A-step doesn't have an indication */
if ( CSR_HW_REV_STEP ( drv - > trans - > hw_rev ) = = SILICON_A_STEP )
rev_step [ 0 ] = 0 ;
snprintf ( drv - > firmware_name , sizeof ( drv - > firmware_name ) ,
" %s%s-%s.ucode " , name_pre , rev_step , tag ) ;
}
2012-03-06 13:30:38 -08:00
IWL_DEBUG_INFO ( drv , " attempting to load firmware %s'%s' \n " ,
( drv - > fw_index = = UCODE_EXPERIMENTAL_INDEX )
2012-03-05 11:24:50 -08:00
? " EXPERIMENTAL " : " " ,
2012-03-06 13:30:38 -08:00
drv - > firmware_name ) ;
2012-03-05 11:24:50 -08:00
2012-03-06 13:30:38 -08:00
return request_firmware_nowait ( THIS_MODULE , 1 , drv - > firmware_name ,
2012-03-22 17:51:44 +02:00
drv - > trans - > dev ,
2012-07-16 12:31:28 +03:00
GFP_KERNEL , drv , iwl_req_fw_callback ) ;
2012-03-05 11:24:50 -08:00
}
2012-03-10 13:00:12 -08:00
struct fw_img_parsing {
2012-03-10 13:00:14 -08:00
struct fw_sec sec [ IWL_UCODE_SECTION_MAX ] ;
2012-03-10 13:00:12 -08:00
int sec_counter ;
} ;
2012-03-10 13:00:13 -08:00
/*
* struct fw_sec_parsing : to extract fw section and it ' s offset from tlv
*/
struct fw_sec_parsing {
__le32 offset ;
const u8 data [ ] ;
} __packed ;
/**
* struct iwl_tlv_calib_data - parse the default calib data from TLV
*
* @ ucode_type : the uCode to which the following default calib relates .
* @ calib : default calibrations .
*/
struct iwl_tlv_calib_data {
__le32 ucode_type ;
2013-01-24 14:12:07 +01:00
struct iwl_tlv_calib_ctrl calib ;
2012-03-10 13:00:13 -08:00
} __packed ;
2012-03-10 13:00:12 -08:00
struct iwl_firmware_pieces {
struct fw_img_parsing img [ IWL_UCODE_TYPE_MAX ] ;
2012-03-05 11:24:50 -08:00
u32 init_evtlog_ptr , init_evtlog_size , init_errlog_ptr ;
u32 inst_evtlog_ptr , inst_evtlog_size , inst_errlog_ptr ;
2014-09-16 15:06:54 +03:00
/* FW debug data parsed for driver usage */
struct iwl_fw_dbg_dest_tlv * dbg_dest_tlv ;
2015-01-29 14:58:06 +02:00
struct iwl_fw_dbg_conf_tlv * dbg_conf_tlv [ FW_DBG_CONF_MAX ] ;
size_t dbg_conf_tlv_len [ FW_DBG_CONF_MAX ] ;
struct iwl_fw_dbg_trigger_tlv * dbg_trigger_tlv [ FW_DBG_TRIGGER_MAX ] ;
size_t dbg_trigger_tlv_len [ FW_DBG_TRIGGER_MAX ] ;
2012-03-05 11:24:50 -08:00
} ;
2012-03-10 13:00:12 -08:00
/*
* These functions are just to extract uCode section data from the pieces
* structure .
*/
static struct fw_sec * get_sec ( struct iwl_firmware_pieces * pieces ,
enum iwl_ucode_type type ,
int sec )
{
return & pieces - > img [ type ] . sec [ sec ] ;
}
static void set_sec_data ( struct iwl_firmware_pieces * pieces ,
enum iwl_ucode_type type ,
int sec ,
const void * data )
{
pieces - > img [ type ] . sec [ sec ] . data = data ;
}
static void set_sec_size ( struct iwl_firmware_pieces * pieces ,
enum iwl_ucode_type type ,
int sec ,
size_t size )
{
pieces - > img [ type ] . sec [ sec ] . size = size ;
}
static size_t get_sec_size ( struct iwl_firmware_pieces * pieces ,
enum iwl_ucode_type type ,
int sec )
{
return pieces - > img [ type ] . sec [ sec ] . size ;
}
static void set_sec_offset ( struct iwl_firmware_pieces * pieces ,
enum iwl_ucode_type type ,
int sec ,
u32 offset )
{
pieces - > img [ type ] . sec [ sec ] . offset = offset ;
}
2013-08-27 19:56:13 +03:00
static int iwl_store_cscheme ( struct iwl_fw * fw , const u8 * data , const u32 len )
{
int i , j ;
struct iwl_fw_cscheme_list * l = ( struct iwl_fw_cscheme_list * ) data ;
struct iwl_fw_cipher_scheme * fwcs ;
struct ieee80211_cipher_scheme * cs ;
u32 cipher ;
if ( len < sizeof ( * l ) | |
len < sizeof ( l - > size ) + l - > size * sizeof ( l - > cs [ 0 ] ) )
return - EINVAL ;
for ( i = 0 , j = 0 ; i < IWL_UCODE_MAX_CS & & i < l - > size ; i + + ) {
fwcs = & l - > cs [ j ] ;
cipher = le32_to_cpu ( fwcs - > cipher ) ;
/* we skip schemes with zero cipher suite selector */
if ( ! cipher )
continue ;
cs = & fw - > cs [ j + + ] ;
cs - > cipher = cipher ;
cs - > iftype = BIT ( NL80211_IFTYPE_STATION ) ;
cs - > hdr_len = fwcs - > hdr_len ;
cs - > pn_len = fwcs - > pn_len ;
cs - > pn_off = fwcs - > pn_off ;
cs - > key_idx_off = fwcs - > key_idx_off ;
cs - > key_idx_mask = fwcs - > key_idx_mask ;
cs - > key_idx_shift = fwcs - > key_idx_shift ;
cs - > mic_len = fwcs - > mic_len ;
}
return 0 ;
}
2012-03-10 13:00:13 -08:00
/*
* Gets uCode section from tlv .
*/
static int iwl_store_ucode_sec ( struct iwl_firmware_pieces * pieces ,
const void * data , enum iwl_ucode_type type ,
int size )
{
struct fw_img_parsing * img ;
struct fw_sec * sec ;
struct fw_sec_parsing * sec_parse ;
if ( WARN_ON ( ! pieces | | ! data | | type > = IWL_UCODE_TYPE_MAX ) )
return - 1 ;
sec_parse = ( struct fw_sec_parsing * ) data ;
img = & pieces - > img [ type ] ;
sec = & img - > sec [ img - > sec_counter ] ;
sec - > offset = le32_to_cpu ( sec_parse - > offset ) ;
sec - > data = sec_parse - > data ;
2012-03-13 14:32:48 +02:00
sec - > size = size - sizeof ( sec_parse - > offset ) ;
2012-03-10 13:00:13 -08:00
+ + img - > sec_counter ;
return 0 ;
}
static int iwl_set_default_calib ( struct iwl_drv * drv , const u8 * data )
{
struct iwl_tlv_calib_data * def_calib =
( struct iwl_tlv_calib_data * ) data ;
u32 ucode_type = le32_to_cpu ( def_calib - > ucode_type ) ;
if ( ucode_type > = IWL_UCODE_TYPE_MAX ) {
IWL_ERR ( drv , " Wrong ucode_type %u for default calibration. \n " ,
ucode_type ) ;
return - EINVAL ;
}
2013-01-24 14:12:07 +01:00
drv - > fw . default_calib [ ucode_type ] . flow_trigger =
def_calib - > calib . flow_trigger ;
drv - > fw . default_calib [ ucode_type ] . event_trigger =
def_calib - > calib . event_trigger ;
2012-03-10 13:00:13 -08:00
return 0 ;
}
2014-02-20 11:00:01 +02:00
static int iwl_set_ucode_api_flags ( struct iwl_drv * drv , const u8 * data ,
struct iwl_ucode_capabilities * capa )
{
const struct iwl_ucode_api * ucode_api = ( void * ) data ;
u32 api_index = le32_to_cpu ( ucode_api - > api_index ) ;
if ( api_index > = IWL_API_ARRAY_SIZE ) {
IWL_ERR ( drv , " api_index larger than supported by driver \n " ) ;
return - EINVAL ;
}
capa - > api [ api_index ] = le32_to_cpu ( ucode_api - > api_flags ) ;
return 0 ;
}
static int iwl_set_ucode_capabilities ( struct iwl_drv * drv , const u8 * data ,
struct iwl_ucode_capabilities * capa )
{
const struct iwl_ucode_capa * ucode_capa = ( void * ) data ;
u32 api_index = le32_to_cpu ( ucode_capa - > api_index ) ;
if ( api_index > = IWL_CAPABILITIES_ARRAY_SIZE ) {
IWL_ERR ( drv , " api_index larger than supported by driver \n " ) ;
return - EINVAL ;
}
capa - > capa [ api_index ] = le32_to_cpu ( ucode_capa - > api_capa ) ;
return 0 ;
}
2012-03-06 13:30:38 -08:00
static int iwl_parse_v1_v2_firmware ( struct iwl_drv * drv ,
2012-03-10 13:00:12 -08:00
const struct firmware * ucode_raw ,
struct iwl_firmware_pieces * pieces )
2012-03-05 11:24:50 -08:00
{
struct iwl_ucode_header * ucode = ( void * ) ucode_raw - > data ;
u32 api_ver , hdr_size , build ;
char buildstr [ 25 ] ;
const u8 * src ;
2012-03-06 13:30:38 -08:00
drv - > fw . ucode_ver = le32_to_cpu ( ucode - > ver ) ;
api_ver = IWL_UCODE_API ( drv - > fw . ucode_ver ) ;
2012-03-05 11:24:50 -08:00
switch ( api_ver ) {
default :
hdr_size = 28 ;
if ( ucode_raw - > size < hdr_size ) {
2012-03-06 13:30:38 -08:00
IWL_ERR ( drv , " File size too small! \n " ) ;
2012-03-05 11:24:50 -08:00
return - EINVAL ;
}
build = le32_to_cpu ( ucode - > u . v2 . build ) ;
2012-03-10 13:00:12 -08:00
set_sec_size ( pieces , IWL_UCODE_REGULAR , IWL_UCODE_SECTION_INST ,
le32_to_cpu ( ucode - > u . v2 . inst_size ) ) ;
set_sec_size ( pieces , IWL_UCODE_REGULAR , IWL_UCODE_SECTION_DATA ,
le32_to_cpu ( ucode - > u . v2 . data_size ) ) ;
set_sec_size ( pieces , IWL_UCODE_INIT , IWL_UCODE_SECTION_INST ,
le32_to_cpu ( ucode - > u . v2 . init_size ) ) ;
set_sec_size ( pieces , IWL_UCODE_INIT , IWL_UCODE_SECTION_DATA ,
le32_to_cpu ( ucode - > u . v2 . init_data_size ) ) ;
2012-03-05 11:24:50 -08:00
src = ucode - > u . v2 . data ;
break ;
case 0 :
case 1 :
case 2 :
hdr_size = 24 ;
if ( ucode_raw - > size < hdr_size ) {
2012-03-06 13:30:38 -08:00
IWL_ERR ( drv , " File size too small! \n " ) ;
2012-03-05 11:24:50 -08:00
return - EINVAL ;
}
build = 0 ;
2012-03-10 13:00:12 -08:00
set_sec_size ( pieces , IWL_UCODE_REGULAR , IWL_UCODE_SECTION_INST ,
le32_to_cpu ( ucode - > u . v1 . inst_size ) ) ;
set_sec_size ( pieces , IWL_UCODE_REGULAR , IWL_UCODE_SECTION_DATA ,
le32_to_cpu ( ucode - > u . v1 . data_size ) ) ;
set_sec_size ( pieces , IWL_UCODE_INIT , IWL_UCODE_SECTION_INST ,
le32_to_cpu ( ucode - > u . v1 . init_size ) ) ;
set_sec_size ( pieces , IWL_UCODE_INIT , IWL_UCODE_SECTION_DATA ,
le32_to_cpu ( ucode - > u . v1 . init_data_size ) ) ;
2012-03-05 11:24:50 -08:00
src = ucode - > u . v1 . data ;
break ;
}
if ( build )
sprintf ( buildstr , " build %u%s " , build ,
2012-03-06 13:30:38 -08:00
( drv - > fw_index = = UCODE_EXPERIMENTAL_INDEX )
2012-03-05 11:24:50 -08:00
? " (EXP) " : " " ) ;
else
buildstr [ 0 ] = ' \0 ' ;
2012-03-06 13:30:38 -08:00
snprintf ( drv - > fw . fw_version ,
sizeof ( drv - > fw . fw_version ) ,
2012-03-05 11:24:50 -08:00
" %u.%u.%u.%u%s " ,
2012-03-06 13:30:38 -08:00
IWL_UCODE_MAJOR ( drv - > fw . ucode_ver ) ,
IWL_UCODE_MINOR ( drv - > fw . ucode_ver ) ,
IWL_UCODE_API ( drv - > fw . ucode_ver ) ,
IWL_UCODE_SERIAL ( drv - > fw . ucode_ver ) ,
2012-03-05 11:24:50 -08:00
buildstr ) ;
/* Verify size of file vs. image size info in file's header */
2012-03-10 13:00:12 -08:00
if ( ucode_raw - > size ! = hdr_size +
get_sec_size ( pieces , IWL_UCODE_REGULAR , IWL_UCODE_SECTION_INST ) +
get_sec_size ( pieces , IWL_UCODE_REGULAR , IWL_UCODE_SECTION_DATA ) +
get_sec_size ( pieces , IWL_UCODE_INIT , IWL_UCODE_SECTION_INST ) +
get_sec_size ( pieces , IWL_UCODE_INIT , IWL_UCODE_SECTION_DATA ) ) {
2012-03-05 11:24:50 -08:00
2012-03-06 13:30:38 -08:00
IWL_ERR ( drv ,
2012-03-05 11:24:50 -08:00
" uCode file size %d does not match expected size \n " ,
( int ) ucode_raw - > size ) ;
return - EINVAL ;
}
2012-03-10 13:00:12 -08:00
set_sec_data ( pieces , IWL_UCODE_REGULAR , IWL_UCODE_SECTION_INST , src ) ;
src + = get_sec_size ( pieces , IWL_UCODE_REGULAR , IWL_UCODE_SECTION_INST ) ;
set_sec_offset ( pieces , IWL_UCODE_REGULAR , IWL_UCODE_SECTION_INST ,
IWLAGN_RTC_INST_LOWER_BOUND ) ;
set_sec_data ( pieces , IWL_UCODE_REGULAR , IWL_UCODE_SECTION_DATA , src ) ;
src + = get_sec_size ( pieces , IWL_UCODE_REGULAR , IWL_UCODE_SECTION_DATA ) ;
set_sec_offset ( pieces , IWL_UCODE_REGULAR , IWL_UCODE_SECTION_DATA ,
IWLAGN_RTC_DATA_LOWER_BOUND ) ;
set_sec_data ( pieces , IWL_UCODE_INIT , IWL_UCODE_SECTION_INST , src ) ;
src + = get_sec_size ( pieces , IWL_UCODE_INIT , IWL_UCODE_SECTION_INST ) ;
set_sec_offset ( pieces , IWL_UCODE_INIT , IWL_UCODE_SECTION_INST ,
IWLAGN_RTC_INST_LOWER_BOUND ) ;
set_sec_data ( pieces , IWL_UCODE_INIT , IWL_UCODE_SECTION_DATA , src ) ;
src + = get_sec_size ( pieces , IWL_UCODE_INIT , IWL_UCODE_SECTION_DATA ) ;
set_sec_offset ( pieces , IWL_UCODE_INIT , IWL_UCODE_SECTION_DATA ,
IWLAGN_RTC_DATA_LOWER_BOUND ) ;
2012-03-05 11:24:50 -08:00
return 0 ;
}
2012-03-06 13:30:38 -08:00
static int iwl_parse_tlv_firmware ( struct iwl_drv * drv ,
2012-03-05 11:24:50 -08:00
const struct firmware * ucode_raw ,
2012-03-10 13:00:12 -08:00
struct iwl_firmware_pieces * pieces ,
2012-03-05 11:24:50 -08:00
struct iwl_ucode_capabilities * capa )
{
struct iwl_tlv_ucode_header * ucode = ( void * ) ucode_raw - > data ;
struct iwl_ucode_tlv * tlv ;
size_t len = ucode_raw - > size ;
const u8 * data ;
u32 tlv_len ;
enum iwl_ucode_tlv_type tlv_type ;
const u8 * tlv_data ;
char buildstr [ 25 ] ;
u32 build ;
2013-10-02 13:53:40 +03:00
int num_of_cpus ;
2014-12-01 17:40:37 +02:00
bool usniffer_images = false ;
bool usniffer_req = false ;
2012-03-05 11:24:50 -08:00
if ( len < sizeof ( * ucode ) ) {
2012-03-06 13:30:38 -08:00
IWL_ERR ( drv , " uCode has invalid length: %zd \n " , len ) ;
2012-03-05 11:24:50 -08:00
return - EINVAL ;
}
if ( ucode - > magic ! = cpu_to_le32 ( IWL_TLV_UCODE_MAGIC ) ) {
2012-03-06 13:30:38 -08:00
IWL_ERR ( drv , " invalid uCode magic: 0X%x \n " ,
2012-03-05 11:24:50 -08:00
le32_to_cpu ( ucode - > magic ) ) ;
return - EINVAL ;
}
2012-03-06 13:30:38 -08:00
drv - > fw . ucode_ver = le32_to_cpu ( ucode - > ver ) ;
2014-06-02 08:34:53 +03:00
memcpy ( drv - > fw . human_readable , ucode - > human_readable ,
sizeof ( drv - > fw . human_readable ) ) ;
2012-03-05 11:24:50 -08:00
build = le32_to_cpu ( ucode - > build ) ;
if ( build )
sprintf ( buildstr , " build %u%s " , build ,
2012-03-06 13:30:38 -08:00
( drv - > fw_index = = UCODE_EXPERIMENTAL_INDEX )
2012-03-05 11:24:50 -08:00
? " (EXP) " : " " ) ;
else
buildstr [ 0 ] = ' \0 ' ;
2012-03-06 13:30:38 -08:00
snprintf ( drv - > fw . fw_version ,
sizeof ( drv - > fw . fw_version ) ,
2012-03-05 11:24:50 -08:00
" %u.%u.%u.%u%s " ,
2012-03-06 13:30:38 -08:00
IWL_UCODE_MAJOR ( drv - > fw . ucode_ver ) ,
IWL_UCODE_MINOR ( drv - > fw . ucode_ver ) ,
IWL_UCODE_API ( drv - > fw . ucode_ver ) ,
IWL_UCODE_SERIAL ( drv - > fw . ucode_ver ) ,
2012-03-05 11:24:50 -08:00
buildstr ) ;
data = ucode - > data ;
len - = sizeof ( * ucode ) ;
while ( len > = sizeof ( * tlv ) ) {
len - = sizeof ( * tlv ) ;
tlv = ( void * ) data ;
tlv_len = le32_to_cpu ( tlv - > length ) ;
2012-03-09 09:16:35 +01:00
tlv_type = le32_to_cpu ( tlv - > type ) ;
2012-03-05 11:24:50 -08:00
tlv_data = tlv - > data ;
if ( len < tlv_len ) {
2012-03-06 13:30:38 -08:00
IWL_ERR ( drv , " invalid TLV len: %zd/%u \n " ,
2012-03-05 11:24:50 -08:00
len , tlv_len ) ;
return - EINVAL ;
}
len - = ALIGN ( tlv_len , 4 ) ;
data + = sizeof ( * tlv ) + ALIGN ( tlv_len , 4 ) ;
switch ( tlv_type ) {
case IWL_UCODE_TLV_INST :
2012-03-10 13:00:12 -08:00
set_sec_data ( pieces , IWL_UCODE_REGULAR ,
IWL_UCODE_SECTION_INST , tlv_data ) ;
set_sec_size ( pieces , IWL_UCODE_REGULAR ,
IWL_UCODE_SECTION_INST , tlv_len ) ;
set_sec_offset ( pieces , IWL_UCODE_REGULAR ,
IWL_UCODE_SECTION_INST ,
IWLAGN_RTC_INST_LOWER_BOUND ) ;
2012-03-05 11:24:50 -08:00
break ;
case IWL_UCODE_TLV_DATA :
2012-03-10 13:00:12 -08:00
set_sec_data ( pieces , IWL_UCODE_REGULAR ,
IWL_UCODE_SECTION_DATA , tlv_data ) ;
set_sec_size ( pieces , IWL_UCODE_REGULAR ,
IWL_UCODE_SECTION_DATA , tlv_len ) ;
set_sec_offset ( pieces , IWL_UCODE_REGULAR ,
IWL_UCODE_SECTION_DATA ,
IWLAGN_RTC_DATA_LOWER_BOUND ) ;
2012-03-05 11:24:50 -08:00
break ;
case IWL_UCODE_TLV_INIT :
2012-03-10 13:00:12 -08:00
set_sec_data ( pieces , IWL_UCODE_INIT ,
IWL_UCODE_SECTION_INST , tlv_data ) ;
set_sec_size ( pieces , IWL_UCODE_INIT ,
IWL_UCODE_SECTION_INST , tlv_len ) ;
set_sec_offset ( pieces , IWL_UCODE_INIT ,
IWL_UCODE_SECTION_INST ,
IWLAGN_RTC_INST_LOWER_BOUND ) ;
2012-03-05 11:24:50 -08:00
break ;
case IWL_UCODE_TLV_INIT_DATA :
2012-03-10 13:00:12 -08:00
set_sec_data ( pieces , IWL_UCODE_INIT ,
IWL_UCODE_SECTION_DATA , tlv_data ) ;
set_sec_size ( pieces , IWL_UCODE_INIT ,
IWL_UCODE_SECTION_DATA , tlv_len ) ;
set_sec_offset ( pieces , IWL_UCODE_INIT ,
IWL_UCODE_SECTION_DATA ,
IWLAGN_RTC_DATA_LOWER_BOUND ) ;
2012-03-05 11:24:50 -08:00
break ;
case IWL_UCODE_TLV_BOOT :
2012-03-06 13:30:38 -08:00
IWL_ERR ( drv , " Found unexpected BOOT ucode \n " ) ;
2012-03-05 11:24:50 -08:00
break ;
case IWL_UCODE_TLV_PROBE_MAX_LEN :
if ( tlv_len ! = sizeof ( u32 ) )
goto invalid_tlv_len ;
capa - > max_probe_length =
le32_to_cpup ( ( __le32 * ) tlv_data ) ;
break ;
case IWL_UCODE_TLV_PAN :
if ( tlv_len )
goto invalid_tlv_len ;
capa - > flags | = IWL_UCODE_TLV_FLAGS_PAN ;
break ;
case IWL_UCODE_TLV_FLAGS :
/* must be at least one u32 */
if ( tlv_len < sizeof ( u32 ) )
goto invalid_tlv_len ;
/* and a proper number of u32s */
if ( tlv_len % sizeof ( u32 ) )
goto invalid_tlv_len ;
/*
* This driver only reads the first u32 as
* right now no more features are defined ,
* if that changes then either the driver
* will not work with the new firmware , or
* it ' ll not take advantage of new features .
*/
capa - > flags = le32_to_cpup ( ( __le32 * ) tlv_data ) ;
break ;
2014-02-20 11:00:01 +02:00
case IWL_UCODE_TLV_API_CHANGES_SET :
if ( tlv_len ! = sizeof ( struct iwl_ucode_api ) )
goto invalid_tlv_len ;
if ( iwl_set_ucode_api_flags ( drv , tlv_data , capa ) )
goto tlv_error ;
break ;
case IWL_UCODE_TLV_ENABLED_CAPABILITIES :
if ( tlv_len ! = sizeof ( struct iwl_ucode_capa ) )
goto invalid_tlv_len ;
if ( iwl_set_ucode_capabilities ( drv , tlv_data , capa ) )
goto tlv_error ;
break ;
2012-03-05 11:24:50 -08:00
case IWL_UCODE_TLV_INIT_EVTLOG_PTR :
if ( tlv_len ! = sizeof ( u32 ) )
goto invalid_tlv_len ;
pieces - > init_evtlog_ptr =
le32_to_cpup ( ( __le32 * ) tlv_data ) ;
break ;
case IWL_UCODE_TLV_INIT_EVTLOG_SIZE :
if ( tlv_len ! = sizeof ( u32 ) )
goto invalid_tlv_len ;
pieces - > init_evtlog_size =
le32_to_cpup ( ( __le32 * ) tlv_data ) ;
break ;
case IWL_UCODE_TLV_INIT_ERRLOG_PTR :
if ( tlv_len ! = sizeof ( u32 ) )
goto invalid_tlv_len ;
pieces - > init_errlog_ptr =
le32_to_cpup ( ( __le32 * ) tlv_data ) ;
break ;
case IWL_UCODE_TLV_RUNT_EVTLOG_PTR :
if ( tlv_len ! = sizeof ( u32 ) )
goto invalid_tlv_len ;
pieces - > inst_evtlog_ptr =
le32_to_cpup ( ( __le32 * ) tlv_data ) ;
break ;
case IWL_UCODE_TLV_RUNT_EVTLOG_SIZE :
if ( tlv_len ! = sizeof ( u32 ) )
goto invalid_tlv_len ;
pieces - > inst_evtlog_size =
le32_to_cpup ( ( __le32 * ) tlv_data ) ;
break ;
case IWL_UCODE_TLV_RUNT_ERRLOG_PTR :
if ( tlv_len ! = sizeof ( u32 ) )
goto invalid_tlv_len ;
pieces - > inst_errlog_ptr =
le32_to_cpup ( ( __le32 * ) tlv_data ) ;
break ;
case IWL_UCODE_TLV_ENHANCE_SENS_TBL :
if ( tlv_len )
goto invalid_tlv_len ;
2012-03-06 13:30:38 -08:00
drv - > fw . enhance_sensitivity_table = true ;
2012-03-05 11:24:50 -08:00
break ;
case IWL_UCODE_TLV_WOWLAN_INST :
2012-03-10 13:00:12 -08:00
set_sec_data ( pieces , IWL_UCODE_WOWLAN ,
IWL_UCODE_SECTION_INST , tlv_data ) ;
set_sec_size ( pieces , IWL_UCODE_WOWLAN ,
IWL_UCODE_SECTION_INST , tlv_len ) ;
set_sec_offset ( pieces , IWL_UCODE_WOWLAN ,
IWL_UCODE_SECTION_INST ,
IWLAGN_RTC_INST_LOWER_BOUND ) ;
2012-03-05 11:24:50 -08:00
break ;
case IWL_UCODE_TLV_WOWLAN_DATA :
2012-03-10 13:00:12 -08:00
set_sec_data ( pieces , IWL_UCODE_WOWLAN ,
IWL_UCODE_SECTION_DATA , tlv_data ) ;
set_sec_size ( pieces , IWL_UCODE_WOWLAN ,
IWL_UCODE_SECTION_DATA , tlv_len ) ;
set_sec_offset ( pieces , IWL_UCODE_WOWLAN ,
IWL_UCODE_SECTION_DATA ,
IWLAGN_RTC_DATA_LOWER_BOUND ) ;
2012-03-05 11:24:50 -08:00
break ;
case IWL_UCODE_TLV_PHY_CALIBRATION_SIZE :
if ( tlv_len ! = sizeof ( u32 ) )
goto invalid_tlv_len ;
capa - > standard_phy_calibration_size =
le32_to_cpup ( ( __le32 * ) tlv_data ) ;
break ;
2012-03-10 13:00:13 -08:00
case IWL_UCODE_TLV_SEC_RT :
iwl_store_ucode_sec ( pieces , tlv_data , IWL_UCODE_REGULAR ,
tlv_len ) ;
2012-03-10 13:00:15 -08:00
drv - > fw . mvm_fw = true ;
2012-03-10 13:00:13 -08:00
break ;
case IWL_UCODE_TLV_SEC_INIT :
iwl_store_ucode_sec ( pieces , tlv_data , IWL_UCODE_INIT ,
tlv_len ) ;
2012-03-10 13:00:15 -08:00
drv - > fw . mvm_fw = true ;
2012-03-10 13:00:13 -08:00
break ;
case IWL_UCODE_TLV_SEC_WOWLAN :
iwl_store_ucode_sec ( pieces , tlv_data , IWL_UCODE_WOWLAN ,
tlv_len ) ;
2012-03-10 13:00:15 -08:00
drv - > fw . mvm_fw = true ;
2012-03-10 13:00:13 -08:00
break ;
case IWL_UCODE_TLV_DEF_CALIB :
if ( tlv_len ! = sizeof ( struct iwl_tlv_calib_data ) )
goto invalid_tlv_len ;
if ( iwl_set_default_calib ( drv , tlv_data ) )
goto tlv_error ;
break ;
case IWL_UCODE_TLV_PHY_SKU :
if ( tlv_len ! = sizeof ( u32 ) )
goto invalid_tlv_len ;
drv - > fw . phy_config = le32_to_cpup ( ( __le32 * ) tlv_data ) ;
2014-02-04 14:21:38 +02:00
drv - > fw . valid_tx_ant = ( drv - > fw . phy_config &
FW_PHY_CFG_TX_CHAIN ) > >
FW_PHY_CFG_TX_CHAIN_POS ;
drv - > fw . valid_rx_ant = ( drv - > fw . phy_config &
FW_PHY_CFG_RX_CHAIN ) > >
FW_PHY_CFG_RX_CHAIN_POS ;
2012-03-10 13:00:13 -08:00
break ;
2013-10-02 13:53:40 +03:00
case IWL_UCODE_TLV_SECURE_SEC_RT :
iwl_store_ucode_sec ( pieces , tlv_data , IWL_UCODE_REGULAR ,
tlv_len ) ;
drv - > fw . mvm_fw = true ;
break ;
case IWL_UCODE_TLV_SECURE_SEC_INIT :
iwl_store_ucode_sec ( pieces , tlv_data , IWL_UCODE_INIT ,
tlv_len ) ;
drv - > fw . mvm_fw = true ;
break ;
case IWL_UCODE_TLV_SECURE_SEC_WOWLAN :
iwl_store_ucode_sec ( pieces , tlv_data , IWL_UCODE_WOWLAN ,
tlv_len ) ;
drv - > fw . mvm_fw = true ;
break ;
case IWL_UCODE_TLV_NUM_OF_CPU :
if ( tlv_len ! = sizeof ( u32 ) )
goto invalid_tlv_len ;
num_of_cpus =
le32_to_cpup ( ( __le32 * ) tlv_data ) ;
if ( num_of_cpus = = 2 ) {
drv - > fw . img [ IWL_UCODE_REGULAR ] . is_dual_cpus =
true ;
drv - > fw . img [ IWL_UCODE_INIT ] . is_dual_cpus =
true ;
drv - > fw . img [ IWL_UCODE_WOWLAN ] . is_dual_cpus =
true ;
} else if ( ( num_of_cpus > 2 ) | | ( num_of_cpus < 1 ) ) {
IWL_ERR ( drv , " Driver support upto 2 CPUs \n " ) ;
return - EINVAL ;
}
break ;
2013-08-27 19:56:13 +03:00
case IWL_UCODE_TLV_CSCHEME :
if ( iwl_store_cscheme ( & drv - > fw , tlv_data , tlv_len ) )
goto invalid_tlv_len ;
break ;
2014-06-05 11:20:43 +03:00
case IWL_UCODE_TLV_N_SCAN_CHANNELS :
if ( tlv_len ! = sizeof ( u32 ) )
goto invalid_tlv_len ;
capa - > n_scan_channels =
le32_to_cpup ( ( __le32 * ) tlv_data ) ;
break ;
2015-02-03 20:11:48 +02:00
case IWL_UCODE_TLV_FW_VERSION : {
__le32 * ptr = ( void * ) tlv_data ;
u32 major , minor ;
u8 local_comp ;
if ( tlv_len ! = sizeof ( u32 ) * 3 )
goto invalid_tlv_len ;
major = le32_to_cpup ( ptr + + ) ;
minor = le32_to_cpup ( ptr + + ) ;
local_comp = le32_to_cpup ( ptr ) ;
snprintf ( drv - > fw . fw_version ,
sizeof ( drv - > fw . fw_version ) , " %u.%u.%u " ,
major , minor , local_comp ) ;
break ;
}
2014-09-16 15:06:54 +03:00
case IWL_UCODE_TLV_FW_DBG_DEST : {
struct iwl_fw_dbg_dest_tlv * dest = ( void * ) tlv_data ;
if ( pieces - > dbg_dest_tlv ) {
IWL_ERR ( drv ,
" dbg destination ignored, already exists \n " ) ;
break ;
}
pieces - > dbg_dest_tlv = dest ;
IWL_INFO ( drv , " Found debug destination: %s \n " ,
get_fw_dbg_mode_string ( dest - > monitor_mode ) ) ;
drv - > fw . dbg_dest_reg_num =
tlv_len - offsetof ( struct iwl_fw_dbg_dest_tlv ,
reg_ops ) ;
drv - > fw . dbg_dest_reg_num / =
sizeof ( drv - > fw . dbg_dest_tlv - > reg_ops [ 0 ] ) ;
break ;
}
case IWL_UCODE_TLV_FW_DBG_CONF : {
struct iwl_fw_dbg_conf_tlv * conf = ( void * ) tlv_data ;
if ( ! pieces - > dbg_dest_tlv ) {
IWL_ERR ( drv ,
" Ignore dbg config %d - no destination configured \n " ,
conf - > id ) ;
break ;
}
if ( conf - > id > = ARRAY_SIZE ( drv - > fw . dbg_conf_tlv ) ) {
IWL_ERR ( drv ,
" Skip unknown configuration: %d \n " ,
conf - > id ) ;
break ;
}
if ( pieces - > dbg_conf_tlv [ conf - > id ] ) {
IWL_ERR ( drv ,
" Ignore duplicate dbg config %d \n " ,
conf - > id ) ;
break ;
}
2014-12-01 17:40:37 +02:00
if ( conf - > usniffer )
usniffer_req = true ;
2014-09-16 15:06:54 +03:00
IWL_INFO ( drv , " Found debug configuration: %d \n " ,
conf - > id ) ;
pieces - > dbg_conf_tlv [ conf - > id ] = conf ;
pieces - > dbg_conf_tlv_len [ conf - > id ] = tlv_len ;
break ;
}
2015-01-29 14:58:06 +02:00
case IWL_UCODE_TLV_FW_DBG_TRIGGER : {
struct iwl_fw_dbg_trigger_tlv * trigger =
( void * ) tlv_data ;
u32 trigger_id = le32_to_cpu ( trigger - > id ) ;
if ( trigger_id > = ARRAY_SIZE ( drv - > fw . dbg_trigger_tlv ) ) {
IWL_ERR ( drv ,
" Skip unknown trigger: %u \n " ,
trigger - > id ) ;
break ;
}
if ( pieces - > dbg_trigger_tlv [ trigger_id ] ) {
IWL_ERR ( drv ,
" Ignore duplicate dbg trigger %u \n " ,
trigger - > id ) ;
break ;
}
IWL_INFO ( drv , " Found debug trigger: %u \n " , trigger - > id ) ;
pieces - > dbg_trigger_tlv [ trigger_id ] = trigger ;
pieces - > dbg_trigger_tlv_len [ trigger_id ] = tlv_len ;
break ;
}
2014-12-01 17:40:37 +02:00
case IWL_UCODE_TLV_SEC_RT_USNIFFER :
usniffer_images = true ;
iwl_store_ucode_sec ( pieces , tlv_data ,
IWL_UCODE_REGULAR_USNIFFER ,
tlv_len ) ;
break ;
2014-10-19 16:58:15 +02:00
case IWL_UCODE_TLV_SDIO_ADMA_ADDR :
if ( tlv_len ! = sizeof ( u32 ) )
goto invalid_tlv_len ;
drv - > fw . sdio_adma_addr =
le32_to_cpup ( ( __le32 * ) tlv_data ) ;
break ;
2012-03-05 11:24:50 -08:00
default :
2012-03-06 13:30:38 -08:00
IWL_DEBUG_INFO ( drv , " unknown TLV: %d \n " , tlv_type ) ;
2012-03-05 11:24:50 -08:00
break ;
}
}
2014-12-01 17:40:37 +02:00
if ( usniffer_req & & ! usniffer_images ) {
IWL_ERR ( drv ,
" user selected to work with usniffer but usniffer image isn't available in ucode package \n " ) ;
return - EINVAL ;
}
2012-03-05 11:24:50 -08:00
if ( len ) {
2012-03-06 13:30:38 -08:00
IWL_ERR ( drv , " invalid TLV after parsing: %zd \n " , len ) ;
iwl_print_hex_dump ( drv , IWL_DL_FW , ( u8 * ) data , len ) ;
2012-03-05 11:24:50 -08:00
return - EINVAL ;
}
return 0 ;
invalid_tlv_len :
2012-03-06 13:30:38 -08:00
IWL_ERR ( drv , " TLV %d has invalid size: %u \n " , tlv_type , tlv_len ) ;
2012-03-10 13:00:13 -08:00
tlv_error :
2012-03-06 13:30:38 -08:00
iwl_print_hex_dump ( drv , IWL_DL_FW , tlv_data , tlv_len ) ;
2012-03-05 11:24:50 -08:00
return - EINVAL ;
}
2012-05-16 22:49:49 +02:00
static int iwl_alloc_ucode ( struct iwl_drv * drv ,
struct iwl_firmware_pieces * pieces ,
enum iwl_ucode_type type )
2012-03-10 13:00:14 -08:00
{
int i ;
for ( i = 0 ;
i < IWL_UCODE_SECTION_MAX & & get_sec_size ( pieces , type , i ) ;
i + + )
if ( iwl_alloc_fw_desc ( drv , & ( drv - > fw . img [ type ] . sec [ i ] ) ,
2012-05-16 22:49:49 +02:00
get_sec ( pieces , type , i ) ) )
return - ENOMEM ;
2012-03-10 13:00:14 -08:00
return 0 ;
}
static int validate_sec_sizes ( struct iwl_drv * drv ,
struct iwl_firmware_pieces * pieces ,
const struct iwl_cfg * cfg )
{
IWL_DEBUG_INFO ( drv , " f/w package hdr runtime inst size = %Zd \n " ,
get_sec_size ( pieces , IWL_UCODE_REGULAR ,
IWL_UCODE_SECTION_INST ) ) ;
IWL_DEBUG_INFO ( drv , " f/w package hdr runtime data size = %Zd \n " ,
get_sec_size ( pieces , IWL_UCODE_REGULAR ,
IWL_UCODE_SECTION_DATA ) ) ;
IWL_DEBUG_INFO ( drv , " f/w package hdr init inst size = %Zd \n " ,
get_sec_size ( pieces , IWL_UCODE_INIT , IWL_UCODE_SECTION_INST ) ) ;
IWL_DEBUG_INFO ( drv , " f/w package hdr init data size = %Zd \n " ,
get_sec_size ( pieces , IWL_UCODE_INIT , IWL_UCODE_SECTION_DATA ) ) ;
/* Verify that uCode images will fit in card's SRAM. */
if ( get_sec_size ( pieces , IWL_UCODE_REGULAR , IWL_UCODE_SECTION_INST ) >
cfg - > max_inst_size ) {
IWL_ERR ( drv , " uCode instr len %Zd too large to fit in \n " ,
get_sec_size ( pieces , IWL_UCODE_REGULAR ,
IWL_UCODE_SECTION_INST ) ) ;
return - 1 ;
}
if ( get_sec_size ( pieces , IWL_UCODE_REGULAR , IWL_UCODE_SECTION_DATA ) >
cfg - > max_data_size ) {
IWL_ERR ( drv , " uCode data len %Zd too large to fit in \n " ,
get_sec_size ( pieces , IWL_UCODE_REGULAR ,
IWL_UCODE_SECTION_DATA ) ) ;
return - 1 ;
}
if ( get_sec_size ( pieces , IWL_UCODE_INIT , IWL_UCODE_SECTION_INST ) >
cfg - > max_inst_size ) {
IWL_ERR ( drv , " uCode init instr len %Zd too large to fit in \n " ,
get_sec_size ( pieces , IWL_UCODE_INIT ,
IWL_UCODE_SECTION_INST ) ) ;
return - 1 ;
}
if ( get_sec_size ( pieces , IWL_UCODE_INIT , IWL_UCODE_SECTION_DATA ) >
cfg - > max_data_size ) {
IWL_ERR ( drv , " uCode init data len %Zd too large to fit in \n " ,
get_sec_size ( pieces , IWL_UCODE_REGULAR ,
IWL_UCODE_SECTION_DATA ) ) ;
return - 1 ;
}
return 0 ;
}
2012-07-16 18:43:56 -07:00
static struct iwl_op_mode *
_iwl_op_mode_start ( struct iwl_drv * drv , struct iwlwifi_opmode_table * op )
{
const struct iwl_op_mode_ops * ops = op - > ops ;
struct dentry * dbgfs_dir = NULL ;
struct iwl_op_mode * op_mode = NULL ;
# ifdef CONFIG_IWLWIFI_DEBUGFS
drv - > dbgfs_op_mode = debugfs_create_dir ( op - > name ,
drv - > dbgfs_drv ) ;
if ( ! drv - > dbgfs_op_mode ) {
IWL_ERR ( drv ,
" failed to create opmode debugfs directory \n " ) ;
return op_mode ;
}
dbgfs_dir = drv - > dbgfs_op_mode ;
# endif
op_mode = ops - > start ( drv - > trans , drv - > cfg , & drv - > fw , dbgfs_dir ) ;
# ifdef CONFIG_IWLWIFI_DEBUGFS
if ( ! op_mode ) {
debugfs_remove_recursive ( drv - > dbgfs_op_mode ) ;
drv - > dbgfs_op_mode = NULL ;
}
# endif
return op_mode ;
}
static void _iwl_op_mode_stop ( struct iwl_drv * drv )
{
/* op_mode can be NULL if its start failed */
if ( drv - > op_mode ) {
iwl_op_mode_stop ( drv - > op_mode ) ;
drv - > op_mode = NULL ;
# ifdef CONFIG_IWLWIFI_DEBUGFS
debugfs_remove_recursive ( drv - > dbgfs_op_mode ) ;
drv - > dbgfs_op_mode = NULL ;
# endif
}
}
2012-03-05 11:24:50 -08:00
/**
2012-07-16 12:31:28 +03:00
* iwl_req_fw_callback - callback when firmware was loaded
2012-03-05 11:24:50 -08:00
*
* If loaded successfully , copies the firmware into buffers
* for the card to fetch ( via DMA ) .
*/
2012-07-16 12:31:28 +03:00
static void iwl_req_fw_callback ( const struct firmware * ucode_raw , void * context )
2012-03-05 11:24:50 -08:00
{
2012-03-06 13:30:38 -08:00
struct iwl_drv * drv = context ;
struct iwl_fw * fw = & drv - > fw ;
2012-03-05 11:24:50 -08:00
struct iwl_ucode_header * ucode ;
2012-05-16 22:54:27 +02:00
struct iwlwifi_opmode_table * op ;
2012-03-05 11:24:50 -08:00
int err ;
2014-09-16 15:06:54 +03:00
struct iwl_firmware_pieces * pieces ;
2012-03-22 17:51:44 +02:00
const unsigned int api_max = drv - > cfg - > ucode_api_max ;
unsigned int api_ok = drv - > cfg - > ucode_api_ok ;
const unsigned int api_min = drv - > cfg - > ucode_api_min ;
2012-03-05 11:24:50 -08:00
u32 api_ver ;
2012-03-10 13:00:14 -08:00
int i ;
2012-06-12 19:50:43 +02:00
bool load_module = false ;
2012-03-05 11:24:50 -08:00
2013-08-12 19:30:21 +03:00
fw - > ucode_capa . max_probe_length = IWL_DEFAULT_MAX_PROBE_LENGTH ;
2012-03-05 11:24:50 -08:00
fw - > ucode_capa . standard_phy_calibration_size =
IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE ;
2014-06-05 11:20:43 +03:00
fw - > ucode_capa . n_scan_channels = IWL_DEFAULT_SCAN_CHANNELS ;
2012-03-05 11:24:50 -08:00
if ( ! api_ok )
api_ok = api_max ;
2014-09-16 15:06:54 +03:00
pieces = kzalloc ( sizeof ( * pieces ) , GFP_KERNEL ) ;
if ( ! pieces )
return ;
2012-03-05 11:24:50 -08:00
if ( ! ucode_raw ) {
2012-03-06 13:30:38 -08:00
if ( drv - > fw_index < = api_ok )
IWL_ERR ( drv ,
2012-03-05 11:24:50 -08:00
" request for firmware file '%s' failed. \n " ,
2012-03-06 13:30:38 -08:00
drv - > firmware_name ) ;
2012-03-05 11:24:50 -08:00
goto try_again ;
}
2012-03-06 13:30:38 -08:00
IWL_DEBUG_INFO ( drv , " Loaded firmware file '%s' (%zd bytes). \n " ,
drv - > firmware_name , ucode_raw - > size ) ;
2012-03-05 11:24:50 -08:00
/* Make sure that we got at least the API version number */
if ( ucode_raw - > size < 4 ) {
2012-03-06 13:30:38 -08:00
IWL_ERR ( drv , " File size way too small! \n " ) ;
2012-03-05 11:24:50 -08:00
goto try_again ;
}
/* Data from ucode file: header followed by uCode images */
ucode = ( struct iwl_ucode_header * ) ucode_raw - > data ;
if ( ucode - > ver )
2014-09-16 15:06:54 +03:00
err = iwl_parse_v1_v2_firmware ( drv , ucode_raw , pieces ) ;
2012-03-05 11:24:50 -08:00
else
2014-09-16 15:06:54 +03:00
err = iwl_parse_tlv_firmware ( drv , ucode_raw , pieces ,
& fw - > ucode_capa ) ;
2012-03-05 11:24:50 -08:00
if ( err )
goto try_again ;
2015-02-03 20:11:48 +02:00
if ( drv - > fw . ucode_capa . api [ 0 ] & IWL_UCODE_TLV_API_NEW_VERSION )
api_ver = drv - > fw . ucode_ver ;
else
api_ver = IWL_UCODE_API ( drv - > fw . ucode_ver ) ;
2012-03-05 11:24:50 -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
* on the API version read from firmware header from here on forward
*/
/* no api version check required for experimental uCode */
2012-03-06 13:30:38 -08:00
if ( drv - > fw_index ! = UCODE_EXPERIMENTAL_INDEX ) {
2012-03-05 11:24:50 -08:00
if ( api_ver < api_min | | api_ver > api_max ) {
2012-03-06 13:30:38 -08:00
IWL_ERR ( drv ,
2012-03-05 11:24:50 -08:00
" Driver unable to support your firmware API. "
" Driver supports v%u, firmware is v%u. \n " ,
api_max , api_ver ) ;
goto try_again ;
}
if ( api_ver < api_ok ) {
if ( api_ok ! = api_max )
2012-03-06 13:30:38 -08:00
IWL_ERR ( drv , " Firmware has old API version, "
2012-03-05 11:24:50 -08:00
" expected v%u through v%u, got v%u. \n " ,
api_ok , api_max , api_ver ) ;
else
2012-03-06 13:30:38 -08:00
IWL_ERR ( drv , " Firmware has old API version, "
2012-03-05 11:24:50 -08:00
" expected v%u, got v%u. \n " ,
api_max , api_ver ) ;
2012-03-06 13:30:38 -08:00
IWL_ERR ( drv , " New firmware can be obtained from "
2012-03-05 11:24:50 -08:00
" http://www.intellinuxwireless.org/. \n " ) ;
}
}
2012-03-10 13:00:15 -08:00
/*
* In mvm uCode there is no difference between data and instructions
* sections .
*/
2014-09-16 15:06:54 +03:00
if ( ! fw - > mvm_fw & & validate_sec_sizes ( drv , pieces , drv - > cfg ) )
2012-03-05 11:24:50 -08:00
goto try_again ;
/* 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 */
2012-03-10 13:00:14 -08:00
for ( i = 0 ; i < IWL_UCODE_TYPE_MAX ; i + + )
2014-09-16 15:06:54 +03:00
if ( iwl_alloc_ucode ( drv , pieces , i ) )
2012-05-16 22:49:49 +02:00
goto out_free_fw ;
2012-03-05 11:24:50 -08:00
2014-09-16 15:06:54 +03:00
if ( pieces - > dbg_dest_tlv ) {
drv - > fw . dbg_dest_tlv =
kmemdup ( pieces - > dbg_dest_tlv ,
sizeof ( * pieces - > dbg_dest_tlv ) +
sizeof ( pieces - > dbg_dest_tlv - > reg_ops [ 0 ] ) *
drv - > fw . dbg_dest_reg_num , GFP_KERNEL ) ;
if ( ! drv - > fw . dbg_dest_tlv )
goto out_free_fw ;
}
for ( i = 0 ; i < ARRAY_SIZE ( drv - > fw . dbg_conf_tlv ) ; i + + ) {
if ( pieces - > dbg_conf_tlv [ i ] ) {
drv - > fw . dbg_conf_tlv_len [ i ] =
pieces - > dbg_conf_tlv_len [ i ] ;
drv - > fw . dbg_conf_tlv [ i ] =
kmemdup ( pieces - > dbg_conf_tlv [ i ] ,
drv - > fw . dbg_conf_tlv_len [ i ] ,
GFP_KERNEL ) ;
if ( ! drv - > fw . dbg_conf_tlv [ i ] )
goto out_free_fw ;
}
}
2015-01-29 14:58:06 +02:00
for ( i = 0 ; i < ARRAY_SIZE ( drv - > fw . dbg_trigger_tlv ) ; i + + ) {
if ( pieces - > dbg_trigger_tlv [ i ] ) {
drv - > fw . dbg_trigger_tlv_len [ i ] =
pieces - > dbg_trigger_tlv_len [ i ] ;
drv - > fw . dbg_trigger_tlv [ i ] =
kmemdup ( pieces - > dbg_trigger_tlv [ i ] ,
drv - > fw . dbg_trigger_tlv_len [ i ] ,
GFP_KERNEL ) ;
if ( ! drv - > fw . dbg_trigger_tlv [ i ] )
goto out_free_fw ;
}
}
2012-03-05 11:24:50 -08:00
/* Now that we can no longer fail, copy information */
/*
* The ( size - 16 ) / 12 formula is based on the information recorded
* for each event , which is of mode 1 ( including timestamp ) for all
* new microcodes that include this information .
*/
2014-09-16 15:06:54 +03:00
fw - > init_evtlog_ptr = pieces - > init_evtlog_ptr ;
if ( pieces - > init_evtlog_size )
fw - > init_evtlog_size = ( pieces - > init_evtlog_size - 16 ) / 12 ;
2012-03-05 11:24:50 -08:00
else
2012-03-06 13:30:37 -08:00
fw - > init_evtlog_size =
2012-03-22 17:51:44 +02:00
drv - > cfg - > base_params - > max_event_log_size ;
2014-09-16 15:06:54 +03:00
fw - > init_errlog_ptr = pieces - > init_errlog_ptr ;
fw - > inst_evtlog_ptr = pieces - > inst_evtlog_ptr ;
if ( pieces - > inst_evtlog_size )
fw - > inst_evtlog_size = ( pieces - > inst_evtlog_size - 16 ) / 12 ;
2012-03-05 11:24:50 -08:00
else
2012-03-06 13:30:37 -08:00
fw - > inst_evtlog_size =
2012-03-22 17:51:44 +02:00
drv - > cfg - > base_params - > max_event_log_size ;
2014-09-16 15:06:54 +03:00
fw - > inst_errlog_ptr = pieces - > inst_errlog_ptr ;
2012-03-05 11:24:50 -08:00
/*
* figure out the offset of chain noise reset and gain commands
* base on the size of standard phy calibration commands table size
*/
if ( fw - > ucode_capa . standard_phy_calibration_size >
IWL_MAX_PHY_CALIBRATE_TBL_SIZE )
fw - > ucode_capa . standard_phy_calibration_size =
IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE ;
/* We have our copies now, allow OS release its copies */
release_firmware ( ucode_raw ) ;
2012-06-06 09:42:57 +02:00
mutex_lock ( & iwlwifi_opmode_table_mtx ) ;
2013-01-24 14:25:36 +01:00
if ( fw - > mvm_fw )
op = & iwlwifi_opmode_table [ MVM_OP_MODE ] ;
else
op = & iwlwifi_opmode_table [ DVM_OP_MODE ] ;
2012-03-05 11:24:50 -08:00
2013-03-26 11:41:51 +01:00
IWL_INFO ( drv , " loaded firmware version %s op_mode %s \n " ,
drv - > fw . fw_version , op - > name ) ;
2012-05-16 22:54:27 +02:00
/* add this device to the list of devices using this op_mode */
list_add_tail ( & drv - > list , & op - > drv ) ;
if ( op - > ops ) {
2012-07-16 18:43:56 -07:00
drv - > op_mode = _iwl_op_mode_start ( drv , op ) ;
2012-06-06 14:40:06 -04:00
2012-06-14 21:35:26 +03:00
if ( ! drv - > op_mode ) {
mutex_unlock ( & iwlwifi_opmode_table_mtx ) ;
2012-06-06 14:40:06 -04:00
goto out_unbind ;
2012-06-14 21:35:26 +03:00
}
2012-05-16 22:54:27 +02:00
} else {
2012-06-12 19:50:43 +02:00
load_module = true ;
2012-05-16 22:54:27 +02:00
}
2012-06-06 09:42:57 +02:00
mutex_unlock ( & iwlwifi_opmode_table_mtx ) ;
2012-03-05 11:24:50 -08:00
2012-06-05 19:56:06 +02:00
/*
* Complete the firmware request last so that
* a driver unbind ( stop ) doesn ' t run while we
* are doing the start ( ) above .
*/
complete ( & drv - > request_firmware_complete ) ;
2012-06-12 19:50:43 +02:00
/*
* Load the module last so we don ' t block anything
* else from proceeding if the module fails to load
* or hangs loading .
*/
2013-04-04 10:35:23 +02:00
if ( load_module ) {
err = request_module ( " %s " , op - > name ) ;
2013-05-28 21:32:47 +02:00
# ifdef CONFIG_IWLWIFI_OPMODE_MODULAR
2013-04-04 10:35:23 +02:00
if ( err )
IWL_ERR ( drv ,
" failed to load module %s (error %d), is dynamic loading enabled? \n " ,
op - > name , err ) ;
2013-05-28 21:32:47 +02:00
# endif
2013-04-04 10:35:23 +02:00
}
2012-03-05 11:24:50 -08:00
return ;
try_again :
/* try next, if any */
release_firmware ( ucode_raw ) ;
2012-03-06 13:30:38 -08:00
if ( iwl_request_firmware ( drv , false ) )
2012-03-05 11:24:50 -08:00
goto out_unbind ;
2014-12-03 08:25:44 +02:00
kfree ( pieces ) ;
2012-03-05 11:24:50 -08:00
return ;
2012-05-16 22:49:49 +02:00
out_free_fw :
2012-03-06 13:30:38 -08:00
IWL_ERR ( drv , " failed to allocate pci memory \n " ) ;
iwl_dealloc_ucode ( drv ) ;
2012-03-05 11:24:50 -08:00
release_firmware ( ucode_raw ) ;
out_unbind :
2014-09-16 15:06:54 +03:00
kfree ( pieces ) ;
2012-03-06 13:30:38 -08:00
complete ( & drv - > request_firmware_complete ) ;
2012-03-22 17:51:44 +02:00
device_release_driver ( drv - > trans - > dev ) ;
2012-03-05 11:24:50 -08:00
}
2012-03-26 09:03:18 -07:00
struct iwl_drv * iwl_drv_start ( struct iwl_trans * trans ,
2012-03-26 08:51:09 -07:00
const struct iwl_cfg * cfg )
2012-02-07 14:18:40 +02:00
{
2012-03-06 13:30:38 -08:00
struct iwl_drv * drv ;
2012-02-07 14:18:40 +02:00
int ret ;
2012-03-06 13:30:38 -08:00
drv = kzalloc ( sizeof ( * drv ) , GFP_KERNEL ) ;
2013-08-13 10:34:55 +03:00
if ( ! drv ) {
ret = - ENOMEM ;
goto err ;
}
2012-04-19 10:29:58 +03:00
2012-03-26 08:51:09 -07:00
drv - > trans = trans ;
2012-03-22 23:59:52 +02:00
drv - > dev = trans - > dev ;
2012-03-22 17:51:44 +02:00
drv - > cfg = cfg ;
2012-02-07 14:18:40 +02:00
2012-03-06 13:30:38 -08:00
init_completion ( & drv - > request_firmware_complete ) ;
2012-06-06 09:42:57 +02:00
INIT_LIST_HEAD ( & drv - > list ) ;
2012-02-07 14:18:40 +02:00
2012-07-16 18:43:56 -07:00
# ifdef CONFIG_IWLWIFI_DEBUGFS
/* Create the device debugfs entries. */
drv - > dbgfs_drv = debugfs_create_dir ( dev_name ( trans - > dev ) ,
iwl_dbgfs_root ) ;
if ( ! drv - > dbgfs_drv ) {
IWL_ERR ( drv , " failed to create debugfs directory \n " ) ;
2012-11-28 16:42:09 +02:00
ret = - ENOMEM ;
2012-07-16 18:43:56 -07:00
goto err_free_drv ;
}
/* Create transport layer debugfs dir */
drv - > trans - > dbgfs_dir = debugfs_create_dir ( " trans " , drv - > dbgfs_drv ) ;
if ( ! drv - > trans - > dbgfs_dir ) {
IWL_ERR ( drv , " failed to create transport debugfs directory \n " ) ;
2012-11-28 16:42:09 +02:00
ret = - ENOMEM ;
2012-07-16 18:43:56 -07:00
goto err_free_dbgfs ;
}
# endif
2012-03-06 13:30:38 -08:00
ret = iwl_request_firmware ( drv , true ) ;
2012-02-07 14:18:40 +02:00
if ( ret ) {
2012-04-19 10:29:58 +03:00
IWL_ERR ( trans , " Couldn't request the fw \n " ) ;
2012-07-16 18:43:56 -07:00
goto err_fw ;
2012-02-07 14:18:40 +02:00
}
2012-07-16 18:43:56 -07:00
return drv ;
err_fw :
# ifdef CONFIG_IWLWIFI_DEBUGFS
err_free_dbgfs :
debugfs_remove_recursive ( drv - > dbgfs_drv ) ;
err_free_drv :
# endif
kfree ( drv ) ;
2013-08-13 10:34:55 +03:00
err :
2012-11-28 16:42:09 +02:00
return ERR_PTR ( ret ) ;
2012-02-07 14:18:40 +02:00
}
2012-03-26 08:51:09 -07:00
void iwl_drv_stop ( struct iwl_drv * drv )
2012-02-07 14:27:31 +02:00
{
2012-03-06 13:30:38 -08:00
wait_for_completion ( & drv - > request_firmware_complete ) ;
2012-03-05 11:24:51 -08:00
2012-07-16 18:43:56 -07:00
_iwl_op_mode_stop ( drv ) ;
2012-02-07 14:27:31 +02:00
2012-03-06 13:30:38 -08:00
iwl_dealloc_ucode ( drv ) ;
2012-03-05 11:24:48 -08:00
2012-06-06 09:42:57 +02:00
mutex_lock ( & iwlwifi_opmode_table_mtx ) ;
/*
* List is empty ( this item wasn ' t added )
* when firmware loading failed - - in that
* case we can ' t remove it from any list .
*/
if ( ! list_empty ( & drv - > list ) )
list_del ( & drv - > list ) ;
mutex_unlock ( & iwlwifi_opmode_table_mtx ) ;
2012-07-16 18:43:56 -07:00
# ifdef CONFIG_IWLWIFI_DEBUGFS
debugfs_remove_recursive ( drv - > dbgfs_drv ) ;
# endif
2012-03-06 13:30:38 -08:00
kfree ( drv ) ;
2012-02-07 14:27:31 +02:00
}
2012-04-17 07:36:30 -07:00
/* shared module parameters */
struct iwl_mod_params iwlwifi_mod_params = {
2013-03-04 08:53:07 +02:00
. restart_fw = true ,
2012-04-17 07:36:30 -07:00
. bt_coex_active = true ,
. power_level = IWL_POWER_INDEX_1 ,
2014-11-20 17:33:43 +02:00
. d0i3_disable = true ,
2014-09-01 11:28:11 +02:00
# ifndef CONFIG_IWLWIFI_UAPSD
. uapsd_disable = true ,
# endif /* CONFIG_IWLWIFI_UAPSD */
2012-04-17 07:36:30 -07:00
/* the rest are 0 by default */
} ;
2013-03-01 00:13:33 +01:00
IWL_EXPORT_SYMBOL ( iwlwifi_mod_params ) ;
2012-05-16 22:54:27 +02:00
int iwl_opmode_register ( const char * name , const struct iwl_op_mode_ops * ops )
{
int i ;
struct iwl_drv * drv ;
2012-07-16 18:43:56 -07:00
struct iwlwifi_opmode_table * op ;
2012-05-16 22:54:27 +02:00
2012-06-06 09:42:57 +02:00
mutex_lock ( & iwlwifi_opmode_table_mtx ) ;
2012-05-16 22:54:27 +02:00
for ( i = 0 ; i < ARRAY_SIZE ( iwlwifi_opmode_table ) ; i + + ) {
2012-07-16 18:43:56 -07:00
op = & iwlwifi_opmode_table [ i ] ;
if ( strcmp ( op - > name , name ) )
2012-05-16 22:54:27 +02:00
continue ;
2012-07-16 18:43:56 -07:00
op - > ops = ops ;
/* TODO: need to handle exceptional case */
list_for_each_entry ( drv , & op - > drv , list )
drv - > op_mode = _iwl_op_mode_start ( drv , op ) ;
2012-06-06 09:42:57 +02:00
mutex_unlock ( & iwlwifi_opmode_table_mtx ) ;
2012-05-16 22:54:27 +02:00
return 0 ;
}
2012-06-06 09:42:57 +02:00
mutex_unlock ( & iwlwifi_opmode_table_mtx ) ;
2012-05-16 22:54:27 +02:00
return - EIO ;
}
2013-03-01 00:13:33 +01:00
IWL_EXPORT_SYMBOL ( iwl_opmode_register ) ;
2012-05-16 22:54:27 +02:00
void iwl_opmode_deregister ( const char * name )
{
int i ;
struct iwl_drv * drv ;
2012-06-06 09:42:57 +02:00
mutex_lock ( & iwlwifi_opmode_table_mtx ) ;
2012-05-16 22:54:27 +02:00
for ( i = 0 ; i < ARRAY_SIZE ( iwlwifi_opmode_table ) ; i + + ) {
if ( strcmp ( iwlwifi_opmode_table [ i ] . name , name ) )
continue ;
iwlwifi_opmode_table [ i ] . ops = NULL ;
/* call the stop routine for all devices */
2012-07-16 18:43:56 -07:00
list_for_each_entry ( drv , & iwlwifi_opmode_table [ i ] . drv , list )
_iwl_op_mode_stop ( drv ) ;
2012-06-06 09:42:57 +02:00
mutex_unlock ( & iwlwifi_opmode_table_mtx ) ;
2012-05-16 22:54:27 +02:00
return ;
}
2012-06-06 09:42:57 +02:00
mutex_unlock ( & iwlwifi_opmode_table_mtx ) ;
2012-05-16 22:54:27 +02:00
}
2013-03-01 00:13:33 +01:00
IWL_EXPORT_SYMBOL ( iwl_opmode_deregister ) ;
2012-05-16 22:54:27 +02:00
static int __init iwl_drv_init ( void )
{
int i ;
2012-06-06 09:42:57 +02:00
mutex_init ( & iwlwifi_opmode_table_mtx ) ;
2012-05-16 22:54:27 +02:00
for ( i = 0 ; i < ARRAY_SIZE ( iwlwifi_opmode_table ) ; i + + )
INIT_LIST_HEAD ( & iwlwifi_opmode_table [ i ] . drv ) ;
2014-10-22 11:22:56 +02:00
pr_info ( DRV_DESCRIPTION " \n " ) ;
2012-05-16 22:54:27 +02:00
pr_info ( DRV_COPYRIGHT " \n " ) ;
2012-07-16 18:43:56 -07:00
# ifdef CONFIG_IWLWIFI_DEBUGFS
/* Create the root of iwlwifi debugfs subsystem. */
iwl_dbgfs_root = debugfs_create_dir ( DRV_NAME , NULL ) ;
if ( ! iwl_dbgfs_root )
return - EFAULT ;
# endif
2012-05-16 22:54:27 +02:00
return iwl_pci_register_driver ( ) ;
}
module_init ( iwl_drv_init ) ;
static void __exit iwl_drv_exit ( void )
{
iwl_pci_unregister_driver ( ) ;
2012-07-16 18:43:56 -07:00
# ifdef CONFIG_IWLWIFI_DEBUGFS
debugfs_remove_recursive ( iwl_dbgfs_root ) ;
# endif
2012-05-16 22:54:27 +02:00
}
module_exit ( iwl_drv_exit ) ;
2012-04-17 07:36:30 -07:00
# ifdef CONFIG_IWLWIFI_DEBUG
module_param_named ( debug , iwlwifi_mod_params . debug_level , uint ,
S_IRUGO | S_IWUSR ) ;
MODULE_PARM_DESC ( debug , " debug output mask " ) ;
# endif
module_param_named ( swcrypto , iwlwifi_mod_params . sw_crypto , int , S_IRUGO ) ;
MODULE_PARM_DESC ( swcrypto , " using crypto in software (default 0 [hardware]) " ) ;
module_param_named ( 11 n_disable , iwlwifi_mod_params . disable_11n , uint , S_IRUGO ) ;
MODULE_PARM_DESC ( 11 n_disable ,
2014-02-12 15:15:05 +02:00
" disable 11n functionality, bitmap: 1: full, 2: disable agg TX, 4: disable agg RX, 8 enable agg TX " ) ;
2012-04-17 07:36:30 -07:00
module_param_named ( amsdu_size_8K , iwlwifi_mod_params . amsdu_size_8K ,
int , S_IRUGO ) ;
2013-02-20 11:33:00 +02:00
MODULE_PARM_DESC ( amsdu_size_8K , " enable 8K amsdu size (default 0) " ) ;
2013-03-04 08:53:07 +02:00
module_param_named ( fw_restart , iwlwifi_mod_params . restart_fw , bool , S_IRUGO ) ;
MODULE_PARM_DESC ( fw_restart , " restart firmware in case of error (default true) " ) ;
2012-04-17 07:36:30 -07:00
module_param_named ( antenna_coupling , iwlwifi_mod_params . ant_coupling ,
int , S_IRUGO ) ;
MODULE_PARM_DESC ( antenna_coupling ,
2014-09-09 20:08:53 +02:00
" specify antenna coupling in dB (default: 0 dB) " ) ;
2012-04-17 07:36:30 -07:00
2013-05-09 08:07:59 +03:00
module_param_named ( nvm_file , iwlwifi_mod_params . nvm_file , charp , S_IRUGO ) ;
MODULE_PARM_DESC ( nvm_file , " NVM file name " ) ;
2014-11-20 17:33:43 +02:00
module_param_named ( d0i3_disable , iwlwifi_mod_params . d0i3_disable ,
bool , S_IRUGO ) ;
MODULE_PARM_DESC ( d0i3_disable , " disable d0i3 functionality (default: Y) " ) ;
2014-04-24 18:43:18 +08:00
module_param_named ( uapsd_disable , iwlwifi_mod_params . uapsd_disable ,
2014-11-13 20:53:45 +01:00
bool , S_IRUGO | S_IWUSR ) ;
2014-09-01 11:28:11 +02:00
# ifdef CONFIG_IWLWIFI_UAPSD
2014-04-24 18:43:18 +08:00
MODULE_PARM_DESC ( uapsd_disable , " disable U-APSD functionality (default: N) " ) ;
2014-09-01 11:28:11 +02:00
# else
MODULE_PARM_DESC ( uapsd_disable , " disable U-APSD functionality (default: Y) " ) ;
# endif
2014-04-24 18:43:18 +08:00
2012-04-17 07:36:30 -07:00
/*
* set bt_coex_active to true , uCode will do kill / defer
* every time the priority line is asserted ( BT is sending signals on the
* priority line in the PCIx ) .
* set bt_coex_active to false , uCode will ignore the BT activity and
* perform the normal operation
*
* User might experience transmit issue on some platform due to WiFi / BT
* co - exist problem . The possible behaviors are :
* Able to scan and finding all the available AP
* Not able to associate with any AP
* On those platforms , WiFi communication can be restored by set
* " bt_coex_active " module parameter to " false "
*
* default : bt_coex_active = true ( BT_COEX_ENABLE )
*/
module_param_named ( bt_coex_active , iwlwifi_mod_params . bt_coex_active ,
bool , S_IRUGO ) ;
MODULE_PARM_DESC ( bt_coex_active , " enable wifi/bt co-exist (default: enable) " ) ;
module_param_named ( led_mode , iwlwifi_mod_params . led_mode , int , S_IRUGO ) ;
MODULE_PARM_DESC ( led_mode , " 0=system default, "
" 1=On(RF On)/Off(RF Off), 2=blinking, 3=Off (default: 0) " ) ;
module_param_named ( power_save , iwlwifi_mod_params . power_save ,
bool , S_IRUGO ) ;
MODULE_PARM_DESC ( power_save ,
" enable WiFi power management (default: disable) " ) ;
module_param_named ( power_level , iwlwifi_mod_params . power_level ,
int , S_IRUGO ) ;
MODULE_PARM_DESC ( power_level ,
" default power save level (range from 1 - 5, default: 1) " ) ;
2014-06-01 08:05:52 +03:00
module_param_named ( fw_monitor , iwlwifi_mod_params . fw_monitor , bool , S_IRUGO ) ;
2014-06-26 09:13:26 +03:00
MODULE_PARM_DESC ( fw_monitor ,
2014-06-01 08:05:52 +03:00
" firmware monitor - to debug FW (default: false - needs lots of memory) " ) ;