2005-04-17 02:20:36 +04: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-31 02:03:48 +03:00
# include <linux/string.h>
# include <linux/slab.h>
2005-04-17 02:20:36 +04: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 ) ;
2008-10-21 03:41:43 +04:00
kfree ( slot - > name ) ;
2005-04-17 02:20:36 +04:00
kfree ( slot - > hotplug_slot ) ;
kfree ( slot ) ;
}
2007-04-14 02:34:10 +04:00
struct slot * alloc_slot_struct ( struct device_node * dn ,
int drc_index , char * drc_name , int power_domain )
2005-04-17 02:20:36 +04:00
{
struct slot * slot ;
2006-02-28 17:34:49 +03:00
slot = kzalloc ( sizeof ( struct slot ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! slot )
goto error_nomem ;
2006-02-28 17:34:49 +03:00
slot - > hotplug_slot = kzalloc ( sizeof ( struct hotplug_slot ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! slot - > hotplug_slot )
goto error_slot ;
2006-02-28 17:34:49 +03:00
slot - > hotplug_slot - > info = kzalloc ( sizeof ( struct hotplug_slot_info ) ,
2005-04-17 02:20:36 +04:00
GFP_KERNEL ) ;
if ( ! slot - > hotplug_slot - > info )
goto error_hpslot ;
2008-10-21 03:41:43 +04:00
slot - > name = kstrdup ( drc_name , GFP_KERNEL ) ;
if ( ! slot - > name )
2005-04-17 02:20:36 +04:00
goto error_info ;
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-14 02:34:10 +04:00
struct slot * tmp_slot ;
2005-04-17 02:20:36 +04: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-13 03:31:01 +03:00
int rpaphp_deregister_slot ( struct slot * slot )
2005-04-17 02:20:36 +04:00
{
int retval = 0 ;
struct hotplug_slot * php_slot = slot - > hotplug_slot ;
dbg ( " %s - Entry: deregistering slot=%s \n " ,
2008-03-04 06:09:46 +03:00
__func__ , slot - > name ) ;
2005-04-17 02:20:36 +04: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-04 06:09:46 +03:00
dbg ( " %s - Exit: rc[%d] \n " , __func__ , retval ) ;
2005-04-17 02:20:36 +04:00
return retval ;
}
2006-02-02 03:21:09 +03:00
EXPORT_SYMBOL_GPL ( rpaphp_deregister_slot ) ;
2005-04-17 02:20:36 +04:00
2006-01-13 03:31:01 +03:00
int rpaphp_register_slot ( struct slot * slot )
2005-04-17 02:20:36 +04:00
{
2006-12-02 03:31:27 +03:00
struct hotplug_slot * php_slot = slot - > hotplug_slot ;
2005-04-17 02:20:36 +04:00
int retval ;
2008-06-11 01:28:50 +04:00
int slotno ;
2005-04-17 02:20:36 +04:00
dbg ( " %s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d] \n " ,
2008-03-04 06:09:46 +03:00
__func__ , slot - > dn - > full_name , slot - > index , slot - > name ,
2005-04-17 02:20:36 +04:00
slot - > power_domain , slot - > type ) ;
2006-12-02 03:31:27 +03:00
2005-04-17 02:20:36 +04:00
/* should not try to register the same slot twice */
2006-12-02 03:31:27 +03:00
if ( is_registered ( slot ) ) {
2006-01-13 03:31:01 +03:00
err ( " rpaphp_register_slot: slot[%s] is already registered \n " , slot - > name ) ;
2007-04-14 02:34:11 +04:00
return - EAGAIN ;
2005-04-17 02:20:36 +04:00
}
2006-12-02 03:31:27 +03:00
2008-06-11 01:28:50 +04:00
if ( slot - > dn - > child )
slotno = PCI_SLOT ( PCI_DN ( slot - > dn - > child ) - > devfn ) ;
else
slotno = - 1 ;
2008-10-21 03:40:42 +04:00
retval = pci_hp_register ( php_slot , slot - > bus , slotno , slot - > name ) ;
2005-04-17 02:20:36 +04:00
if ( retval ) {
err ( " pci_hp_register failed with error %d \n " , retval ) ;
2007-04-14 02:34:11 +04:00
return retval ;
2005-04-17 02:20:36 +04:00
}
2006-12-02 03:31:27 +03:00
/* add slot to our internal list */
2005-04-17 02:20:36 +04:00
list_add ( & slot - > rpaphp_slot_list , & rpaphp_slot_head ) ;
2007-11-26 10:51:37 +03:00
info ( " Slot [%s] registered \n " , slot - > name ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}