2005-04-17 02:20:36 +04:00
/*
* Standard 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/pci.h>
# include "../pci.h"
# include "shpchp.h"
2014-04-15 02:11:40 +04:00
int shpchp_configure_device ( struct slot * p_slot )
2005-04-17 02:20:36 +04:00
{
2005-10-13 23:05:36 +04:00
struct pci_dev * dev ;
2008-10-23 06:52:12 +04:00
struct controller * ctrl = p_slot - > ctrl ;
2012-05-18 05:58:41 +04:00
struct pci_dev * bridge = ctrl - > pci_dev ;
struct pci_bus * parent = bridge - > subordinate ;
2014-01-14 23:03:14 +04:00
int num , ret = 0 ;
pci_lock_rescan_remove ( ) ;
2005-10-13 23:05:36 +04:00
2005-11-25 06:21:25 +03:00
dev = pci_get_slot ( parent , PCI_DEVFN ( p_slot - > device , 0 ) ) ;
2005-10-13 23:05:36 +04:00
if ( dev ) {
2008-10-23 06:54:39 +04:00
ctrl_err ( ctrl , " Device %s already exists "
" at %04x:%02x:%02x, cannot hot-add \n " , pci_name ( dev ) ,
pci_domain_nr ( parent ) , p_slot - > bus , p_slot - > device ) ;
2005-11-25 06:21:25 +03:00
pci_dev_put ( dev ) ;
2014-01-14 23:03:14 +04:00
ret = - EINVAL ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2005-10-13 23:05:36 +04:00
num = pci_scan_slot ( parent , PCI_DEVFN ( p_slot - > device , 0 ) ) ;
if ( num = = 0 ) {
2008-10-23 06:52:12 +04:00
ctrl_err ( ctrl , " No new device found \n " ) ;
2014-01-14 23:03:14 +04:00
ret = - ENODEV ;
goto out ;
2005-10-13 23:05:36 +04:00
}
2005-04-17 02:20:36 +04:00
2013-01-15 07:12:22 +04:00
list_for_each_entry ( dev , & parent - > devices , bus_list ) {
if ( PCI_SLOT ( dev - > devfn ) ! = p_slot - > device )
2005-10-13 23:05:36 +04:00
continue ;
2014-05-04 08:23:44 +04:00
if ( pci_is_bridge ( dev ) )
2012-05-18 05:58:41 +04:00
pci_hp_add_bridge ( dev ) ;
}
pci_assign_unassigned_bridge_resources ( bridge ) ;
2013-01-15 07:12:22 +04:00
list_for_each_entry ( dev , & parent - > devices , bus_list ) {
if ( PCI_SLOT ( dev - > devfn ) ! = p_slot - > device )
2012-05-18 05:58:41 +04:00
continue ;
2009-09-15 02:35:30 +04:00
pci_configure_slot ( dev ) ;
2005-04-17 02:20:36 +04:00
}
2005-10-13 23:05:36 +04:00
pci_bus_add_devices ( parent ) ;
2012-05-18 05:58:41 +04:00
2014-01-14 23:03:14 +04:00
out :
pci_unlock_rescan_remove ( ) ;
return ret ;
2005-04-17 02:20:36 +04:00
}
2005-10-13 23:05:41 +04:00
int shpchp_unconfigure_device ( struct slot * p_slot )
2005-04-17 02:20:36 +04:00
{
int rc = 0 ;
2005-10-13 23:05:41 +04:00
u8 bctl = 0 ;
2005-11-25 06:21:25 +03:00
struct pci_bus * parent = p_slot - > ctrl - > pci_dev - > subordinate ;
2013-01-15 07:12:22 +04:00
struct pci_dev * dev , * temp ;
2008-10-23 06:52:12 +04:00
struct controller * ctrl = p_slot - > ctrl ;
2005-11-25 06:21:25 +03:00
2008-10-23 06:54:39 +04:00
ctrl_dbg ( ctrl , " %s: domain:bus:dev = %04x:%02x:%02x \n " ,
__func__ , pci_domain_nr ( parent ) , p_slot - > bus , p_slot - > device ) ;
2005-04-17 02:20:36 +04:00
2014-01-14 23:03:14 +04:00
pci_lock_rescan_remove ( ) ;
2013-01-15 07:12:22 +04:00
list_for_each_entry_safe ( dev , temp , & parent - > devices , bus_list ) {
if ( PCI_SLOT ( dev - > devfn ) ! = p_slot - > device )
2005-10-13 23:05:41 +04:00
continue ;
2013-01-15 07:12:22 +04:00
pci_dev_get ( dev ) ;
if ( dev - > hdr_type = = PCI_HEADER_TYPE_BRIDGE ) {
pci_read_config_byte ( dev , PCI_BRIDGE_CONTROL , & bctl ) ;
2005-10-13 23:05:41 +04:00
if ( bctl & PCI_BRIDGE_CTL_VGA ) {
2008-10-23 06:52:12 +04:00
ctrl_err ( ctrl ,
" Cannot remove display device %s \n " ,
2013-01-15 07:12:22 +04:00
pci_name ( dev ) ) ;
pci_dev_put ( dev ) ;
2010-05-20 21:15:01 +04:00
rc = - EINVAL ;
break ;
2005-10-13 23:05:41 +04:00
}
2005-04-17 02:20:36 +04:00
}
2013-01-15 07:12:22 +04:00
pci_stop_and_remove_bus_device ( dev ) ;
pci_dev_put ( dev ) ;
2005-04-17 02:20:36 +04:00
}
2014-01-14 23:03:14 +04:00
pci_unlock_rescan_remove ( ) ;
2005-04-17 02:20:36 +04:00
return rc ;
}