2011-05-24 11:39:02 +03: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
*
* Copyright ( c ) 2007 - 2011 Intel Corporation . All rights reserved .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 ,
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE . GPL .
*
* Contact Information :
* Intel Linux Wireless < ilw @ linux . intel . com >
* Intel Corporation , 5200 N . E . Elam Young Parkway , Hillsboro , OR 97124 - 6497
*
* BSD LICENSE
*
* Copyright ( c ) 2005 - 2011 Intel Corporation . All rights reserved .
* 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/pci.h>
# include <linux/pci-aspm.h>
# include "iwl-pci.h"
# include "iwl-agn.h"
# include "iwl-core.h"
2011-06-10 11:23:36 -07:00
# include "iwl-io.h"
/* PCI registers */
# define PCI_CFG_RETRY_TIMEOUT 0x041
# define PCI_CFG_LINK_CTRL_VAL_L0S_EN 0x01
# define PCI_CFG_LINK_CTRL_VAL_L1_EN 0x02
2011-05-24 11:39:02 +03:00
2011-05-31 08:22:30 +03:00
struct iwl_pci_bus {
/* basic pci-network driver stuff */
struct pci_dev * pci_dev ;
/* pci hardware address support */
void __iomem * hw_base ;
} ;
# define IWL_BUS_GET_PCI_BUS(_iwl_bus) \
( ( struct iwl_pci_bus * ) ( ( _iwl_bus ) - > bus_specific ) )
# define IWL_BUS_GET_PCI_DEV(_iwl_bus) \
( ( IWL_BUS_GET_PCI_BUS ( _iwl_bus ) ) - > pci_dev )
2011-06-10 11:23:36 -07:00
static u16 iwl_pciexp_link_ctrl ( struct iwl_bus * bus )
{
int pos ;
u16 pci_lnk_ctl ;
struct pci_dev * pci_dev = IWL_BUS_GET_PCI_DEV ( bus ) ;
pos = pci_find_capability ( pci_dev , PCI_CAP_ID_EXP ) ;
pci_read_config_word ( pci_dev , pos + PCI_EXP_LNKCTL , & pci_lnk_ctl ) ;
return pci_lnk_ctl ;
}
static bool iwl_pci_is_pm_supported ( struct iwl_bus * bus )
{
u16 lctl = iwl_pciexp_link_ctrl ( bus ) ;
return ! ( lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN ) ;
}
static void iwl_pci_apm_config ( struct iwl_bus * bus )
{
/*
* HW bug W / A for instability in PCIe bus L0S - > L1 transition .
* Check if BIOS ( or OS ) enabled L1 - ASPM on this device .
* If so ( likely ) , disable L0S , so device moves directly L0 - > L1 ;
* costs negligible amount of power savings .
* If not ( unlikely ) , enable L0S , so there is at least some
* power savings , even without L1 .
*/
u16 lctl = iwl_pciexp_link_ctrl ( bus ) ;
if ( ( lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN ) = =
PCI_CFG_LINK_CTRL_VAL_L1_EN ) {
/* L1-ASPM enabled; disable(!) L0S */
iwl_set_bit ( bus - > priv , CSR_GIO_REG ,
CSR_GIO_REG_VAL_L0S_ENABLED ) ;
IWL_DEBUG_POWER ( bus - > priv , " L1 Enabled; Disabling L0S \n " ) ;
} else {
/* L1-ASPM disabled; enable(!) L0S */
iwl_clear_bit ( bus - > priv , CSR_GIO_REG ,
CSR_GIO_REG_VAL_L0S_ENABLED ) ;
IWL_DEBUG_POWER ( bus - > priv , " L1 Disabled; Enabling L0S \n " ) ;
}
}
2011-05-31 08:22:30 +03:00
static void iwl_pci_set_drv_data ( struct iwl_bus * bus , void * drv_priv )
{
pci_set_drvdata ( IWL_BUS_GET_PCI_DEV ( bus ) , drv_priv ) ;
}
2011-05-31 08:52:10 +03:00
static struct device * iwl_pci_get_dev ( const struct iwl_bus * bus )
{
return & ( IWL_BUS_GET_PCI_DEV ( bus ) - > dev ) ;
}
2011-05-31 09:07:00 +03:00
static void iwl_pci_write8 ( struct iwl_bus * bus , u32 ofs , u8 val )
{
iowrite8 ( val , IWL_BUS_GET_PCI_BUS ( bus ) - > hw_base + ofs ) ;
}
static void iwl_pci_write32 ( struct iwl_bus * bus , u32 ofs , u32 val )
{
iowrite32 ( val , IWL_BUS_GET_PCI_BUS ( bus ) - > hw_base + ofs ) ;
}
static u32 iwl_pci_read32 ( struct iwl_bus * bus , u32 ofs )
{
u32 val = ioread32 ( IWL_BUS_GET_PCI_BUS ( bus ) - > hw_base + ofs ) ;
return val ;
}
2011-05-31 08:22:30 +03:00
static struct iwl_bus_ops pci_ops = {
2011-06-10 11:23:36 -07:00
. get_pm_support = iwl_pci_is_pm_supported ,
. apm_config = iwl_pci_apm_config ,
2011-05-31 08:22:30 +03:00
. set_drv_data = iwl_pci_set_drv_data ,
2011-05-31 08:52:10 +03:00
. get_dev = iwl_pci_get_dev ,
2011-05-31 09:07:00 +03:00
. write8 = iwl_pci_write8 ,
. write32 = iwl_pci_write32 ,
. read32 = iwl_pci_read32 ,
2011-05-31 08:22:30 +03:00
} ;
2011-05-24 11:39:02 +03:00
# define IWL_PCI_DEVICE(dev, subdev, cfg) \
. vendor = PCI_VENDOR_ID_INTEL , . device = ( dev ) , \
. subvendor = PCI_ANY_ID , . subdevice = ( subdev ) , \
. driver_data = ( kernel_ulong_t ) & ( cfg )
/* Hardware specific file defines the PCI IDs table for that hardware module */
static DEFINE_PCI_DEVICE_TABLE ( iwl_hw_card_ids ) = {
{ IWL_PCI_DEVICE ( 0x4232 , 0x1201 , iwl5100_agn_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x4232 , 0x1301 , iwl5100_agn_cfg ) } , /* Half Mini Card */
{ IWL_PCI_DEVICE ( 0x4232 , 0x1204 , iwl5100_agn_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x4232 , 0x1304 , iwl5100_agn_cfg ) } , /* Half Mini Card */
{ IWL_PCI_DEVICE ( 0x4232 , 0x1205 , iwl5100_bgn_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x4232 , 0x1305 , iwl5100_bgn_cfg ) } , /* Half Mini Card */
{ IWL_PCI_DEVICE ( 0x4232 , 0x1206 , iwl5100_abg_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x4232 , 0x1306 , iwl5100_abg_cfg ) } , /* Half Mini Card */
{ IWL_PCI_DEVICE ( 0x4232 , 0x1221 , iwl5100_agn_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x4232 , 0x1321 , iwl5100_agn_cfg ) } , /* Half Mini Card */
{ IWL_PCI_DEVICE ( 0x4232 , 0x1224 , iwl5100_agn_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x4232 , 0x1324 , iwl5100_agn_cfg ) } , /* Half Mini Card */
{ IWL_PCI_DEVICE ( 0x4232 , 0x1225 , iwl5100_bgn_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x4232 , 0x1325 , iwl5100_bgn_cfg ) } , /* Half Mini Card */
{ IWL_PCI_DEVICE ( 0x4232 , 0x1226 , iwl5100_abg_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x4232 , 0x1326 , iwl5100_abg_cfg ) } , /* Half Mini Card */
{ IWL_PCI_DEVICE ( 0x4237 , 0x1211 , iwl5100_agn_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x4237 , 0x1311 , iwl5100_agn_cfg ) } , /* Half Mini Card */
{ IWL_PCI_DEVICE ( 0x4237 , 0x1214 , iwl5100_agn_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x4237 , 0x1314 , iwl5100_agn_cfg ) } , /* Half Mini Card */
{ IWL_PCI_DEVICE ( 0x4237 , 0x1215 , iwl5100_bgn_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x4237 , 0x1315 , iwl5100_bgn_cfg ) } , /* Half Mini Card */
{ IWL_PCI_DEVICE ( 0x4237 , 0x1216 , iwl5100_abg_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x4237 , 0x1316 , iwl5100_abg_cfg ) } , /* Half Mini Card */
/* 5300 Series WiFi */
{ IWL_PCI_DEVICE ( 0x4235 , 0x1021 , iwl5300_agn_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x4235 , 0x1121 , iwl5300_agn_cfg ) } , /* Half Mini Card */
{ IWL_PCI_DEVICE ( 0x4235 , 0x1024 , iwl5300_agn_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x4235 , 0x1124 , iwl5300_agn_cfg ) } , /* Half Mini Card */
{ IWL_PCI_DEVICE ( 0x4235 , 0x1001 , iwl5300_agn_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x4235 , 0x1101 , iwl5300_agn_cfg ) } , /* Half Mini Card */
{ IWL_PCI_DEVICE ( 0x4235 , 0x1004 , iwl5300_agn_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x4235 , 0x1104 , iwl5300_agn_cfg ) } , /* Half Mini Card */
{ IWL_PCI_DEVICE ( 0x4236 , 0x1011 , iwl5300_agn_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x4236 , 0x1111 , iwl5300_agn_cfg ) } , /* Half Mini Card */
{ IWL_PCI_DEVICE ( 0x4236 , 0x1014 , iwl5300_agn_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x4236 , 0x1114 , iwl5300_agn_cfg ) } , /* Half Mini Card */
/* 5350 Series WiFi/WiMax */
{ IWL_PCI_DEVICE ( 0x423A , 0x1001 , iwl5350_agn_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x423A , 0x1021 , iwl5350_agn_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x423B , 0x1011 , iwl5350_agn_cfg ) } , /* Mini Card */
/* 5150 Series Wifi/WiMax */
{ IWL_PCI_DEVICE ( 0x423C , 0x1201 , iwl5150_agn_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x423C , 0x1301 , iwl5150_agn_cfg ) } , /* Half Mini Card */
{ IWL_PCI_DEVICE ( 0x423C , 0x1206 , iwl5150_abg_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x423C , 0x1306 , iwl5150_abg_cfg ) } , /* Half Mini Card */
{ IWL_PCI_DEVICE ( 0x423C , 0x1221 , iwl5150_agn_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x423C , 0x1321 , iwl5150_agn_cfg ) } , /* Half Mini Card */
{ IWL_PCI_DEVICE ( 0x423D , 0x1211 , iwl5150_agn_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x423D , 0x1311 , iwl5150_agn_cfg ) } , /* Half Mini Card */
{ IWL_PCI_DEVICE ( 0x423D , 0x1216 , iwl5150_abg_cfg ) } , /* Mini Card */
{ IWL_PCI_DEVICE ( 0x423D , 0x1316 , iwl5150_abg_cfg ) } , /* Half Mini Card */
/* 6x00 Series */
{ IWL_PCI_DEVICE ( 0x422B , 0x1101 , iwl6000_3agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x422B , 0x1121 , iwl6000_3agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x422C , 0x1301 , iwl6000i_2agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x422C , 0x1306 , iwl6000i_2abg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x422C , 0x1307 , iwl6000i_2bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x422C , 0x1321 , iwl6000i_2agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x422C , 0x1326 , iwl6000i_2abg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x4238 , 0x1111 , iwl6000_3agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x4239 , 0x1311 , iwl6000i_2agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x4239 , 0x1316 , iwl6000i_2abg_cfg ) } ,
/* 6x05 Series */
{ IWL_PCI_DEVICE ( 0x0082 , 0x1301 , iwl6005_2agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0082 , 0x1306 , iwl6005_2abg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0082 , 0x1307 , iwl6005_2bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0082 , 0x1321 , iwl6005_2agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0082 , 0x1326 , iwl6005_2abg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0085 , 0x1311 , iwl6005_2agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0085 , 0x1316 , iwl6005_2abg_cfg ) } ,
/* 6x30 Series */
{ IWL_PCI_DEVICE ( 0x008A , 0x5305 , iwl1030_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x008A , 0x5307 , iwl1030_bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x008A , 0x5325 , iwl1030_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x008A , 0x5327 , iwl1030_bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x008B , 0x5315 , iwl1030_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x008B , 0x5317 , iwl1030_bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0090 , 0x5211 , iwl6030_2agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0090 , 0x5215 , iwl6030_2bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0090 , 0x5216 , iwl6030_2abg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0091 , 0x5201 , iwl6030_2agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0091 , 0x5205 , iwl6030_2bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0091 , 0x5206 , iwl6030_2abg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0091 , 0x5207 , iwl6030_2bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0091 , 0x5221 , iwl6030_2agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0091 , 0x5225 , iwl6030_2bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0091 , 0x5226 , iwl6030_2abg_cfg ) } ,
/* 6x50 WiFi/WiMax Series */
{ IWL_PCI_DEVICE ( 0x0087 , 0x1301 , iwl6050_2agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0087 , 0x1306 , iwl6050_2abg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0087 , 0x1321 , iwl6050_2agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0087 , 0x1326 , iwl6050_2abg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0089 , 0x1311 , iwl6050_2agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0089 , 0x1316 , iwl6050_2abg_cfg ) } ,
/* 6150 WiFi/WiMax Series */
{ IWL_PCI_DEVICE ( 0x0885 , 0x1305 , iwl6150_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0885 , 0x1307 , iwl6150_bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0885 , 0x1325 , iwl6150_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0885 , 0x1327 , iwl6150_bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0886 , 0x1315 , iwl6150_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0886 , 0x1317 , iwl6150_bg_cfg ) } ,
/* 1000 Series WiFi */
{ IWL_PCI_DEVICE ( 0x0083 , 0x1205 , iwl1000_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0083 , 0x1305 , iwl1000_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0083 , 0x1225 , iwl1000_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0083 , 0x1325 , iwl1000_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0084 , 0x1215 , iwl1000_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0084 , 0x1315 , iwl1000_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0083 , 0x1206 , iwl1000_bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0083 , 0x1306 , iwl1000_bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0083 , 0x1226 , iwl1000_bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0083 , 0x1326 , iwl1000_bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0084 , 0x1216 , iwl1000_bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0084 , 0x1316 , iwl1000_bg_cfg ) } ,
/* 100 Series WiFi */
{ IWL_PCI_DEVICE ( 0x08AE , 0x1005 , iwl100_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x08AE , 0x1007 , iwl100_bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x08AF , 0x1015 , iwl100_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x08AF , 0x1017 , iwl100_bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x08AE , 0x1025 , iwl100_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x08AE , 0x1027 , iwl100_bg_cfg ) } ,
/* 130 Series WiFi */
{ IWL_PCI_DEVICE ( 0x0896 , 0x5005 , iwl130_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0896 , 0x5007 , iwl130_bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0897 , 0x5015 , iwl130_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0897 , 0x5017 , iwl130_bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0896 , 0x5025 , iwl130_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0896 , 0x5027 , iwl130_bg_cfg ) } ,
/* 2x00 Series */
{ IWL_PCI_DEVICE ( 0x0890 , 0x4022 , iwl2000_2bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0891 , 0x4222 , iwl2000_2bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0890 , 0x4422 , iwl2000_2bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0890 , 0x4026 , iwl2000_2bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0891 , 0x4226 , iwl2000_2bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0890 , 0x4426 , iwl2000_2bg_cfg ) } ,
/* 2x30 Series */
{ IWL_PCI_DEVICE ( 0x0887 , 0x4062 , iwl2030_2bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0888 , 0x4262 , iwl2030_2bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0887 , 0x4462 , iwl2030_2bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0887 , 0x4066 , iwl2030_2bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0888 , 0x4266 , iwl2030_2bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0887 , 0x4466 , iwl2030_2bg_cfg ) } ,
/* 6x35 Series */
{ IWL_PCI_DEVICE ( 0x088E , 0x4060 , iwl6035_2agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x088F , 0x4260 , iwl6035_2agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x088E , 0x4460 , iwl6035_2agn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x088E , 0x4064 , iwl6035_2abg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x088F , 0x4264 , iwl6035_2abg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x088E , 0x4464 , iwl6035_2abg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x088E , 0x4066 , iwl6035_2bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x088F , 0x4266 , iwl6035_2bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x088E , 0x4466 , iwl6035_2bg_cfg ) } ,
/* 105 Series */
{ IWL_PCI_DEVICE ( 0x0894 , 0x0022 , iwl105_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0895 , 0x0222 , iwl105_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0894 , 0x0422 , iwl105_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0894 , 0x0026 , iwl105_bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0895 , 0x0226 , iwl105_bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0894 , 0x0426 , iwl105_bg_cfg ) } ,
/* 135 Series */
{ IWL_PCI_DEVICE ( 0x0892 , 0x0062 , iwl135_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0893 , 0x0262 , iwl135_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0892 , 0x0462 , iwl135_bgn_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0892 , 0x0066 , iwl135_bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0893 , 0x0266 , iwl135_bg_cfg ) } ,
{ IWL_PCI_DEVICE ( 0x0892 , 0x0466 , iwl135_bg_cfg ) } ,
{ 0 }
} ;
MODULE_DEVICE_TABLE ( pci , iwl_hw_card_ids ) ;
static int iwl_pci_probe ( struct pci_dev * pdev , const struct pci_device_id * ent )
{
struct iwl_cfg * cfg = ( struct iwl_cfg * ) ( ent - > driver_data ) ;
2011-05-31 08:22:30 +03:00
struct iwl_pci_bus * bus ;
2011-05-31 09:07:00 +03:00
u8 rev_id ;
u16 pci_cmd ;
2011-05-31 08:22:30 +03:00
int err ;
bus = kzalloc ( sizeof ( * bus ) , GFP_KERNEL ) ;
if ( ! bus ) {
pr_err ( " Couldn't allocate iwl_pci_bus " ) ;
err = - ENOMEM ;
goto out_no_pci ;
}
bus - > pci_dev = pdev ;
2011-05-24 11:39:02 +03:00
2011-05-31 09:07:00 +03:00
/* W/A - seems to solve weird behavior. We need to remove this if we
* don ' t want to stay in L1 all the time . This wastes a lot of power */
pci_disable_link_state ( pdev , PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
PCIE_LINK_STATE_CLKPM ) ;
if ( pci_enable_device ( pdev ) ) {
err = - ENODEV ;
goto out_no_pci ;
}
pci_set_master ( pdev ) ;
err = pci_set_dma_mask ( pdev , DMA_BIT_MASK ( 36 ) ) ;
if ( ! err )
err = pci_set_consistent_dma_mask ( pdev , DMA_BIT_MASK ( 36 ) ) ;
if ( err ) {
err = pci_set_dma_mask ( pdev , DMA_BIT_MASK ( 32 ) ) ;
if ( ! err )
err = pci_set_consistent_dma_mask ( pdev ,
DMA_BIT_MASK ( 32 ) ) ;
/* both attempts failed: */
if ( err ) {
pr_err ( " No suitable DMA available. \n " ) ;
goto out_pci_disable_device ;
}
}
err = pci_request_regions ( pdev , DRV_NAME ) ;
if ( err ) {
pr_err ( " pci_request_regions failed " ) ;
goto out_pci_disable_device ;
}
bus - > hw_base = pci_iomap ( pdev , 0 , 0 ) ;
if ( ! bus - > hw_base ) {
pr_err ( " pci_iomap failed " ) ;
err = - ENODEV ;
goto out_pci_release_regions ;
}
pr_info ( " pci_resource_len = 0x%08llx \n " ,
( unsigned long long ) pci_resource_len ( pdev , 0 ) ) ;
pr_info ( " pci_resource_base = %p \n " , bus - > hw_base ) ;
pci_read_config_byte ( pdev , PCI_REVISION_ID , & rev_id ) ;
pr_info ( " HW Revision ID = 0x%X \n " , rev_id ) ;
/* 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 ) ;
err = pci_enable_msi ( pdev ) ;
if ( err ) {
pr_err ( " pci_enable_msi failed " ) ;
goto out_iounmap ;
}
/* TODO: Move this away, not needed if not MSI */
/* enable rfkill interrupt: hw bug w/a */
pci_read_config_word ( pdev , PCI_COMMAND , & pci_cmd ) ;
if ( pci_cmd & PCI_COMMAND_INTX_DISABLE ) {
pci_cmd & = ~ PCI_COMMAND_INTX_DISABLE ;
pci_write_config_word ( pdev , PCI_COMMAND , pci_cmd ) ;
}
2011-05-31 08:22:30 +03:00
err = iwl_probe ( ( void * ) bus , & pci_ops , cfg ) ;
if ( err )
2011-05-31 09:07:00 +03:00
goto out_disable_msi ;
2011-05-31 08:22:30 +03:00
return 0 ;
2011-05-31 09:07:00 +03:00
out_disable_msi :
pci_disable_msi ( pdev ) ;
out_iounmap :
pci_iounmap ( pdev , bus - > hw_base ) ;
out_pci_release_regions :
pci_set_drvdata ( pdev , NULL ) ;
pci_release_regions ( pdev ) ;
out_pci_disable_device :
pci_disable_device ( pdev ) ;
2011-05-31 08:22:30 +03:00
out_no_pci :
kfree ( bus ) ;
return err ;
2011-05-24 11:39:02 +03:00
}
2011-05-31 09:07:00 +03:00
static void iwl_pci_down ( void * bus )
{
struct iwl_pci_bus * pci_bus = ( struct iwl_pci_bus * ) bus ;
pci_disable_msi ( pci_bus - > pci_dev ) ;
pci_iounmap ( pci_bus - > pci_dev , pci_bus - > hw_base ) ;
pci_release_regions ( pci_bus - > pci_dev ) ;
pci_disable_device ( pci_bus - > pci_dev ) ;
pci_set_drvdata ( pci_bus - > pci_dev , NULL ) ;
kfree ( pci_bus ) ;
}
2011-05-24 11:39:02 +03:00
static void __devexit iwl_pci_remove ( struct pci_dev * pdev )
{
2011-05-31 08:22:30 +03:00
struct iwl_priv * priv = pci_get_drvdata ( pdev ) ;
/* This can happen if probe failed */
if ( unlikely ( ! priv ) )
return ;
iwl_remove ( priv ) ;
2011-05-31 09:07:00 +03:00
iwl_pci_down ( IWL_BUS_GET_PCI_BUS ( & priv - > bus ) ) ;
2011-05-24 11:39:02 +03:00
}
# ifdef CONFIG_PM
static int iwl_pci_suspend ( struct device * device )
{
struct pci_dev * pdev = to_pci_dev ( device ) ;
struct iwl_priv * priv = pci_get_drvdata ( pdev ) ;
return iwl_suspend ( priv ) ;
}
static int iwl_pci_resume ( struct device * device )
{
struct pci_dev * pdev = to_pci_dev ( device ) ;
struct iwl_priv * priv = pci_get_drvdata ( pdev ) ;
/*
* 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 ) ;
return iwl_resume ( priv ) ;
}
static const struct dev_pm_ops iwl_dev_pm_ops = {
. suspend = iwl_pci_suspend ,
. resume = iwl_pci_resume ,
. freeze = iwl_pci_suspend ,
. thaw = iwl_pci_resume ,
. poweroff = iwl_pci_suspend ,
. restore = iwl_pci_resume ,
} ;
# define IWL_PM_OPS (&iwl_dev_pm_ops)
# else
# define IWL_PM_OPS NULL
# endif
static struct pci_driver iwl_pci_driver = {
. name = DRV_NAME ,
. id_table = iwl_hw_card_ids ,
. probe = iwl_pci_probe ,
. remove = __devexit_p ( iwl_pci_remove ) ,
. driver . pm = IWL_PM_OPS ,
} ;
int __must_check iwl_pci_register_driver ( void )
{
int ret ;
ret = pci_register_driver ( & iwl_pci_driver ) ;
if ( ret )
pr_err ( " Unable to initialize PCI module \n " ) ;
return ret ;
}
void iwl_pci_unregister_driver ( void )
{
pci_unregister_driver ( & iwl_pci_driver ) ;
}