2018-01-26 14:22:04 -06:00
// SPDX-License-Identifier: GPL-2.0+
2005-04-16 15:20:36 -07: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 .
*
2005-08-16 15:16:10 -07:00
* Send feedback to < greg @ kroah . com > , < kristen . c . accardi @ intel . com >
2005-04-16 15:20:36 -07: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-14 16:11:40 -06:00
int shpchp_configure_device ( struct slot * p_slot )
2005-04-16 15:20:36 -07:00
{
2005-10-13 12:05:36 -07:00
struct pci_dev * dev ;
2008-10-23 11:52:12 +09:00
struct controller * ctrl = p_slot - > ctrl ;
2012-05-17 18:58:41 -07:00
struct pci_dev * bridge = ctrl - > pci_dev ;
struct pci_bus * parent = bridge - > subordinate ;
2014-01-14 12:03:14 -07:00
int num , ret = 0 ;
pci_lock_rescan_remove ( ) ;
2005-10-13 12:05:36 -07:00
2005-11-25 12:21:25 +09:00
dev = pci_get_slot ( parent , PCI_DEVFN ( p_slot - > device , 0 ) ) ;
2005-10-13 12:05:36 -07:00
if ( dev ) {
2014-04-18 20:13:50 -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 12:21:25 +09:00
pci_dev_put ( dev ) ;
2014-01-14 12:03:14 -07:00
ret = - EINVAL ;
goto out ;
2005-04-16 15:20:36 -07:00
}
2005-10-13 12:05:36 -07:00
num = pci_scan_slot ( parent , PCI_DEVFN ( p_slot - > device , 0 ) ) ;
if ( num = = 0 ) {
2008-10-23 11:52:12 +09:00
ctrl_err ( ctrl , " No new device found \n " ) ;
2014-01-14 12:03:14 -07:00
ret = - ENODEV ;
goto out ;
2005-10-13 12:05:36 -07:00
}
2005-04-16 15:20:36 -07:00
2017-10-20 15:38:54 -05:00
for_each_pci_bridge ( dev , parent ) {
if ( PCI_SLOT ( dev - > devfn ) = = p_slot - > device )
2012-05-17 18:58:41 -07:00
pci_hp_add_bridge ( dev ) ;
}
pci_assign_unassigned_bridge_resources ( bridge ) ;
2014-08-28 12:18:37 -06:00
pcie_bus_configure_settings ( parent ) ;
2005-10-13 12:05:36 -07:00
pci_bus_add_devices ( parent ) ;
2012-05-17 18:58:41 -07:00
2014-01-14 12:03:14 -07:00
out :
pci_unlock_rescan_remove ( ) ;
return ret ;
2005-04-16 15:20:36 -07:00
}
2020-05-21 19:04:57 +00:00
void shpchp_unconfigure_device ( struct slot * p_slot )
2005-04-16 15:20:36 -07:00
{
2005-11-25 12:21:25 +09:00
struct pci_bus * parent = p_slot - > ctrl - > pci_dev - > subordinate ;
2013-01-15 11:12:22 +08:00
struct pci_dev * dev , * temp ;
2008-10-23 11:52:12 +09:00
struct controller * ctrl = p_slot - > ctrl ;
2005-11-25 12:21:25 +09:00
2008-10-23 11:54:39 +09: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-16 15:20:36 -07:00
2014-01-14 12:03:14 -07:00
pci_lock_rescan_remove ( ) ;
2013-01-15 11:12:22 +08:00
list_for_each_entry_safe ( dev , temp , & parent - > devices , bus_list ) {
if ( PCI_SLOT ( dev - > devfn ) ! = p_slot - > device )
2005-10-13 12:05:41 -07:00
continue ;
2013-01-15 11:12:22 +08:00
pci_dev_get ( dev ) ;
pci_stop_and_remove_bus_device ( dev ) ;
pci_dev_put ( dev ) ;
2005-04-16 15:20:36 -07:00
}
2014-01-14 12:03:14 -07:00
pci_unlock_rescan_remove ( ) ;
2005-04-16 15:20:36 -07:00
}