2005-04-17 02:20:36 +04:00
/*
* PCI Express Hot Plug Controller Driver
*
* Copyright ( C ) 1995 , 2001 Compaq Computer Corporation
* Copyright ( C ) 2001 Greg Kroah - Hartman ( greg @ kroah . com )
* Copyright ( C ) 2001 IBM Corp .
* Copyright ( C ) 2003 - 2004 Intel Corporation
*
* All rights reserved .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or ( at
* your option ) any later version .
*
* 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 , GOOD TITLE or
* NON INFRINGEMENT . 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 . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*
2005-08-17 02:16:10 +04:00
* Send feedback to < greg @ kroah . com > , < kristen . c . accardi @ intel . com >
2005-04-17 02:20:36 +04:00
*
*/
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/kernel.h>
# include <linux/types.h>
# include <linux/pci.h>
# include "pciehp.h"
# include <linux/interrupt.h>
2007-01-10 00:02:36 +03:00
# include <linux/time.h>
2005-04-17 02:20:36 +04:00
/* Global variables */
int pciehp_debug ;
int pciehp_poll_mode ;
int pciehp_poll_time ;
2005-11-01 03:20:12 +03:00
int pciehp_force ;
2008-05-05 22:21:51 +04:00
static int pciehp_slot_with_bus ;
2007-03-07 02:02:26 +03:00
struct workqueue_struct * pciehp_wq ;
2005-04-17 02:20:36 +04:00
# define DRIVER_VERSION "0.4"
# define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
# define DRIVER_DESC "PCI Express Hot Plug Controller Driver"
MODULE_AUTHOR ( DRIVER_AUTHOR ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( " GPL " ) ;
module_param ( pciehp_debug , bool , 0644 ) ;
module_param ( pciehp_poll_mode , bool , 0644 ) ;
module_param ( pciehp_poll_time , int , 0644 ) ;
2005-11-01 03:20:12 +03:00
module_param ( pciehp_force , bool , 0644 ) ;
2008-04-26 01:38:38 +04:00
module_param ( pciehp_slot_with_bus , bool , 0644 ) ;
2005-04-17 02:20:36 +04:00
MODULE_PARM_DESC ( pciehp_debug , " Debugging mode enabled or not " ) ;
MODULE_PARM_DESC ( pciehp_poll_mode , " Using polling mechanism for hot-plug events or not " ) ;
MODULE_PARM_DESC ( pciehp_poll_time , " Polling mechanism frequency, in seconds " ) ;
2005-11-01 03:20:12 +03:00
MODULE_PARM_DESC ( pciehp_force , " Force pciehp, even if _OSC and OSHP are missing " ) ;
2008-04-26 01:38:38 +04:00
MODULE_PARM_DESC ( pciehp_slot_with_bus , " Use bus number in the slot name " ) ;
2005-04-17 02:20:36 +04:00
# define PCIE_MODULE_NAME "pciehp"
static int set_attention_status ( struct hotplug_slot * slot , u8 value ) ;
static int enable_slot ( struct hotplug_slot * slot ) ;
static int disable_slot ( struct hotplug_slot * slot ) ;
static int get_power_status ( struct hotplug_slot * slot , u8 * value ) ;
static int get_attention_status ( struct hotplug_slot * slot , u8 * value ) ;
static int get_latch_status ( struct hotplug_slot * slot , u8 * value ) ;
static int get_adapter_status ( struct hotplug_slot * slot , u8 * value ) ;
2006-05-12 08:39:45 +04:00
static int get_address ( struct hotplug_slot * slot , u32 * value ) ;
2005-04-17 02:20:36 +04:00
static int get_max_bus_speed ( struct hotplug_slot * slot , enum pci_bus_speed * value ) ;
static int get_cur_bus_speed ( struct hotplug_slot * slot , enum pci_bus_speed * value ) ;
static struct hotplug_slot_ops pciehp_hotplug_slot_ops = {
. owner = THIS_MODULE ,
. set_attention_status = set_attention_status ,
. enable_slot = enable_slot ,
. disable_slot = disable_slot ,
. get_power_status = get_power_status ,
. get_attention_status = get_attention_status ,
. get_latch_status = get_latch_status ,
. get_adapter_status = get_adapter_status ,
2006-05-12 08:39:45 +04:00
. get_address = get_address ,
2005-04-17 02:20:36 +04:00
. get_max_bus_speed = get_max_bus_speed ,
. get_cur_bus_speed = get_cur_bus_speed ,
} ;
2007-01-10 00:02:36 +03:00
/*
* Check the status of the Electro Mechanical Interlock ( EMI )
*/
static int get_lock_status ( struct hotplug_slot * hotplug_slot , u8 * value )
{
struct slot * slot = hotplug_slot - > private ;
return ( slot - > hpc_ops - > get_emi_status ( slot , value ) ) ;
}
/*
* sysfs interface for the Electro Mechanical Interlock ( EMI )
* 1 = = locked , 0 = = unlocked
*/
static ssize_t lock_read_file ( struct hotplug_slot * slot , char * buf )
{
int retval ;
u8 value ;
retval = get_lock_status ( slot , & value ) ;
if ( retval )
goto lock_read_exit ;
retval = sprintf ( buf , " %d \n " , value ) ;
lock_read_exit :
return retval ;
}
/*
* Change the status of the Electro Mechanical Interlock ( EMI )
* This is a toggle - in addition there must be at least 1 second
* in between toggles .
*/
static int set_lock_status ( struct hotplug_slot * hotplug_slot , u8 status )
{
struct slot * slot = hotplug_slot - > private ;
int retval ;
u8 value ;
mutex_lock ( & slot - > ctrl - > crit_sect ) ;
/* has it been >1 sec since our last toggle? */
if ( ( get_seconds ( ) - slot - > last_emi_toggle ) < 1 )
return - EINVAL ;
/* see what our current state is */
retval = get_lock_status ( hotplug_slot , & value ) ;
if ( retval | | ( value = = status ) )
goto set_lock_exit ;
slot - > hpc_ops - > toggle_emi ( slot ) ;
set_lock_exit :
mutex_unlock ( & slot - > ctrl - > crit_sect ) ;
return 0 ;
}
/*
* sysfs interface which allows the user to toggle the Electro Mechanical
* Interlock . Valid values are either 0 or 1. 0 = = unlock , 1 = = lock
*/
static ssize_t lock_write_file ( struct hotplug_slot * slot , const char * buf ,
size_t count )
{
unsigned long llock ;
u8 lock ;
int retval = 0 ;
llock = simple_strtoul ( buf , NULL , 10 ) ;
lock = ( u8 ) ( llock & 0xff ) ;
switch ( lock ) {
case 0 :
case 1 :
retval = set_lock_status ( slot , lock ) ;
break ;
default :
err ( " %d is an invalid lock value \n " , lock ) ;
retval = - EINVAL ;
}
if ( retval )
return retval ;
return count ;
}
static struct hotplug_slot_attribute hotplug_slot_attr_lock = {
. attr = { . name = " lock " , . mode = S_IFREG | S_IRUGO | S_IWUSR } ,
. show = lock_read_file ,
. store = lock_write_file
} ;
2005-04-29 05:08:53 +04:00
/**
* release_slot - free up the memory used by a slot
* @ hotplug_slot : slot to free
*/
static void release_slot ( struct hotplug_slot * hotplug_slot )
{
struct slot * slot = hotplug_slot - > private ;
2008-03-04 06:09:46 +03:00
dbg ( " %s - physical_slot = %s \n " , __func__ , hotplug_slot - > name ) ;
2005-04-29 05:08:53 +04:00
kfree ( slot - > hotplug_slot - > info ) ;
kfree ( slot - > hotplug_slot ) ;
kfree ( slot ) ;
}
2006-12-22 04:01:02 +03:00
static void make_slot_name ( struct slot * slot )
{
2008-04-26 01:38:38 +04:00
if ( pciehp_slot_with_bus )
snprintf ( slot - > hotplug_slot - > name , SLOT_NAME_SIZE , " %04d_%04d " ,
slot - > bus , slot - > number ) ;
else
snprintf ( slot - > hotplug_slot - > name , SLOT_NAME_SIZE , " %d " ,
slot - > number ) ;
2006-12-22 04:01:02 +03:00
}
2005-04-17 02:20:36 +04:00
static int init_slots ( struct controller * ctrl )
{
2005-12-11 08:41:42 +03:00
struct slot * slot ;
struct hotplug_slot * hotplug_slot ;
2006-12-22 04:01:02 +03:00
struct hotplug_slot_info * info ;
int retval = - ENOMEM ;
int i ;
2005-04-17 02:20:36 +04:00
2006-12-22 04:01:02 +03:00
for ( i = 0 ; i < ctrl - > num_slots ; i + + ) {
2006-02-28 17:34:49 +03:00
slot = kzalloc ( sizeof ( * slot ) , GFP_KERNEL ) ;
2005-12-11 08:41:42 +03:00
if ( ! slot )
2005-04-17 02:20:36 +04:00
goto error ;
2006-12-22 04:01:02 +03:00
hotplug_slot = kzalloc ( sizeof ( * hotplug_slot ) , GFP_KERNEL ) ;
if ( ! hotplug_slot )
2005-04-17 02:20:36 +04:00
goto error_slot ;
2006-12-22 04:01:02 +03:00
slot - > hotplug_slot = hotplug_slot ;
2005-04-17 02:20:36 +04:00
2006-12-22 04:01:02 +03:00
info = kzalloc ( sizeof ( * info ) , GFP_KERNEL ) ;
if ( ! info )
2005-04-17 02:20:36 +04:00
goto error_hpslot ;
2006-12-22 04:01:02 +03:00
hotplug_slot - > info = info ;
2005-04-17 02:20:36 +04:00
2006-12-22 04:01:02 +03:00
hotplug_slot - > name = slot - > name ;
2005-04-17 02:20:36 +04:00
2006-12-22 04:01:02 +03:00
slot - > hp_slot = i ;
slot - > ctrl = ctrl ;
slot - > bus = ctrl - > pci_dev - > subordinate - > number ;
slot - > device = ctrl - > slot_device_offset + i ;
slot - > hpc_ops = ctrl - > hpc_ops ;
2005-12-11 08:41:42 +03:00
slot - > number = ctrl - > first_slot ;
2007-03-07 02:02:26 +03:00
mutex_init ( & slot - > lock ) ;
2007-03-21 21:45:31 +03:00
INIT_DELAYED_WORK ( & slot - > work , pciehp_queue_pushbutton_work ) ;
2005-04-17 02:20:36 +04:00
/* register this slot with the hotplug pci core */
2005-12-11 08:41:42 +03:00
hotplug_slot - > private = slot ;
hotplug_slot - > release = & release_slot ;
2006-12-22 04:01:02 +03:00
make_slot_name ( slot ) ;
2005-12-11 08:41:42 +03:00
hotplug_slot - > ops = & pciehp_hotplug_slot_ops ;
2006-12-22 04:01:02 +03:00
get_power_status ( hotplug_slot , & info - > power_status ) ;
get_attention_status ( hotplug_slot , & info - > attention_status ) ;
get_latch_status ( hotplug_slot , & info - > latch_status ) ;
get_adapter_status ( hotplug_slot , & info - > adapter_status ) ;
2005-12-11 08:41:42 +03:00
dbg ( " Registering bus=%x dev=%x hp_slot=%x sun=%x "
2006-12-22 04:01:02 +03:00
" slot_device_offset=%x \n " , slot - > bus , slot - > device ,
slot - > hp_slot , slot - > number , ctrl - > slot_device_offset ) ;
retval = pci_hp_register ( hotplug_slot ) ;
if ( retval ) {
2008-05-27 14:07:33 +04:00
err ( " pci_hp_register failed with error %d \n " , retval ) ;
if ( retval = = - EEXIST )
err ( " Failed to register slot because of name "
" collision. Try \' pciehp_slot_with_bus \' "
" module option. \n " ) ;
2006-12-22 04:01:02 +03:00
goto error_info ;
2005-04-17 02:20:36 +04:00
}
2007-01-10 00:02:36 +03:00
/* create additional sysfs entries */
2008-04-26 01:39:06 +04:00
if ( EMI ( ctrl ) ) {
2007-01-10 00:02:36 +03:00
retval = sysfs_create_file ( & hotplug_slot - > kobj ,
& hotplug_slot_attr_lock . attr ) ;
if ( retval ) {
pci_hp_deregister ( hotplug_slot ) ;
err ( " cannot create additional sysfs entries \n " ) ;
goto error_info ;
}
}
2005-04-17 02:20:36 +04:00
2006-12-22 04:01:03 +03:00
list_add ( & slot - > slot_list , & ctrl - > slot_list ) ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
error_info :
2006-12-22 04:01:02 +03:00
kfree ( info ) ;
2005-04-17 02:20:36 +04:00
error_hpslot :
2005-12-11 08:41:42 +03:00
kfree ( hotplug_slot ) ;
2005-04-17 02:20:36 +04:00
error_slot :
2005-12-11 08:41:42 +03:00
kfree ( slot ) ;
2005-04-17 02:20:36 +04:00
error :
2006-12-22 04:01:02 +03:00
return retval ;
2005-04-17 02:20:36 +04:00
}
2006-12-22 04:01:03 +03:00
static void cleanup_slots ( struct controller * ctrl )
2005-04-17 02:20:36 +04:00
{
2006-12-22 04:01:03 +03:00
struct list_head * tmp ;
struct list_head * next ;
struct slot * slot ;
2005-04-17 02:20:36 +04:00
2006-12-22 04:01:03 +03:00
list_for_each_safe ( tmp , next , & ctrl - > slot_list ) {
slot = list_entry ( tmp , struct slot , slot_list ) ;
list_del ( & slot - > slot_list ) ;
2008-04-26 01:39:06 +04:00
if ( EMI ( ctrl ) )
2007-01-10 00:02:36 +03:00
sysfs_remove_file ( & slot - > hotplug_slot - > kobj ,
& hotplug_slot_attr_lock . attr ) ;
2007-03-07 02:02:26 +03:00
cancel_delayed_work ( & slot - > work ) ;
flush_scheduled_work ( ) ;
flush_workqueue ( pciehp_wq ) ;
2006-12-22 04:01:03 +03:00
pci_hp_deregister ( slot - > hotplug_slot ) ;
2005-04-17 02:20:36 +04:00
}
}
/*
* set_attention_status - Turns the Amber LED for a slot on , off or blink
*/
static int set_attention_status ( struct hotplug_slot * hotplug_slot , u8 status )
{
struct slot * slot = hotplug_slot - > private ;
2008-03-04 06:09:46 +03:00
dbg ( " %s - physical_slot = %s \n " , __func__ , hotplug_slot - > name ) ;
2005-04-17 02:20:36 +04:00
hotplug_slot - > info - > attention_status = status ;
2007-08-10 03:09:35 +04:00
2008-04-26 01:39:06 +04:00
if ( ATTN_LED ( slot - > ctrl ) )
2005-04-17 02:20:36 +04:00
slot - > hpc_ops - > set_attention_status ( slot , status ) ;
return 0 ;
}
static int enable_slot ( struct hotplug_slot * hotplug_slot )
{
struct slot * slot = hotplug_slot - > private ;
2008-03-04 06:09:46 +03:00
dbg ( " %s - physical_slot = %s \n " , __func__ , hotplug_slot - > name ) ;
2005-04-17 02:20:36 +04:00
2007-03-07 02:02:26 +03:00
return pciehp_sysfs_enable_slot ( slot ) ;
2005-04-17 02:20:36 +04:00
}
static int disable_slot ( struct hotplug_slot * hotplug_slot )
{
struct slot * slot = hotplug_slot - > private ;
2008-03-04 06:09:46 +03:00
dbg ( " %s - physical_slot = %s \n " , __func__ , hotplug_slot - > name ) ;
2005-04-17 02:20:36 +04:00
2007-03-07 02:02:26 +03:00
return pciehp_sysfs_disable_slot ( slot ) ;
2005-04-17 02:20:36 +04:00
}
static int get_power_status ( struct hotplug_slot * hotplug_slot , u8 * value )
{
struct slot * slot = hotplug_slot - > private ;
int retval ;
2008-03-04 06:09:46 +03:00
dbg ( " %s - physical_slot = %s \n " , __func__ , hotplug_slot - > name ) ;
2005-04-17 02:20:36 +04:00
retval = slot - > hpc_ops - > get_power_status ( slot , value ) ;
if ( retval < 0 )
* value = hotplug_slot - > info - > power_status ;
return 0 ;
}
static int get_attention_status ( struct hotplug_slot * hotplug_slot , u8 * value )
{
struct slot * slot = hotplug_slot - > private ;
int retval ;
2008-03-04 06:09:46 +03:00
dbg ( " %s - physical_slot = %s \n " , __func__ , hotplug_slot - > name ) ;
2005-04-17 02:20:36 +04:00
retval = slot - > hpc_ops - > get_attention_status ( slot , value ) ;
if ( retval < 0 )
* value = hotplug_slot - > info - > attention_status ;
return 0 ;
}
static int get_latch_status ( struct hotplug_slot * hotplug_slot , u8 * value )
{
struct slot * slot = hotplug_slot - > private ;
int retval ;
2008-03-04 06:09:46 +03:00
dbg ( " %s - physical_slot = %s \n " , __func__ , hotplug_slot - > name ) ;
2005-04-17 02:20:36 +04:00
retval = slot - > hpc_ops - > get_latch_status ( slot , value ) ;
if ( retval < 0 )
* value = hotplug_slot - > info - > latch_status ;
return 0 ;
}
static int get_adapter_status ( struct hotplug_slot * hotplug_slot , u8 * value )
{
struct slot * slot = hotplug_slot - > private ;
int retval ;
2008-03-04 06:09:46 +03:00
dbg ( " %s - physical_slot = %s \n " , __func__ , hotplug_slot - > name ) ;
2005-04-17 02:20:36 +04:00
retval = slot - > hpc_ops - > get_adapter_status ( slot , value ) ;
if ( retval < 0 )
* value = hotplug_slot - > info - > adapter_status ;
return 0 ;
}
2006-05-12 08:39:45 +04:00
static int get_address ( struct hotplug_slot * hotplug_slot , u32 * value )
{
struct slot * slot = hotplug_slot - > private ;
struct pci_bus * bus = slot - > ctrl - > pci_dev - > subordinate ;
2008-03-04 06:09:46 +03:00
dbg ( " %s - physical_slot = %s \n " , __func__ , hotplug_slot - > name ) ;
2006-05-12 08:39:45 +04:00
* value = ( pci_domain_nr ( bus ) < < 16 ) | ( slot - > bus < < 8 ) | slot - > device ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
static int get_max_bus_speed ( struct hotplug_slot * hotplug_slot , enum pci_bus_speed * value )
{
struct slot * slot = hotplug_slot - > private ;
int retval ;
2008-03-04 06:09:46 +03:00
dbg ( " %s - physical_slot = %s \n " , __func__ , hotplug_slot - > name ) ;
2007-08-10 03:09:35 +04:00
2005-04-17 02:20:36 +04:00
retval = slot - > hpc_ops - > get_max_bus_speed ( slot , value ) ;
if ( retval < 0 )
* value = PCI_SPEED_UNKNOWN ;
return 0 ;
}
static int get_cur_bus_speed ( struct hotplug_slot * hotplug_slot , enum pci_bus_speed * value )
{
struct slot * slot = hotplug_slot - > private ;
int retval ;
2008-03-04 06:09:46 +03:00
dbg ( " %s - physical_slot = %s \n " , __func__ , hotplug_slot - > name ) ;
2007-08-10 03:09:35 +04:00
2005-04-17 02:20:36 +04:00
retval = slot - > hpc_ops - > get_cur_bus_speed ( slot , value ) ;
if ( retval < 0 )
* value = PCI_SPEED_UNKNOWN ;
return 0 ;
}
static int pciehp_probe ( struct pcie_device * dev , const struct pcie_port_service_id * id )
{
int rc ;
struct controller * ctrl ;
struct slot * t_slot ;
u8 value ;
2008-05-28 09:57:30 +04:00
struct pci_dev * pdev = dev - > port ;
if ( pciehp_force )
dbg ( " Bypassing BIOS check for pciehp use on %s \n " ,
pci_name ( pdev ) ) ;
else if ( pciehp_get_hp_hw_control_from_firmware ( pdev ) )
goto err_out_none ;
2007-08-10 03:09:35 +04:00
2006-02-28 17:34:49 +03:00
ctrl = kzalloc ( sizeof ( * ctrl ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! ctrl ) {
2008-03-04 06:09:46 +03:00
err ( " %s : out of memory \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
goto err_out_none ;
}
2006-12-22 04:01:03 +03:00
INIT_LIST_HEAD ( & ctrl - > slot_list ) ;
2005-04-17 02:20:36 +04:00
2005-11-01 03:20:09 +03:00
rc = pcie_init ( ctrl , dev ) ;
2005-04-17 02:20:36 +04:00
if ( rc ) {
dbg ( " %s: controller initialization failed \n " , PCIE_MODULE_NAME ) ;
goto err_out_free_ctrl ;
}
pci_set_drvdata ( pdev , ctrl ) ;
2007-11-09 11:30:29 +03:00
dbg ( " %s: ctrl bus=0x%x, device=%x, function=%x, irq=%x \n " ,
2008-03-04 06:09:46 +03:00
__func__ , pdev - > bus - > number , PCI_SLOT ( pdev - > devfn ) ,
2007-11-09 11:30:29 +03:00
PCI_FUNC ( pdev - > devfn ) , pdev - > irq ) ;
2005-04-17 02:20:36 +04:00
/* Setup the slot information structures */
rc = init_slots ( ctrl ) ;
if ( rc ) {
2006-12-22 04:01:07 +03:00
err ( " %s: slot initialization failed \n " , PCIE_MODULE_NAME ) ;
2006-12-22 04:01:05 +03:00
goto err_out_release_ctlr ;
2005-04-17 02:20:36 +04:00
}
2006-12-22 04:01:04 +03:00
t_slot = pciehp_find_slot ( ctrl , ctrl - > slot_device_offset ) ;
2005-04-17 02:20:36 +04:00
t_slot - > hpc_ops - > get_adapter_status ( t_slot , & value ) ; /* Check if slot is occupied */
2008-03-17 23:04:23 +03:00
if ( value & & pciehp_force ) {
2007-11-29 02:11:28 +03:00
rc = pciehp_enable_slot ( t_slot ) ;
if ( rc ) /* -ENODEV: shouldn't happen, but deal with it */
value = 0 ;
}
2008-04-26 01:39:06 +04:00
if ( ( POWER_CTRL ( ctrl ) ) & & ! value ) {
2005-04-17 02:20:36 +04:00
rc = t_slot - > hpc_ops - > power_off_slot ( t_slot ) ; /* Power off slot if not occupied*/
2006-12-22 04:01:09 +03:00
if ( rc )
2005-04-17 02:20:36 +04:00
goto err_out_free_ctrl_slot ;
}
return 0 ;
err_out_free_ctrl_slot :
cleanup_slots ( ctrl ) ;
2006-12-22 04:01:05 +03:00
err_out_release_ctlr :
2005-04-17 02:20:36 +04:00
ctrl - > hpc_ops - > release_ctlr ( ctrl ) ;
err_out_free_ctrl :
kfree ( ctrl ) ;
err_out_none :
return - ENODEV ;
}
2007-03-07 02:02:32 +03:00
static void pciehp_remove ( struct pcie_device * dev )
2005-04-17 02:20:36 +04:00
{
2007-03-07 02:02:32 +03:00
struct pci_dev * pdev = dev - > port ;
struct controller * ctrl = pci_get_drvdata ( pdev ) ;
2005-04-17 02:20:36 +04:00
2007-03-07 02:02:32 +03:00
cleanup_slots ( ctrl ) ;
ctrl - > hpc_ops - > release_ctlr ( ctrl ) ;
kfree ( ctrl ) ;
2005-04-17 02:20:36 +04:00
}
# ifdef CONFIG_PM
2005-04-17 02:25:33 +04:00
static int pciehp_suspend ( struct pcie_device * dev , pm_message_t state )
2005-04-17 02:20:36 +04:00
{
2008-03-04 06:09:46 +03:00
printk ( " %s ENTRY \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int pciehp_resume ( struct pcie_device * dev )
{
2008-03-04 06:09:46 +03:00
printk ( " %s ENTRY \n " , __func__ ) ;
2007-11-29 02:12:00 +03:00
if ( pciehp_force ) {
struct pci_dev * pdev = dev - > port ;
struct controller * ctrl = pci_get_drvdata ( pdev ) ;
struct slot * t_slot ;
u8 status ;
/* reinitialize the chipset's event detection logic */
2007-11-22 02:07:55 +03:00
pcie_init_hardware_part2 ( ctrl , dev ) ;
2007-11-29 02:12:00 +03:00
t_slot = pciehp_find_slot ( ctrl , ctrl - > slot_device_offset ) ;
/* Check if slot is occupied */
t_slot - > hpc_ops - > get_adapter_status ( t_slot , & status ) ;
if ( status )
pciehp_enable_slot ( t_slot ) ;
else
pciehp_disable_slot ( t_slot ) ;
}
2005-04-17 02:20:36 +04:00
return 0 ;
}
# endif
2007-08-10 03:09:35 +04:00
static struct pcie_port_service_id port_pci_ids [ ] = { {
. vendor = PCI_ANY_ID ,
2005-04-17 02:20:36 +04:00
. device = PCI_ANY_ID ,
2005-05-07 04:19:09 +04:00
. port_type = PCIE_ANY_PORT ,
2005-04-17 02:20:36 +04:00
. service_type = PCIE_PORT_SERVICE_HP ,
2007-08-10 03:09:35 +04:00
. driver_data = 0 ,
2005-04-17 02:20:36 +04:00
} , { /* end: all zeroes */ }
} ;
static const char device_name [ ] = " hpdriver " ;
static struct pcie_port_service_driver hpdriver_portdrv = {
. name = ( char * ) device_name ,
. id_table = & port_pci_ids [ 0 ] ,
. probe = pciehp_probe ,
. remove = pciehp_remove ,
# ifdef CONFIG_PM
. suspend = pciehp_suspend ,
. resume = pciehp_resume ,
# endif /* PM */
} ;
static int __init pcied_init ( void )
{
int retval = 0 ;
2005-11-01 03:20:07 +03:00
retval = pcie_port_service_register ( & hpdriver_portdrv ) ;
dbg ( " pcie_port_service_register = %d \n " , retval ) ;
info ( DRIVER_DESC " version: " DRIVER_VERSION " \n " ) ;
if ( retval )
2008-03-04 06:09:46 +03:00
dbg ( " %s: Failure to register service \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return retval ;
}
static void __exit pcied_cleanup ( void )
{
dbg ( " unload_pciehpd() \n " ) ;
pcie_port_service_unregister ( & hpdriver_portdrv ) ;
info ( DRIVER_DESC " version: " DRIVER_VERSION " unloaded \n " ) ;
}
module_init ( pcied_init ) ;
module_exit ( pcied_cleanup ) ;