2005-04-16 15:20:36 -07:00
/*
* RPA Virtual I / O device functions
* Copyright ( C ) 2004 Linda Xie < lxie @ us . ibm . com >
*
* 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 .
*
* Send feedback to < lxie @ us . ibm . com >
*
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/kobject.h>
# include <linux/sysfs.h>
# include <linux/pci.h>
2005-10-30 15:03:48 -08:00
# include <linux/string.h>
# include <linux/slab.h>
2005-04-16 15:20:36 -07:00
# include <asm/rtas.h>
# include "rpaphp.h"
/* free up the memory used by a slot */
static void rpaphp_release_slot ( struct hotplug_slot * hotplug_slot )
{
struct slot * slot = ( struct slot * ) hotplug_slot - > private ;
dealloc_slot_struct ( slot ) ;
}
void dealloc_slot_struct ( struct slot * slot )
{
kfree ( slot - > hotplug_slot - > info ) ;
kfree ( slot - > hotplug_slot - > name ) ;
kfree ( slot - > hotplug_slot ) ;
kfree ( slot ) ;
}
2007-04-13 15:34:10 -07:00
struct slot * alloc_slot_struct ( struct device_node * dn ,
int drc_index , char * drc_name , int power_domain )
2005-04-16 15:20:36 -07:00
{
struct slot * slot ;
2006-02-28 15:34:49 +01:00
slot = kzalloc ( sizeof ( struct slot ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! slot )
goto error_nomem ;
2006-02-28 15:34:49 +01:00
slot - > hotplug_slot = kzalloc ( sizeof ( struct hotplug_slot ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! slot - > hotplug_slot )
goto error_slot ;
2006-02-28 15:34:49 +01:00
slot - > hotplug_slot - > info = kzalloc ( sizeof ( struct hotplug_slot_info ) ,
2005-04-16 15:20:36 -07:00
GFP_KERNEL ) ;
if ( ! slot - > hotplug_slot - > info )
goto error_hpslot ;
2007-11-25 23:51:37 -08:00
slot - > hotplug_slot - > name = kmalloc ( strlen ( drc_name ) + 1 , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! slot - > hotplug_slot - > name )
goto error_info ;
slot - > name = slot - > hotplug_slot - > name ;
2007-11-25 23:51:37 -08:00
strcpy ( slot - > name , drc_name ) ;
2005-04-16 15:20:36 -07:00
slot - > dn = dn ;
slot - > index = drc_index ;
slot - > power_domain = power_domain ;
slot - > hotplug_slot - > private = slot ;
slot - > hotplug_slot - > ops = & rpaphp_hotplug_slot_ops ;
slot - > hotplug_slot - > release = & rpaphp_release_slot ;
return ( slot ) ;
error_info :
kfree ( slot - > hotplug_slot - > info ) ;
error_hpslot :
kfree ( slot - > hotplug_slot ) ;
error_slot :
kfree ( slot ) ;
error_nomem :
return NULL ;
}
static int is_registered ( struct slot * slot )
{
2007-04-13 15:34:10 -07:00
struct slot * tmp_slot ;
2005-04-16 15:20:36 -07:00
list_for_each_entry ( tmp_slot , & rpaphp_slot_head , rpaphp_slot_list ) {
if ( ! strcmp ( tmp_slot - > name , slot - > name ) )
return 1 ;
}
return 0 ;
}
2006-01-12 18:31:01 -06:00
int rpaphp_deregister_slot ( struct slot * slot )
2005-04-16 15:20:36 -07:00
{
int retval = 0 ;
struct hotplug_slot * php_slot = slot - > hotplug_slot ;
dbg ( " %s - Entry: deregistering slot=%s \n " ,
2008-03-03 19:09:46 -08:00
__func__ , slot - > name ) ;
2005-04-16 15:20:36 -07:00
list_del ( & slot - > rpaphp_slot_list ) ;
retval = pci_hp_deregister ( php_slot ) ;
if ( retval )
err ( " Problem unregistering a slot %s \n " , slot - > name ) ;
2008-03-03 19:09:46 -08:00
dbg ( " %s - Exit: rc[%d] \n " , __func__ , retval ) ;
2005-04-16 15:20:36 -07:00
return retval ;
}
2006-02-01 18:21:09 -06:00
EXPORT_SYMBOL_GPL ( rpaphp_deregister_slot ) ;
2005-04-16 15:20:36 -07:00
2006-01-12 18:31:01 -06:00
int rpaphp_register_slot ( struct slot * slot )
2005-04-16 15:20:36 -07:00
{
2006-12-01 16:31:27 -08:00
struct hotplug_slot * php_slot = slot - > hotplug_slot ;
2005-04-16 15:20:36 -07:00
int retval ;
2008-06-10 15:28:50 -06:00
int slotno ;
2005-04-16 15:20:36 -07:00
dbg ( " %s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d] \n " ,
2008-03-03 19:09:46 -08:00
__func__ , slot - > dn - > full_name , slot - > index , slot - > name ,
2005-04-16 15:20:36 -07:00
slot - > power_domain , slot - > type ) ;
2006-12-01 16:31:27 -08:00
2005-04-16 15:20:36 -07:00
/* should not try to register the same slot twice */
2006-12-01 16:31:27 -08:00
if ( is_registered ( slot ) ) {
2006-01-12 18:31:01 -06:00
err ( " rpaphp_register_slot: slot[%s] is already registered \n " , slot - > name ) ;
2007-04-13 15:34:11 -07:00
return - EAGAIN ;
2005-04-16 15:20:36 -07:00
}
2006-12-01 16:31:27 -08:00
2008-06-10 15:28:50 -06:00
if ( slot - > dn - > child )
slotno = PCI_SLOT ( PCI_DN ( slot - > dn - > child ) - > devfn ) ;
else
slotno = - 1 ;
retval = pci_hp_register ( php_slot , slot - > bus , slotno ) ;
2005-04-16 15:20:36 -07:00
if ( retval ) {
err ( " pci_hp_register failed with error %d \n " , retval ) ;
2007-04-13 15:34:11 -07:00
return retval ;
2005-04-16 15:20:36 -07:00
}
2006-12-01 16:31:27 -08:00
/* add slot to our internal list */
2005-04-16 15:20:36 -07:00
list_add ( & slot - > rpaphp_slot_list , & rpaphp_slot_head ) ;
2007-11-25 23:51:37 -08:00
info ( " Slot [%s] registered \n " , slot - > name ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
2006-12-01 16:31:27 -08:00
sysfs_fail :
pci_hp_deregister ( php_slot ) ;
return retval ;
2005-04-16 15:20:36 -07:00
}