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/kernel.h>
# include <linux/types.h>
# include <linux/smp_lock.h>
# include <linux/pci.h>
2007-03-07 02:02:26 +03:00
# include <linux/workqueue.h>
2005-04-17 02:20:36 +04:00
# include "../pci.h"
# include "pciehp.h"
2007-03-07 02:02:26 +03:00
static void interrupt_event_handler ( struct work_struct * work ) ;
2005-04-17 02:20:36 +04:00
2007-03-07 02:02:26 +03:00
static int queue_interrupt_event ( struct slot * p_slot , u32 event_type )
2006-09-22 21:17:10 +04:00
{
2007-03-07 02:02:26 +03:00
struct event_info * info ;
info = kmalloc ( sizeof ( * info ) , GFP_ATOMIC ) ;
if ( ! info )
return - ENOMEM ;
info - > event_type = event_type ;
info - > p_slot = p_slot ;
INIT_WORK ( & info - > work , interrupt_event_handler ) ;
schedule_work ( & info - > work ) ;
return 0 ;
2006-09-22 21:17:10 +04:00
}
2008-05-27 14:03:16 +04:00
u8 pciehp_handle_attention_button ( struct slot * p_slot )
2005-04-17 02:20:36 +04:00
{
2007-03-07 02:02:26 +03:00
u32 event_type ;
2005-04-17 02:20:36 +04:00
/* Attention Button Change */
dbg ( " pciehp: Attention button interrupt received. \n " ) ;
/*
* Button pressed - See if need to TAKE ACTION ! ! !
*/
2007-03-07 02:02:26 +03:00
info ( " Button pressed on Slot(%s) \n " , p_slot - > name ) ;
event_type = INT_BUTTON_PRESS ;
2005-04-17 02:20:36 +04:00
2007-03-07 02:02:26 +03:00
queue_interrupt_event ( p_slot , event_type ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2008-05-27 14:03:16 +04:00
u8 pciehp_handle_switch_change ( struct slot * p_slot )
2005-04-17 02:20:36 +04:00
{
u8 getstatus ;
2007-03-07 02:02:26 +03:00
u32 event_type ;
2005-04-17 02:20:36 +04:00
/* Switch Change */
dbg ( " pciehp: Switch interrupt received. \n " ) ;
p_slot - > hpc_ops - > get_latch_status ( p_slot , & getstatus ) ;
if ( getstatus ) {
/*
* Switch opened
*/
2007-03-07 02:02:26 +03:00
info ( " Latch open on Slot(%s) \n " , p_slot - > name ) ;
event_type = INT_SWITCH_OPEN ;
2005-04-17 02:20:36 +04:00
} else {
/*
* Switch closed
*/
2007-03-07 02:02:26 +03:00
info ( " Latch close on Slot(%s) \n " , p_slot - > name ) ;
event_type = INT_SWITCH_CLOSE ;
2005-04-17 02:20:36 +04:00
}
2007-03-07 02:02:26 +03:00
queue_interrupt_event ( p_slot , event_type ) ;
2005-04-17 02:20:36 +04:00
2007-03-07 02:02:26 +03:00
return 1 ;
2005-04-17 02:20:36 +04:00
}
2008-05-27 14:03:16 +04:00
u8 pciehp_handle_presence_change ( struct slot * p_slot )
2005-04-17 02:20:36 +04:00
{
2007-03-07 02:02:26 +03:00
u32 event_type ;
u8 presence_save ;
2005-04-17 02:20:36 +04:00
/* Presence Change */
dbg ( " pciehp: Presence/Notify input change. \n " ) ;
/* Switch is open, assume a presence change
* Save the presence state
*/
2005-11-01 03:20:09 +03:00
p_slot - > hpc_ops - > get_adapter_status ( p_slot , & presence_save ) ;
if ( presence_save ) {
2005-04-17 02:20:36 +04:00
/*
* Card Present
*/
2007-03-07 02:02:26 +03:00
info ( " Card present on Slot(%s) \n " , p_slot - > name ) ;
event_type = INT_PRESENCE_ON ;
2005-04-17 02:20:36 +04:00
} else {
/*
* Not Present
*/
2007-03-07 02:02:26 +03:00
info ( " Card not present on Slot(%s) \n " , p_slot - > name ) ;
event_type = INT_PRESENCE_OFF ;
2005-04-17 02:20:36 +04:00
}
2007-03-07 02:02:26 +03:00
queue_interrupt_event ( p_slot , event_type ) ;
2005-04-17 02:20:36 +04:00
2007-03-07 02:02:26 +03:00
return 1 ;
2005-04-17 02:20:36 +04:00
}
2008-05-27 14:03:16 +04:00
u8 pciehp_handle_power_fault ( struct slot * p_slot )
2005-04-17 02:20:36 +04:00
{
2007-03-07 02:02:26 +03:00
u32 event_type ;
2005-04-17 02:20:36 +04:00
/* power fault */
dbg ( " pciehp: Power fault interrupt received. \n " ) ;
if ( ! ( p_slot - > hpc_ops - > query_power_fault ( p_slot ) ) ) {
/*
* power fault Cleared
*/
2007-03-07 02:02:26 +03:00
info ( " Power fault cleared on Slot(%s) \n " , p_slot - > name ) ;
event_type = INT_POWER_FAULT_CLEAR ;
2005-04-17 02:20:36 +04:00
} else {
/*
* power fault
*/
2007-03-07 02:02:26 +03:00
info ( " Power fault on Slot(%s) \n " , p_slot - > name ) ;
event_type = INT_POWER_FAULT ;
2008-05-27 14:03:16 +04:00
info ( " power fault bit %x set \n " , 0 ) ;
2005-04-17 02:20:36 +04:00
}
2007-03-07 02:02:26 +03:00
queue_interrupt_event ( p_slot , event_type ) ;
return 1 ;
2005-04-17 02:20:36 +04:00
}
2007-08-10 03:09:36 +04:00
/* The following routines constitute the bulk of the
2005-04-17 02:20:36 +04:00
hotplug controller logic
*/
static void set_slot_off ( struct controller * ctrl , struct slot * pslot )
{
/* turn off slot, turn on Amber LED, turn off Green LED if supported*/
2008-04-26 01:39:06 +04:00
if ( POWER_CTRL ( ctrl ) ) {
2007-08-10 03:09:36 +04:00
if ( pslot - > hpc_ops - > power_off_slot ( pslot ) ) {
2006-12-22 04:01:09 +03:00
err ( " %s: Issue of Slot Power Off command failed \n " ,
2008-03-04 06:09:46 +03:00
__func__ ) ;
2005-04-17 02:20:36 +04:00
return ;
}
}
2008-05-27 14:06:22 +04:00
/*
* After turning power off , we must wait for at least 1 second
* before taking any action that relies on power having been
* removed from the slot / adapter .
*/
msleep ( 1000 ) ;
2008-04-26 01:39:06 +04:00
if ( PWR_LED ( ctrl ) )
2007-08-10 03:09:36 +04:00
pslot - > hpc_ops - > green_led_off ( pslot ) ;
2005-04-17 02:20:36 +04:00
2008-04-26 01:39:06 +04:00
if ( ATTN_LED ( ctrl ) ) {
2006-12-22 04:01:09 +03:00
if ( pslot - > hpc_ops - > set_attention_status ( pslot , 1 ) ) {
err ( " %s: Issue of Set Attention Led command failed \n " ,
2008-03-04 06:09:46 +03:00
__func__ ) ;
2005-04-17 02:20:36 +04:00
return ;
}
}
}
/**
* board_added - Called after a board has been added to the system .
2007-11-28 20:04:30 +03:00
* @ p_slot : & slot where board is added
2005-04-17 02:20:36 +04:00
*
2007-11-28 20:04:30 +03:00
* Turns power on for the board .
* Configures board .
2005-04-17 02:20:36 +04:00
*/
2005-11-01 03:20:09 +03:00
static int board_added ( struct slot * p_slot )
2005-04-17 02:20:36 +04:00
{
2006-12-22 04:01:09 +03:00
int retval = 0 ;
2005-11-01 03:20:08 +03:00
struct controller * ctrl = p_slot - > ctrl ;
2005-04-17 02:20:36 +04:00
2005-11-01 03:20:10 +03:00
dbg ( " %s: slot device, slot offset, hp slot = %d, %d ,%d \n " ,
2008-03-04 06:09:46 +03:00
__func__ , p_slot - > device ,
2007-11-09 11:29:42 +03:00
ctrl - > slot_device_offset , p_slot - > hp_slot ) ;
2005-04-17 02:20:36 +04:00
2008-04-26 01:39:06 +04:00
if ( POWER_CTRL ( ctrl ) ) {
2005-04-17 02:20:36 +04:00
/* Power on slot */
2006-12-22 04:01:09 +03:00
retval = p_slot - > hpc_ops - > power_on_slot ( p_slot ) ;
if ( retval )
return retval ;
2005-04-17 02:20:36 +04:00
}
2007-08-10 03:09:36 +04:00
2008-04-26 01:39:06 +04:00
if ( PWR_LED ( ctrl ) )
2005-04-17 02:20:36 +04:00
p_slot - > hpc_ops - > green_led_blink ( p_slot ) ;
/* Wait for ~1 second */
2006-12-22 04:01:09 +03:00
msleep ( 1000 ) ;
2005-04-17 02:20:36 +04:00
2006-12-22 04:01:09 +03:00
/* Check link training status */
retval = p_slot - > hpc_ops - > check_lnk_status ( ctrl ) ;
if ( retval ) {
2008-03-04 06:09:46 +03:00
err ( " %s: Failed to check link status \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
set_slot_off ( ctrl , p_slot ) ;
2006-12-22 04:01:09 +03:00
return retval ;
2005-04-17 02:20:36 +04:00
}
/* Check for a power fault */
2005-11-24 02:44:54 +03:00
if ( p_slot - > hpc_ops - > query_power_fault ( p_slot ) ) {
2008-03-04 06:09:46 +03:00
dbg ( " %s: power fault detected \n " , __func__ ) ;
2006-12-22 04:01:09 +03:00
retval = POWER_FAILURE ;
2005-11-01 03:20:06 +03:00
goto err_exit ;
2005-04-17 02:20:36 +04:00
}
2006-12-22 04:01:09 +03:00
retval = pciehp_configure_device ( p_slot ) ;
if ( retval ) {
2005-11-01 03:20:06 +03:00
err ( " Cannot add device 0x%x:%x \n " , p_slot - > bus ,
2006-12-22 04:01:09 +03:00
p_slot - > device ) ;
2005-11-01 03:20:06 +03:00
goto err_exit ;
}
2005-04-17 02:20:36 +04:00
2005-11-01 03:20:06 +03:00
/*
* Some PCI Express root ports require fixup after hot - plug operation .
*/
if ( pcie_mch_quirk )
pci_fixup_device ( pci_fixup_final , ctrl - > pci_dev ) ;
2008-04-26 01:39:06 +04:00
if ( PWR_LED ( ctrl ) )
2005-11-01 03:20:06 +03:00
p_slot - > hpc_ops - > green_led_on ( p_slot ) ;
2006-12-22 04:01:09 +03:00
2005-04-17 02:20:36 +04:00
return 0 ;
2005-11-01 03:20:06 +03:00
err_exit :
set_slot_off ( ctrl , p_slot ) ;
2006-12-22 04:01:09 +03:00
return retval ;
2005-04-17 02:20:36 +04:00
}
/**
2007-11-28 20:04:30 +03:00
* remove_board - Turns off slot and LEDs
* @ p_slot : slot where board is being removed
2005-04-17 02:20:36 +04:00
*/
2005-11-01 03:20:09 +03:00
static int remove_board ( struct slot * p_slot )
2005-04-17 02:20:36 +04:00
{
2006-12-22 04:01:09 +03:00
int retval = 0 ;
2005-11-01 03:20:08 +03:00
struct controller * ctrl = p_slot - > ctrl ;
2005-04-17 02:20:36 +04:00
2006-12-22 04:01:09 +03:00
retval = pciehp_unconfigure_device ( p_slot ) ;
if ( retval )
return retval ;
2005-04-17 02:20:36 +04:00
2008-03-04 06:09:46 +03:00
dbg ( " In %s, hp_slot = %d \n " , __func__ , p_slot - > hp_slot ) ;
2005-04-17 02:20:36 +04:00
2008-04-26 01:39:06 +04:00
if ( POWER_CTRL ( ctrl ) ) {
2005-04-17 02:20:36 +04:00
/* power off slot */
2006-12-22 04:01:09 +03:00
retval = p_slot - > hpc_ops - > power_off_slot ( p_slot ) ;
if ( retval ) {
err ( " %s: Issue of Slot Disable command failed \n " ,
2008-03-04 06:09:46 +03:00
__func__ ) ;
2006-12-22 04:01:09 +03:00
return retval ;
2005-04-17 02:20:36 +04:00
}
}
2008-05-27 14:06:22 +04:00
/*
* After turning power off , we must wait for at least 1 second
* before taking any action that relies on power having been
* removed from the slot / adapter .
*/
msleep ( 1000 ) ;
2008-04-26 01:39:06 +04:00
if ( PWR_LED ( ctrl ) )
2005-04-17 02:20:36 +04:00
/* turn off Green LED */
p_slot - > hpc_ops - > green_led_off ( p_slot ) ;
return 0 ;
}
2007-03-07 02:02:26 +03:00
struct power_work_info {
struct slot * p_slot ;
struct work_struct work ;
} ;
2005-04-17 02:20:36 +04:00
/**
2007-11-28 20:04:30 +03:00
* pciehp_power_thread - handle pushbutton events
* @ work : & struct work_struct describing work to be done
2005-04-17 02:20:36 +04:00
*
2007-11-28 20:04:30 +03:00
* Scheduled procedure to handle blocking stuff for the pushbuttons .
2005-04-17 02:20:36 +04:00
* Handles all pending events and exits .
*/
2007-03-07 02:02:26 +03:00
static void pciehp_power_thread ( struct work_struct * work )
2005-04-17 02:20:36 +04:00
{
2007-03-07 02:02:26 +03:00
struct power_work_info * info =
container_of ( work , struct power_work_info , work ) ;
struct slot * p_slot = info - > p_slot ;
mutex_lock ( & p_slot - > lock ) ;
switch ( p_slot - > state ) {
case POWEROFF_STATE :
mutex_unlock ( & p_slot - > lock ) ;
dbg ( " %s: disabling bus:device(%x:%x) \n " ,
2008-03-04 06:09:46 +03:00
__func__ , p_slot - > bus , p_slot - > device ) ;
2005-04-17 02:20:36 +04:00
pciehp_disable_slot ( p_slot ) ;
2007-03-07 02:02:26 +03:00
mutex_lock ( & p_slot - > lock ) ;
2005-04-17 02:20:36 +04:00
p_slot - > state = STATIC_STATE ;
2007-03-07 02:02:26 +03:00
break ;
case POWERON_STATE :
mutex_unlock ( & p_slot - > lock ) ;
2006-12-22 04:01:09 +03:00
if ( pciehp_enable_slot ( p_slot ) & &
2008-04-26 01:39:06 +04:00
PWR_LED ( p_slot - > ctrl ) )
2005-04-17 02:20:36 +04:00
p_slot - > hpc_ops - > green_led_off ( p_slot ) ;
2007-03-07 02:02:26 +03:00
mutex_lock ( & p_slot - > lock ) ;
2005-04-17 02:20:36 +04:00
p_slot - > state = STATIC_STATE ;
2007-03-07 02:02:26 +03:00
break ;
default :
break ;
2005-04-17 02:20:36 +04:00
}
2007-03-07 02:02:26 +03:00
mutex_unlock ( & p_slot - > lock ) ;
2005-04-17 02:20:36 +04:00
2007-03-07 02:02:26 +03:00
kfree ( info ) ;
2005-04-17 02:20:36 +04:00
}
2007-03-21 21:45:31 +03:00
void pciehp_queue_pushbutton_work ( struct work_struct * work )
2005-04-17 02:20:36 +04:00
{
2007-03-07 02:02:26 +03:00
struct slot * p_slot = container_of ( work , struct slot , work . work ) ;
struct power_work_info * info ;
2005-04-17 02:20:36 +04:00
2007-03-07 02:02:26 +03:00
info = kmalloc ( sizeof ( * info ) , GFP_KERNEL ) ;
if ( ! info ) {
2008-03-04 06:09:46 +03:00
err ( " %s: Cannot allocate memory \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2007-03-07 02:02:26 +03:00
info - > p_slot = p_slot ;
INIT_WORK ( & info - > work , pciehp_power_thread ) ;
2005-04-17 02:20:36 +04:00
2007-03-07 02:02:26 +03:00
mutex_lock ( & p_slot - > lock ) ;
switch ( p_slot - > state ) {
case BLINKINGOFF_STATE :
2005-04-17 02:20:36 +04:00
p_slot - > state = POWEROFF_STATE ;
2007-03-07 02:02:26 +03:00
break ;
case BLINKINGON_STATE :
2005-04-17 02:20:36 +04:00
p_slot - > state = POWERON_STATE ;
2007-03-07 02:02:26 +03:00
break ;
default :
goto out ;
2005-04-17 02:20:36 +04:00
}
2007-03-07 02:02:26 +03:00
queue_work ( pciehp_wq , & info - > work ) ;
out :
mutex_unlock ( & p_slot - > lock ) ;
2005-04-17 02:20:36 +04:00
}
static int update_slot_info ( struct slot * slot )
{
struct hotplug_slot_info * info ;
int result ;
2007-03-07 02:02:26 +03:00
info = kmalloc ( sizeof ( * info ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! info )
return - ENOMEM ;
slot - > hpc_ops - > get_power_status ( slot , & ( info - > power_status ) ) ;
slot - > hpc_ops - > get_attention_status ( slot , & ( info - > attention_status ) ) ;
slot - > hpc_ops - > get_latch_status ( slot , & ( info - > latch_status ) ) ;
slot - > hpc_ops - > get_adapter_status ( slot , & ( info - > adapter_status ) ) ;
result = pci_hp_change_slot_info ( slot - > hotplug_slot , info ) ;
kfree ( info ) ;
return result ;
}
2007-03-07 02:02:26 +03:00
/*
* Note : This function must be called with slot - > lock held
*/
static void handle_button_press_event ( struct slot * p_slot )
2005-04-17 02:20:36 +04:00
{
2007-03-07 02:02:26 +03:00
struct controller * ctrl = p_slot - > ctrl ;
2005-04-17 02:20:36 +04:00
u8 getstatus ;
2007-03-07 02:02:26 +03:00
switch ( p_slot - > state ) {
case STATIC_STATE :
p_slot - > hpc_ops - > get_power_status ( p_slot , & getstatus ) ;
if ( getstatus ) {
p_slot - > state = BLINKINGOFF_STATE ;
info ( " PCI slot #%s - powering off due to button "
" press. \n " , p_slot - > name ) ;
} else {
p_slot - > state = BLINKINGON_STATE ;
info ( " PCI slot #%s - powering on due to button "
" press. \n " , p_slot - > name ) ;
}
/* blink green LED and turn off amber */
2008-04-26 01:39:06 +04:00
if ( PWR_LED ( ctrl ) )
2007-03-07 02:02:26 +03:00
p_slot - > hpc_ops - > green_led_blink ( p_slot ) ;
2008-04-26 01:39:06 +04:00
if ( ATTN_LED ( ctrl ) )
2007-03-07 02:02:26 +03:00
p_slot - > hpc_ops - > set_attention_status ( p_slot , 0 ) ;
schedule_delayed_work ( & p_slot - > work , 5 * HZ ) ;
break ;
case BLINKINGOFF_STATE :
case BLINKINGON_STATE :
/*
* Cancel if we are still blinking ; this means that we
* press the attention again before the 5 sec . limit
* expires to cancel hot - add or hot - remove
*/
info ( " Button cancel on Slot(%s) \n " , p_slot - > name ) ;
2008-03-04 06:09:46 +03:00
dbg ( " %s: button cancel \n " , __func__ ) ;
2007-03-07 02:02:26 +03:00
cancel_delayed_work ( & p_slot - > work ) ;
if ( p_slot - > state = = BLINKINGOFF_STATE ) {
2008-04-26 01:39:06 +04:00
if ( PWR_LED ( ctrl ) )
2007-03-07 02:02:26 +03:00
p_slot - > hpc_ops - > green_led_on ( p_slot ) ;
} else {
2008-04-26 01:39:06 +04:00
if ( PWR_LED ( ctrl ) )
2007-03-07 02:02:26 +03:00
p_slot - > hpc_ops - > green_led_off ( p_slot ) ;
}
2008-04-26 01:39:06 +04:00
if ( ATTN_LED ( ctrl ) )
2007-03-07 02:02:26 +03:00
p_slot - > hpc_ops - > set_attention_status ( p_slot , 0 ) ;
info ( " PCI slot #%s - action canceled due to button press \n " ,
p_slot - > name ) ;
p_slot - > state = STATIC_STATE ;
break ;
case POWEROFF_STATE :
case POWERON_STATE :
/*
* Ignore if the slot is on power - on or power - off state ;
* this means that the previous attention button action
* to hot - add or hot - remove is undergoing
*/
info ( " Button ignore on Slot(%s) \n " , p_slot - > name ) ;
update_slot_info ( p_slot ) ;
break ;
default :
warn ( " Not a valid state \n " ) ;
break ;
2005-04-17 02:20:36 +04:00
}
}
2007-03-07 02:02:26 +03:00
/*
* Note : This function must be called with slot - > lock held
*/
static void handle_surprise_event ( struct slot * p_slot )
{
u8 getstatus ;
struct power_work_info * info ;
info = kmalloc ( sizeof ( * info ) , GFP_KERNEL ) ;
if ( ! info ) {
2008-03-04 06:09:46 +03:00
err ( " %s: Cannot allocate memory \n " , __func__ ) ;
2007-03-07 02:02:26 +03:00
return ;
}
info - > p_slot = p_slot ;
INIT_WORK ( & info - > work , pciehp_power_thread ) ;
p_slot - > hpc_ops - > get_adapter_status ( p_slot , & getstatus ) ;
if ( ! getstatus )
p_slot - > state = POWEROFF_STATE ;
else
p_slot - > state = POWERON_STATE ;
queue_work ( pciehp_wq , & info - > work ) ;
}
static void interrupt_event_handler ( struct work_struct * work )
{
struct event_info * info = container_of ( work , struct event_info , work ) ;
struct slot * p_slot = info - > p_slot ;
struct controller * ctrl = p_slot - > ctrl ;
mutex_lock ( & p_slot - > lock ) ;
switch ( info - > event_type ) {
case INT_BUTTON_PRESS :
handle_button_press_event ( p_slot ) ;
break ;
case INT_POWER_FAULT :
2008-04-26 01:39:06 +04:00
if ( ! POWER_CTRL ( ctrl ) )
2007-03-07 02:02:26 +03:00
break ;
2008-04-26 01:39:06 +04:00
if ( ATTN_LED ( ctrl ) )
2007-03-07 02:02:26 +03:00
p_slot - > hpc_ops - > set_attention_status ( p_slot , 1 ) ;
2008-04-26 01:39:06 +04:00
if ( PWR_LED ( ctrl ) )
2007-03-07 02:02:26 +03:00
p_slot - > hpc_ops - > green_led_off ( p_slot ) ;
break ;
case INT_PRESENCE_ON :
case INT_PRESENCE_OFF :
2008-04-26 01:39:06 +04:00
if ( ! HP_SUPR_RM ( ctrl ) )
2007-03-07 02:02:26 +03:00
break ;
dbg ( " Surprise Removal \n " ) ;
update_slot_info ( p_slot ) ;
handle_surprise_event ( p_slot ) ;
break ;
default :
update_slot_info ( p_slot ) ;
break ;
}
mutex_unlock ( & p_slot - > lock ) ;
kfree ( info ) ;
}
2005-04-17 02:20:36 +04:00
int pciehp_enable_slot ( struct slot * p_slot )
{
u8 getstatus = 0 ;
int rc ;
/* Check to see if (latch closed, card present, power off) */
2006-01-13 18:02:15 +03:00
mutex_lock ( & p_slot - > ctrl - > crit_sect ) ;
2005-04-17 02:20:36 +04:00
rc = p_slot - > hpc_ops - > get_adapter_status ( p_slot , & getstatus ) ;
if ( rc | | ! getstatus ) {
2008-03-04 06:09:46 +03:00
info ( " %s: no adapter on slot(%s) \n " , __func__ ,
2007-03-07 02:02:26 +03:00
p_slot - > name ) ;
2006-01-13 18:02:15 +03:00
mutex_unlock ( & p_slot - > ctrl - > crit_sect ) ;
2006-09-20 04:04:33 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
2008-04-26 01:39:06 +04:00
if ( MRL_SENS ( p_slot - > ctrl ) ) {
2005-04-17 02:20:36 +04:00
rc = p_slot - > hpc_ops - > get_latch_status ( p_slot , & getstatus ) ;
if ( rc | | getstatus ) {
2008-03-04 06:09:46 +03:00
info ( " %s: latch open on slot(%s) \n " , __func__ ,
2007-03-07 02:02:26 +03:00
p_slot - > name ) ;
2006-01-13 18:02:15 +03:00
mutex_unlock ( & p_slot - > ctrl - > crit_sect ) ;
2006-09-20 04:04:33 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
}
2007-08-10 03:09:36 +04:00
2008-04-26 01:39:06 +04:00
if ( POWER_CTRL ( p_slot - > ctrl ) ) {
2005-04-17 02:20:36 +04:00
rc = p_slot - > hpc_ops - > get_power_status ( p_slot , & getstatus ) ;
if ( rc | | getstatus ) {
2008-03-04 06:09:46 +03:00
info ( " %s: already enabled on slot(%s) \n " , __func__ ,
2007-03-07 02:02:26 +03:00
p_slot - > name ) ;
2006-01-13 18:02:15 +03:00
mutex_unlock ( & p_slot - > ctrl - > crit_sect ) ;
2006-09-20 04:04:33 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
}
p_slot - > hpc_ops - > get_latch_status ( p_slot , & getstatus ) ;
2005-11-01 03:20:08 +03:00
rc = board_added ( p_slot ) ;
2005-04-17 02:20:36 +04:00
if ( rc ) {
p_slot - > hpc_ops - > get_latch_status ( p_slot , & getstatus ) ;
}
2006-09-25 02:56:53 +04:00
update_slot_info ( p_slot ) ;
2005-04-17 02:20:36 +04:00
2006-09-22 21:17:29 +04:00
mutex_unlock ( & p_slot - > ctrl - > crit_sect ) ;
2005-04-17 02:20:36 +04:00
return rc ;
}
int pciehp_disable_slot ( struct slot * p_slot )
{
u8 getstatus = 0 ;
int ret = 0 ;
if ( ! p_slot - > ctrl )
return 1 ;
/* Check to see if (latch closed, card present, power on) */
2006-01-13 18:02:15 +03:00
mutex_lock ( & p_slot - > ctrl - > crit_sect ) ;
2005-04-17 02:20:36 +04:00
2008-04-26 01:39:06 +04:00
if ( ! HP_SUPR_RM ( p_slot - > ctrl ) ) {
2005-04-17 02:20:36 +04:00
ret = p_slot - > hpc_ops - > get_adapter_status ( p_slot , & getstatus ) ;
if ( ret | | ! getstatus ) {
2008-03-04 06:09:46 +03:00
info ( " %s: no adapter on slot(%s) \n " , __func__ ,
2007-03-07 02:02:26 +03:00
p_slot - > name ) ;
2006-01-13 18:02:15 +03:00
mutex_unlock ( & p_slot - > ctrl - > crit_sect ) ;
2006-09-20 04:04:33 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
}
2008-04-26 01:39:06 +04:00
if ( MRL_SENS ( p_slot - > ctrl ) ) {
2005-04-17 02:20:36 +04:00
ret = p_slot - > hpc_ops - > get_latch_status ( p_slot , & getstatus ) ;
if ( ret | | getstatus ) {
2008-03-04 06:09:46 +03:00
info ( " %s: latch open on slot(%s) \n " , __func__ ,
2007-03-07 02:02:26 +03:00
p_slot - > name ) ;
2006-01-13 18:02:15 +03:00
mutex_unlock ( & p_slot - > ctrl - > crit_sect ) ;
2006-09-20 04:04:33 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
}
2008-04-26 01:39:06 +04:00
if ( POWER_CTRL ( p_slot - > ctrl ) ) {
2005-04-17 02:20:36 +04:00
ret = p_slot - > hpc_ops - > get_power_status ( p_slot , & getstatus ) ;
if ( ret | | ! getstatus ) {
2008-03-04 06:09:46 +03:00
info ( " %s: already disabled slot(%s) \n " , __func__ ,
2007-03-07 02:02:26 +03:00
p_slot - > name ) ;
2006-01-13 18:02:15 +03:00
mutex_unlock ( & p_slot - > ctrl - > crit_sect ) ;
2006-09-20 04:04:33 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
}
2005-11-01 03:20:08 +03:00
ret = remove_board ( p_slot ) ;
update_slot_info ( p_slot ) ;
2006-09-22 21:17:29 +04:00
mutex_unlock ( & p_slot - > ctrl - > crit_sect ) ;
2005-11-01 03:20:08 +03:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2007-03-07 02:02:26 +03:00
int pciehp_sysfs_enable_slot ( struct slot * p_slot )
{
int retval = - ENODEV ;
mutex_lock ( & p_slot - > lock ) ;
switch ( p_slot - > state ) {
case BLINKINGON_STATE :
cancel_delayed_work ( & p_slot - > work ) ;
case STATIC_STATE :
p_slot - > state = POWERON_STATE ;
mutex_unlock ( & p_slot - > lock ) ;
retval = pciehp_enable_slot ( p_slot ) ;
mutex_lock ( & p_slot - > lock ) ;
p_slot - > state = STATIC_STATE ;
break ;
case POWERON_STATE :
info ( " Slot %s is already in powering on state \n " ,
p_slot - > name ) ;
break ;
case BLINKINGOFF_STATE :
case POWEROFF_STATE :
info ( " Already enabled on slot %s \n " , p_slot - > name ) ;
break ;
default :
err ( " Not a valid state on slot %s \n " , p_slot - > name ) ;
break ;
}
mutex_unlock ( & p_slot - > lock ) ;
return retval ;
}
int pciehp_sysfs_disable_slot ( struct slot * p_slot )
{
int retval = - ENODEV ;
mutex_lock ( & p_slot - > lock ) ;
switch ( p_slot - > state ) {
case BLINKINGOFF_STATE :
cancel_delayed_work ( & p_slot - > work ) ;
case STATIC_STATE :
p_slot - > state = POWEROFF_STATE ;
mutex_unlock ( & p_slot - > lock ) ;
retval = pciehp_disable_slot ( p_slot ) ;
mutex_lock ( & p_slot - > lock ) ;
p_slot - > state = STATIC_STATE ;
break ;
case POWEROFF_STATE :
info ( " Slot %s is already in powering off state \n " ,
p_slot - > name ) ;
break ;
case BLINKINGON_STATE :
case POWERON_STATE :
info ( " Already disabled on slot %s \n " , p_slot - > name ) ;
break ;
default :
err ( " Not a valid state on slot %s \n " , p_slot - > name ) ;
break ;
}
mutex_unlock ( & p_slot - > lock ) ;
return retval ;
}