2005-04-16 15:20:36 -07:00
/*
* IBM Hot Plug Controller Driver
*
* Written By : Tong Yu , IBM Corporation
*
* Copyright ( C ) 2001 , 2003 Greg Kroah - Hartman ( greg @ kroah . com )
* Copyright ( C ) 2001 - 2003 IBM Corp .
*
* 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 < gregkh @ us . ibm . com >
*
*/
# include <linux/module.h>
# include <linux/errno.h>
# include <linux/mm.h>
# include <linux/slab.h>
# include <linux/pci.h>
# include <linux/list.h>
# include <linux/init.h>
# include "ibmphp.h"
/*
* POST builds data blocks ( in this data block definition , a char - 1
* byte , short ( or word ) - 2 byte , long ( dword ) - 4 byte ) in the Extended
* BIOS Data Area which describe the configuration of the hot - plug
* controllers and resources used by the PCI Hot - Plug devices .
*
* This file walks EBDA , maps data block from physical addr ,
* reconstruct linked lists about all system resource ( MEM , PFM , IO )
* already assigned by POST , as well as linked lists about hot plug
* controllers ( ctlr # , slot # , bus & slot features . . . )
*/
/* Global lists */
LIST_HEAD ( ibmphp_ebda_pci_rsrc_head ) ;
LIST_HEAD ( ibmphp_slot_head ) ;
/* Local variables */
static struct ebda_hpc_list * hpc_list_ptr ;
static struct ebda_rsrc_list * rsrc_list_ptr ;
static struct rio_table_hdr * rio_table_ptr = NULL ;
static LIST_HEAD ( ebda_hpc_head ) ;
static LIST_HEAD ( bus_info_head ) ;
static LIST_HEAD ( rio_vg_head ) ;
static LIST_HEAD ( rio_lo_head ) ;
static LIST_HEAD ( opt_vg_head ) ;
static LIST_HEAD ( opt_lo_head ) ;
static void __iomem * io_mem ;
/* Local functions */
static int ebda_rsrc_controller ( void ) ;
static int ebda_rsrc_rsrc ( void ) ;
static int ebda_rio_table ( void ) ;
static struct ebda_hpc_list * __init alloc_ebda_hpc_list ( void )
{
2006-02-28 15:34:49 +01:00
return kzalloc ( sizeof ( struct ebda_hpc_list ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
}
static struct controller * alloc_ebda_hpc ( u32 slot_count , u32 bus_count )
{
struct controller * controller ;
struct ebda_hpc_slot * slots ;
struct ebda_hpc_bus * buses ;
2006-02-28 15:34:49 +01:00
controller = kzalloc ( sizeof ( struct controller ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! controller )
goto error ;
2006-02-28 15:34:49 +01:00
slots = kcalloc ( slot_count , sizeof ( struct ebda_hpc_slot ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! slots )
goto error_contr ;
controller - > slots = slots ;
2006-02-28 15:34:49 +01:00
buses = kcalloc ( bus_count , sizeof ( struct ebda_hpc_bus ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! buses )
goto error_slots ;
controller - > buses = buses ;
return controller ;
error_slots :
kfree ( controller - > slots ) ;
error_contr :
kfree ( controller ) ;
error :
return NULL ;
}
static void free_ebda_hpc ( struct controller * controller )
{
kfree ( controller - > slots ) ;
kfree ( controller - > buses ) ;
kfree ( controller ) ;
}
static struct ebda_rsrc_list * __init alloc_ebda_rsrc_list ( void )
{
2006-02-28 15:34:49 +01:00
return kzalloc ( sizeof ( struct ebda_rsrc_list ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
}
static struct ebda_pci_rsrc * alloc_ebda_pci_rsrc ( void )
{
2006-02-28 15:34:49 +01:00
return kzalloc ( sizeof ( struct ebda_pci_rsrc ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
}
static void __init print_bus_info ( void )
{
struct bus_info * ptr ;
struct list_head * ptr1 ;
list_for_each ( ptr1 , & bus_info_head ) {
ptr = list_entry ( ptr1 , struct bus_info , bus_info_list ) ;
debug ( " %s - slot_min = %x \n " , __FUNCTION__ , ptr - > slot_min ) ;
debug ( " %s - slot_max = %x \n " , __FUNCTION__ , ptr - > slot_max ) ;
debug ( " %s - slot_count = %x \n " , __FUNCTION__ , ptr - > slot_count ) ;
debug ( " %s - bus# = %x \n " , __FUNCTION__ , ptr - > busno ) ;
debug ( " %s - current_speed = %x \n " , __FUNCTION__ , ptr - > current_speed ) ;
debug ( " %s - controller_id = %x \n " , __FUNCTION__ , ptr - > controller_id ) ;
debug ( " %s - slots_at_33_conv = %x \n " , __FUNCTION__ , ptr - > slots_at_33_conv ) ;
debug ( " %s - slots_at_66_conv = %x \n " , __FUNCTION__ , ptr - > slots_at_66_conv ) ;
debug ( " %s - slots_at_66_pcix = %x \n " , __FUNCTION__ , ptr - > slots_at_66_pcix ) ;
debug ( " %s - slots_at_100_pcix = %x \n " , __FUNCTION__ , ptr - > slots_at_100_pcix ) ;
debug ( " %s - slots_at_133_pcix = %x \n " , __FUNCTION__ , ptr - > slots_at_133_pcix ) ;
}
}
static void print_lo_info ( void )
{
struct rio_detail * ptr ;
struct list_head * ptr1 ;
debug ( " print_lo_info ---- \n " ) ;
list_for_each ( ptr1 , & rio_lo_head ) {
ptr = list_entry ( ptr1 , struct rio_detail , rio_detail_list ) ;
debug ( " %s - rio_node_id = %x \n " , __FUNCTION__ , ptr - > rio_node_id ) ;
debug ( " %s - rio_type = %x \n " , __FUNCTION__ , ptr - > rio_type ) ;
debug ( " %s - owner_id = %x \n " , __FUNCTION__ , ptr - > owner_id ) ;
debug ( " %s - first_slot_num = %x \n " , __FUNCTION__ , ptr - > first_slot_num ) ;
debug ( " %s - wpindex = %x \n " , __FUNCTION__ , ptr - > wpindex ) ;
debug ( " %s - chassis_num = %x \n " , __FUNCTION__ , ptr - > chassis_num ) ;
}
}
static void print_vg_info ( void )
{
struct rio_detail * ptr ;
struct list_head * ptr1 ;
debug ( " %s --- \n " , __FUNCTION__ ) ;
list_for_each ( ptr1 , & rio_vg_head ) {
ptr = list_entry ( ptr1 , struct rio_detail , rio_detail_list ) ;
debug ( " %s - rio_node_id = %x \n " , __FUNCTION__ , ptr - > rio_node_id ) ;
debug ( " %s - rio_type = %x \n " , __FUNCTION__ , ptr - > rio_type ) ;
debug ( " %s - owner_id = %x \n " , __FUNCTION__ , ptr - > owner_id ) ;
debug ( " %s - first_slot_num = %x \n " , __FUNCTION__ , ptr - > first_slot_num ) ;
debug ( " %s - wpindex = %x \n " , __FUNCTION__ , ptr - > wpindex ) ;
debug ( " %s - chassis_num = %x \n " , __FUNCTION__ , ptr - > chassis_num ) ;
}
}
static void __init print_ebda_pci_rsrc ( void )
{
struct ebda_pci_rsrc * ptr ;
struct list_head * ptr1 ;
list_for_each ( ptr1 , & ibmphp_ebda_pci_rsrc_head ) {
ptr = list_entry ( ptr1 , struct ebda_pci_rsrc , ebda_pci_rsrc_list ) ;
debug ( " %s - rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x \n " ,
__FUNCTION__ , ptr - > rsrc_type , ptr - > bus_num , ptr - > dev_fun , ptr - > start_addr , ptr - > end_addr ) ;
}
}
static void __init print_ibm_slot ( void )
{
struct slot * ptr ;
struct list_head * ptr1 ;
list_for_each ( ptr1 , & ibmphp_slot_head ) {
ptr = list_entry ( ptr1 , struct slot , ibm_slot_list ) ;
debug ( " %s - slot_number: %x \n " , __FUNCTION__ , ptr - > number ) ;
}
}
static void __init print_opt_vg ( void )
{
struct opt_rio * ptr ;
struct list_head * ptr1 ;
debug ( " %s --- \n " , __FUNCTION__ ) ;
list_for_each ( ptr1 , & opt_vg_head ) {
ptr = list_entry ( ptr1 , struct opt_rio , opt_rio_list ) ;
debug ( " %s - rio_type %x \n " , __FUNCTION__ , ptr - > rio_type ) ;
debug ( " %s - chassis_num: %x \n " , __FUNCTION__ , ptr - > chassis_num ) ;
debug ( " %s - first_slot_num: %x \n " , __FUNCTION__ , ptr - > first_slot_num ) ;
debug ( " %s - middle_num: %x \n " , __FUNCTION__ , ptr - > middle_num ) ;
}
}
static void __init print_ebda_hpc ( void )
{
struct controller * hpc_ptr ;
struct list_head * ptr1 ;
u16 index ;
list_for_each ( ptr1 , & ebda_hpc_head ) {
hpc_ptr = list_entry ( ptr1 , struct controller , ebda_hpc_list ) ;
for ( index = 0 ; index < hpc_ptr - > slot_count ; index + + ) {
debug ( " %s - physical slot#: %x \n " , __FUNCTION__ , hpc_ptr - > slots [ index ] . slot_num ) ;
debug ( " %s - pci bus# of the slot: %x \n " , __FUNCTION__ , hpc_ptr - > slots [ index ] . slot_bus_num ) ;
debug ( " %s - index into ctlr addr: %x \n " , __FUNCTION__ , hpc_ptr - > slots [ index ] . ctl_index ) ;
debug ( " %s - cap of the slot: %x \n " , __FUNCTION__ , hpc_ptr - > slots [ index ] . slot_cap ) ;
}
for ( index = 0 ; index < hpc_ptr - > bus_count ; index + + ) {
debug ( " %s - bus# of each bus controlled by this ctlr: %x \n " , __FUNCTION__ , hpc_ptr - > buses [ index ] . bus_num ) ;
}
debug ( " %s - type of hpc: %x \n " , __FUNCTION__ , hpc_ptr - > ctlr_type ) ;
switch ( hpc_ptr - > ctlr_type ) {
case 1 :
debug ( " %s - bus: %x \n " , __FUNCTION__ , hpc_ptr - > u . pci_ctlr . bus ) ;
debug ( " %s - dev_fun: %x \n " , __FUNCTION__ , hpc_ptr - > u . pci_ctlr . dev_fun ) ;
debug ( " %s - irq: %x \n " , __FUNCTION__ , hpc_ptr - > irq ) ;
break ;
case 0 :
debug ( " %s - io_start: %x \n " , __FUNCTION__ , hpc_ptr - > u . isa_ctlr . io_start ) ;
debug ( " %s - io_end: %x \n " , __FUNCTION__ , hpc_ptr - > u . isa_ctlr . io_end ) ;
debug ( " %s - irq: %x \n " , __FUNCTION__ , hpc_ptr - > irq ) ;
break ;
case 2 :
case 4 :
debug ( " %s - wpegbbar: %lx \n " , __FUNCTION__ , hpc_ptr - > u . wpeg_ctlr . wpegbbar ) ;
debug ( " %s - i2c_addr: %x \n " , __FUNCTION__ , hpc_ptr - > u . wpeg_ctlr . i2c_addr ) ;
debug ( " %s - irq: %x \n " , __FUNCTION__ , hpc_ptr - > irq ) ;
break ;
}
}
}
int __init ibmphp_access_ebda ( void )
{
u8 format , num_ctlrs , rio_complete , hs_complete ;
u16 ebda_seg , num_entries , next_offset , offset , blk_id , sub_addr , re , rc_id , re_id , base ;
int rc = 0 ;
rio_complete = 0 ;
hs_complete = 0 ;
io_mem = ioremap ( ( 0x40 < < 4 ) + 0x0e , 2 ) ;
if ( ! io_mem )
return - ENOMEM ;
ebda_seg = readw ( io_mem ) ;
iounmap ( io_mem ) ;
debug ( " returned ebda segment: %x \n " , ebda_seg ) ;
io_mem = ioremap ( ebda_seg < < 4 , 65000 ) ;
if ( ! io_mem )
return - ENOMEM ;
next_offset = 0x180 ;
for ( ; ; ) {
offset = next_offset ;
next_offset = readw ( io_mem + offset ) ; /* offset of next blk */
offset + = 2 ;
if ( next_offset = = 0 ) /* 0 indicate it's last blk */
break ;
blk_id = readw ( io_mem + offset ) ; /* this blk id */
offset + = 2 ;
/* check if it is hot swap block or rio block */
if ( blk_id ! = 0x4853 & & blk_id ! = 0x4752 )
continue ;
/* found hs table */
if ( blk_id = = 0x4853 ) {
debug ( " now enter hot swap block--- \n " ) ;
debug ( " hot blk id: %x \n " , blk_id ) ;
format = readb ( io_mem + offset ) ;
offset + = 1 ;
if ( format ! = 4 )
goto error_nodev ;
debug ( " hot blk format: %x \n " , format ) ;
/* hot swap sub blk */
base = offset ;
sub_addr = base ;
re = readw ( io_mem + sub_addr ) ; /* next sub blk */
sub_addr + = 2 ;
rc_id = readw ( io_mem + sub_addr ) ; /* sub blk id */
sub_addr + = 2 ;
if ( rc_id ! = 0x5243 )
goto error_nodev ;
/* rc sub blk signature */
num_ctlrs = readb ( io_mem + sub_addr ) ;
sub_addr + = 1 ;
hpc_list_ptr = alloc_ebda_hpc_list ( ) ;
if ( ! hpc_list_ptr ) {
rc = - ENOMEM ;
goto out ;
}
hpc_list_ptr - > format = format ;
hpc_list_ptr - > num_ctlrs = num_ctlrs ;
hpc_list_ptr - > phys_addr = sub_addr ; /* offset of RSRC_CONTROLLER blk */
debug ( " info about hpc descriptor--- \n " ) ;
debug ( " hot blk format: %x \n " , format ) ;
debug ( " num of controller: %x \n " , num_ctlrs ) ;
debug ( " offset of hpc data structure enteries: %x \n " , sub_addr ) ;
sub_addr = base + re ; /* re sub blk */
/* FIXME: rc is never used/checked */
rc = readw ( io_mem + sub_addr ) ; /* next sub blk */
sub_addr + = 2 ;
re_id = readw ( io_mem + sub_addr ) ; /* sub blk id */
sub_addr + = 2 ;
if ( re_id ! = 0x5245 )
goto error_nodev ;
/* signature of re */
num_entries = readw ( io_mem + sub_addr ) ;
sub_addr + = 2 ; /* offset of RSRC_ENTRIES blk */
rsrc_list_ptr = alloc_ebda_rsrc_list ( ) ;
if ( ! rsrc_list_ptr ) {
rc = - ENOMEM ;
goto out ;
}
rsrc_list_ptr - > format = format ;
rsrc_list_ptr - > num_entries = num_entries ;
rsrc_list_ptr - > phys_addr = sub_addr ;
debug ( " info about rsrc descriptor--- \n " ) ;
debug ( " format: %x \n " , format ) ;
debug ( " num of rsrc: %x \n " , num_entries ) ;
debug ( " offset of rsrc data structure enteries: %x \n " , sub_addr ) ;
hs_complete = 1 ;
} else {
/* found rio table, blk_id == 0x4752 */
debug ( " now enter io table --- \n " ) ;
debug ( " rio blk id: %x \n " , blk_id ) ;
2006-02-28 15:34:49 +01:00
rio_table_ptr = kzalloc ( sizeof ( struct rio_table_hdr ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! rio_table_ptr )
return - ENOMEM ;
rio_table_ptr - > ver_num = readb ( io_mem + offset ) ;
rio_table_ptr - > scal_count = readb ( io_mem + offset + 1 ) ;
rio_table_ptr - > riodev_count = readb ( io_mem + offset + 2 ) ;
rio_table_ptr - > offset = offset + 3 ;
debug ( " info about rio table hdr --- \n " ) ;
debug ( " ver_num: %x \n scal_count: %x \n riodev_count: %x \n offset of rio table: %x \n " ,
rio_table_ptr - > ver_num , rio_table_ptr - > scal_count ,
rio_table_ptr - > riodev_count , rio_table_ptr - > offset ) ;
rio_complete = 1 ;
}
}
if ( ! hs_complete & & ! rio_complete )
goto error_nodev ;
if ( rio_table_ptr ) {
if ( rio_complete & & rio_table_ptr - > ver_num = = 3 ) {
rc = ebda_rio_table ( ) ;
if ( rc )
goto out ;
}
}
rc = ebda_rsrc_controller ( ) ;
if ( rc )
goto out ;
rc = ebda_rsrc_rsrc ( ) ;
goto out ;
error_nodev :
rc = - ENODEV ;
out :
iounmap ( io_mem ) ;
return rc ;
}
/*
* map info of scalability details and rio details from physical address
*/
static int __init ebda_rio_table ( void )
{
u16 offset ;
u8 i ;
struct rio_detail * rio_detail_ptr ;
offset = rio_table_ptr - > offset ;
offset + = 12 * rio_table_ptr - > scal_count ;
// we do concern about rio details
for ( i = 0 ; i < rio_table_ptr - > riodev_count ; i + + ) {
2006-02-28 15:34:49 +01:00
rio_detail_ptr = kzalloc ( sizeof ( struct rio_detail ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! rio_detail_ptr )
return - ENOMEM ;
rio_detail_ptr - > rio_node_id = readb ( io_mem + offset ) ;
rio_detail_ptr - > bbar = readl ( io_mem + offset + 1 ) ;
rio_detail_ptr - > rio_type = readb ( io_mem + offset + 5 ) ;
rio_detail_ptr - > owner_id = readb ( io_mem + offset + 6 ) ;
rio_detail_ptr - > port0_node_connect = readb ( io_mem + offset + 7 ) ;
rio_detail_ptr - > port0_port_connect = readb ( io_mem + offset + 8 ) ;
rio_detail_ptr - > port1_node_connect = readb ( io_mem + offset + 9 ) ;
rio_detail_ptr - > port1_port_connect = readb ( io_mem + offset + 10 ) ;
rio_detail_ptr - > first_slot_num = readb ( io_mem + offset + 11 ) ;
rio_detail_ptr - > status = readb ( io_mem + offset + 12 ) ;
rio_detail_ptr - > wpindex = readb ( io_mem + offset + 13 ) ;
rio_detail_ptr - > chassis_num = readb ( io_mem + offset + 14 ) ;
// debug ("rio_node_id: %x\nbbar: %x\nrio_type: %x\nowner_id: %x\nport0_node: %x\nport0_port: %x\nport1_node: %x\nport1_port: %x\nfirst_slot_num: %x\nstatus: %x\n", rio_detail_ptr->rio_node_id, rio_detail_ptr->bbar, rio_detail_ptr->rio_type, rio_detail_ptr->owner_id, rio_detail_ptr->port0_node_connect, rio_detail_ptr->port0_port_connect, rio_detail_ptr->port1_node_connect, rio_detail_ptr->port1_port_connect, rio_detail_ptr->first_slot_num, rio_detail_ptr->status);
//create linked list of chassis
if ( rio_detail_ptr - > rio_type = = 4 | | rio_detail_ptr - > rio_type = = 5 )
list_add ( & rio_detail_ptr - > rio_detail_list , & rio_vg_head ) ;
//create linked list of expansion box
else if ( rio_detail_ptr - > rio_type = = 6 | | rio_detail_ptr - > rio_type = = 7 )
list_add ( & rio_detail_ptr - > rio_detail_list , & rio_lo_head ) ;
else
// not in my concern
kfree ( rio_detail_ptr ) ;
offset + = 15 ;
}
print_lo_info ( ) ;
print_vg_info ( ) ;
return 0 ;
}
/*
* reorganizing linked list of chassis
*/
static struct opt_rio * search_opt_vg ( u8 chassis_num )
{
struct opt_rio * ptr ;
struct list_head * ptr1 ;
list_for_each ( ptr1 , & opt_vg_head ) {
ptr = list_entry ( ptr1 , struct opt_rio , opt_rio_list ) ;
if ( ptr - > chassis_num = = chassis_num )
return ptr ;
}
return NULL ;
}
static int __init combine_wpg_for_chassis ( void )
{
struct opt_rio * opt_rio_ptr = NULL ;
struct rio_detail * rio_detail_ptr = NULL ;
struct list_head * list_head_ptr = NULL ;
list_for_each ( list_head_ptr , & rio_vg_head ) {
rio_detail_ptr = list_entry ( list_head_ptr , struct rio_detail , rio_detail_list ) ;
opt_rio_ptr = search_opt_vg ( rio_detail_ptr - > chassis_num ) ;
if ( ! opt_rio_ptr ) {
2006-02-28 15:34:49 +01:00
opt_rio_ptr = kzalloc ( sizeof ( struct opt_rio ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! opt_rio_ptr )
return - ENOMEM ;
opt_rio_ptr - > rio_type = rio_detail_ptr - > rio_type ;
opt_rio_ptr - > chassis_num = rio_detail_ptr - > chassis_num ;
opt_rio_ptr - > first_slot_num = rio_detail_ptr - > first_slot_num ;
opt_rio_ptr - > middle_num = rio_detail_ptr - > first_slot_num ;
list_add ( & opt_rio_ptr - > opt_rio_list , & opt_vg_head ) ;
} else {
opt_rio_ptr - > first_slot_num = min ( opt_rio_ptr - > first_slot_num , rio_detail_ptr - > first_slot_num ) ;
opt_rio_ptr - > middle_num = max ( opt_rio_ptr - > middle_num , rio_detail_ptr - > first_slot_num ) ;
}
}
print_opt_vg ( ) ;
return 0 ;
}
/*
* reorgnizing linked list of expansion box
*/
static struct opt_rio_lo * search_opt_lo ( u8 chassis_num )
{
struct opt_rio_lo * ptr ;
struct list_head * ptr1 ;
list_for_each ( ptr1 , & opt_lo_head ) {
ptr = list_entry ( ptr1 , struct opt_rio_lo , opt_rio_lo_list ) ;
if ( ptr - > chassis_num = = chassis_num )
return ptr ;
}
return NULL ;
}
static int combine_wpg_for_expansion ( void )
{
struct opt_rio_lo * opt_rio_lo_ptr = NULL ;
struct rio_detail * rio_detail_ptr = NULL ;
struct list_head * list_head_ptr = NULL ;
list_for_each ( list_head_ptr , & rio_lo_head ) {
rio_detail_ptr = list_entry ( list_head_ptr , struct rio_detail , rio_detail_list ) ;
opt_rio_lo_ptr = search_opt_lo ( rio_detail_ptr - > chassis_num ) ;
if ( ! opt_rio_lo_ptr ) {
2006-02-28 15:34:49 +01:00
opt_rio_lo_ptr = kzalloc ( sizeof ( struct opt_rio_lo ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! opt_rio_lo_ptr )
return - ENOMEM ;
opt_rio_lo_ptr - > rio_type = rio_detail_ptr - > rio_type ;
opt_rio_lo_ptr - > chassis_num = rio_detail_ptr - > chassis_num ;
opt_rio_lo_ptr - > first_slot_num = rio_detail_ptr - > first_slot_num ;
opt_rio_lo_ptr - > middle_num = rio_detail_ptr - > first_slot_num ;
opt_rio_lo_ptr - > pack_count = 1 ;
list_add ( & opt_rio_lo_ptr - > opt_rio_lo_list , & opt_lo_head ) ;
} else {
opt_rio_lo_ptr - > first_slot_num = min ( opt_rio_lo_ptr - > first_slot_num , rio_detail_ptr - > first_slot_num ) ;
opt_rio_lo_ptr - > middle_num = max ( opt_rio_lo_ptr - > middle_num , rio_detail_ptr - > first_slot_num ) ;
opt_rio_lo_ptr - > pack_count = 2 ;
}
}
return 0 ;
}
/* Since we don't know the max slot number per each chassis, hence go
* through the list of all chassis to find out the range
* Arguments : slot_num , 1 st slot number of the chassis we think we are on ,
* var ( 0 = chassis , 1 = expansion box )
*/
static int first_slot_num ( u8 slot_num , u8 first_slot , u8 var )
{
struct opt_rio * opt_vg_ptr = NULL ;
struct opt_rio_lo * opt_lo_ptr = NULL ;
struct list_head * ptr = NULL ;
int rc = 0 ;
if ( ! var ) {
list_for_each ( ptr , & opt_vg_head ) {
opt_vg_ptr = list_entry ( ptr , struct opt_rio , opt_rio_list ) ;
if ( ( first_slot < opt_vg_ptr - > first_slot_num ) & & ( slot_num > = opt_vg_ptr - > first_slot_num ) ) {
rc = - ENODEV ;
break ;
}
}
} else {
list_for_each ( ptr , & opt_lo_head ) {
opt_lo_ptr = list_entry ( ptr , struct opt_rio_lo , opt_rio_lo_list ) ;
if ( ( first_slot < opt_lo_ptr - > first_slot_num ) & & ( slot_num > = opt_lo_ptr - > first_slot_num ) ) {
rc = - ENODEV ;
break ;
}
}
}
return rc ;
}
static struct opt_rio_lo * find_rxe_num ( u8 slot_num )
{
struct opt_rio_lo * opt_lo_ptr ;
struct list_head * ptr ;
list_for_each ( ptr , & opt_lo_head ) {
opt_lo_ptr = list_entry ( ptr , struct opt_rio_lo , opt_rio_lo_list ) ;
//check to see if this slot_num belongs to expansion box
if ( ( slot_num > = opt_lo_ptr - > first_slot_num ) & & ( ! first_slot_num ( slot_num , opt_lo_ptr - > first_slot_num , 1 ) ) )
return opt_lo_ptr ;
}
return NULL ;
}
static struct opt_rio * find_chassis_num ( u8 slot_num )
{
struct opt_rio * opt_vg_ptr ;
struct list_head * ptr ;
list_for_each ( ptr , & opt_vg_head ) {
opt_vg_ptr = list_entry ( ptr , struct opt_rio , opt_rio_list ) ;
//check to see if this slot_num belongs to chassis
if ( ( slot_num > = opt_vg_ptr - > first_slot_num ) & & ( ! first_slot_num ( slot_num , opt_vg_ptr - > first_slot_num , 0 ) ) )
return opt_vg_ptr ;
}
return NULL ;
}
/* This routine will find out how many slots are in the chassis, so that
* the slot numbers for rxe100 would start from 1 , and not from 7 , or 6 etc
*/
static u8 calculate_first_slot ( u8 slot_num )
{
u8 first_slot = 1 ;
struct list_head * list ;
struct slot * slot_cur ;
list_for_each ( list , & ibmphp_slot_head ) {
slot_cur = list_entry ( list , struct slot , ibm_slot_list ) ;
if ( slot_cur - > ctrl ) {
if ( ( slot_cur - > ctrl - > ctlr_type ! = 4 ) & & ( slot_cur - > ctrl - > ending_slot_num > first_slot ) & & ( slot_num > slot_cur - > ctrl - > ending_slot_num ) )
first_slot = slot_cur - > ctrl - > ending_slot_num ;
}
}
return first_slot + 1 ;
}
static char * create_file_name ( struct slot * slot_cur )
{
struct opt_rio * opt_vg_ptr = NULL ;
struct opt_rio_lo * opt_lo_ptr = NULL ;
static char str [ 30 ] ;
int which = 0 ; /* rxe = 1, chassis = 0 */
u8 number = 1 ; /* either chassis or rxe # */
u8 first_slot = 1 ;
u8 slot_num ;
u8 flag = 0 ;
if ( ! slot_cur ) {
err ( " Structure passed is empty \n " ) ;
return NULL ;
}
slot_num = slot_cur - > number ;
memset ( str , 0 , sizeof ( str ) ) ;
if ( rio_table_ptr ) {
if ( rio_table_ptr - > ver_num = = 3 ) {
opt_vg_ptr = find_chassis_num ( slot_num ) ;
opt_lo_ptr = find_rxe_num ( slot_num ) ;
}
}
if ( opt_vg_ptr ) {
if ( opt_lo_ptr ) {
if ( ( slot_num - opt_vg_ptr - > first_slot_num ) > ( slot_num - opt_lo_ptr - > first_slot_num ) ) {
number = opt_lo_ptr - > chassis_num ;
first_slot = opt_lo_ptr - > first_slot_num ;
which = 1 ; /* it is RXE */
} else {
first_slot = opt_vg_ptr - > first_slot_num ;
number = opt_vg_ptr - > chassis_num ;
which = 0 ;
}
} else {
first_slot = opt_vg_ptr - > first_slot_num ;
number = opt_vg_ptr - > chassis_num ;
which = 0 ;
}
+ + flag ;
} else if ( opt_lo_ptr ) {
number = opt_lo_ptr - > chassis_num ;
first_slot = opt_lo_ptr - > first_slot_num ;
which = 1 ;
+ + flag ;
} else if ( rio_table_ptr ) {
if ( rio_table_ptr - > ver_num = = 3 ) {
/* if both NULL and we DO have correct RIO table in BIOS */
return NULL ;
}
}
if ( ! flag ) {
if ( slot_cur - > ctrl - > ctlr_type = = 4 ) {
first_slot = calculate_first_slot ( slot_num ) ;
which = 1 ;
} else {
which = 0 ;
}
}
sprintf ( str , " %s%dslot%d " ,
which = = 0 ? " chassis " : " rxe " ,
number , slot_num - first_slot + 1 ) ;
return str ;
}
static int fillslotinfo ( struct hotplug_slot * hotplug_slot )
{
struct slot * slot ;
int rc = 0 ;
if ( ! hotplug_slot | | ! hotplug_slot - > private )
return - EINVAL ;
slot = hotplug_slot - > private ;
rc = ibmphp_hpc_readslot ( slot , READ_ALLSTAT , NULL ) ;
if ( rc )
return rc ;
// power - enabled:1 not:0
hotplug_slot - > info - > power_status = SLOT_POWER ( slot - > status ) ;
// attention - off:0, on:1, blinking:2
hotplug_slot - > info - > attention_status = SLOT_ATTN ( slot - > status , slot - > ext_status ) ;
// latch - open:1 closed:0
hotplug_slot - > info - > latch_status = SLOT_LATCH ( slot - > status ) ;
// pci board - present:1 not:0
if ( SLOT_PRESENT ( slot - > status ) )
hotplug_slot - > info - > adapter_status = 1 ;
else
hotplug_slot - > info - > adapter_status = 0 ;
/*
if ( slot - > bus_on - > supported_bus_mode
& & ( slot - > bus_on - > supported_speed = = BUS_SPEED_66 ) )
hotplug_slot - > info - > max_bus_speed_status = BUS_SPEED_66PCIX ;
else
hotplug_slot - > info - > max_bus_speed_status = slot - > bus_on - > supported_speed ;
*/
return rc ;
}
static void release_slot ( struct hotplug_slot * hotplug_slot )
{
struct slot * slot ;
if ( ! hotplug_slot | | ! hotplug_slot - > private )
return ;
slot = hotplug_slot - > private ;
kfree ( slot - > hotplug_slot - > info ) ;
kfree ( slot - > hotplug_slot - > name ) ;
kfree ( slot - > hotplug_slot ) ;
slot - > ctrl = NULL ;
slot - > bus_on = NULL ;
/* we don't want to actually remove the resources, since free_resources will do just that */
ibmphp_unconfigure_card ( & slot , - 1 ) ;
kfree ( slot ) ;
}
static struct pci_driver ibmphp_driver ;
/*
* map info ( ctlr - id , slot count , slot # . . bus count , bus # , ctlr type . . . ) of
* each hpc from physical address to a list of hot plug controllers based on
* hpc descriptors .
*/
static int __init ebda_rsrc_controller ( void )
{
u16 addr , addr_slot , addr_bus ;
u8 ctlr_id , temp , bus_index ;
u16 ctlr , slot , bus ;
u16 slot_num , bus_num , index ;
struct hotplug_slot * hp_slot_ptr ;
struct controller * hpc_ptr ;
struct ebda_hpc_bus * bus_ptr ;
struct ebda_hpc_slot * slot_ptr ;
struct bus_info * bus_info_ptr1 , * bus_info_ptr2 ;
int rc ;
struct slot * tmp_slot ;
struct list_head * list ;
addr = hpc_list_ptr - > phys_addr ;
for ( ctlr = 0 ; ctlr < hpc_list_ptr - > num_ctlrs ; ctlr + + ) {
bus_index = 1 ;
ctlr_id = readb ( io_mem + addr ) ;
addr + = 1 ;
slot_num = readb ( io_mem + addr ) ;
addr + = 1 ;
addr_slot = addr ; /* offset of slot structure */
addr + = ( slot_num * 4 ) ;
bus_num = readb ( io_mem + addr ) ;
addr + = 1 ;
addr_bus = addr ; /* offset of bus */
addr + = ( bus_num * 9 ) ; /* offset of ctlr_type */
temp = readb ( io_mem + addr ) ;
addr + = 1 ;
/* init hpc structure */
hpc_ptr = alloc_ebda_hpc ( slot_num , bus_num ) ;
if ( ! hpc_ptr ) {
rc = - ENOMEM ;
goto error_no_hpc ;
}
hpc_ptr - > ctlr_id = ctlr_id ;
hpc_ptr - > ctlr_relative_id = ctlr ;
hpc_ptr - > slot_count = slot_num ;
hpc_ptr - > bus_count = bus_num ;
debug ( " now enter ctlr data struture --- \n " ) ;
debug ( " ctlr id: %x \n " , ctlr_id ) ;
debug ( " ctlr_relative_id: %x \n " , hpc_ptr - > ctlr_relative_id ) ;
debug ( " count of slots controlled by this ctlr: %x \n " , slot_num ) ;
debug ( " count of buses controlled by this ctlr: %x \n " , bus_num ) ;
/* init slot structure, fetch slot, bus, cap... */
slot_ptr = hpc_ptr - > slots ;
for ( slot = 0 ; slot < slot_num ; slot + + ) {
slot_ptr - > slot_num = readb ( io_mem + addr_slot ) ;
slot_ptr - > slot_bus_num = readb ( io_mem + addr_slot + slot_num ) ;
slot_ptr - > ctl_index = readb ( io_mem + addr_slot + 2 * slot_num ) ;
slot_ptr - > slot_cap = readb ( io_mem + addr_slot + 3 * slot_num ) ;
// create bus_info lined list --- if only one slot per bus: slot_min = slot_max
bus_info_ptr2 = ibmphp_find_same_bus_num ( slot_ptr - > slot_bus_num ) ;
if ( ! bus_info_ptr2 ) {
2006-02-28 15:34:49 +01:00
bus_info_ptr1 = kzalloc ( sizeof ( struct bus_info ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! bus_info_ptr1 ) {
rc = - ENOMEM ;
goto error_no_hp_slot ;
}
bus_info_ptr1 - > slot_min = slot_ptr - > slot_num ;
bus_info_ptr1 - > slot_max = slot_ptr - > slot_num ;
bus_info_ptr1 - > slot_count + = 1 ;
bus_info_ptr1 - > busno = slot_ptr - > slot_bus_num ;
bus_info_ptr1 - > index = bus_index + + ;
bus_info_ptr1 - > current_speed = 0xff ;
bus_info_ptr1 - > current_bus_mode = 0xff ;
bus_info_ptr1 - > controller_id = hpc_ptr - > ctlr_id ;
list_add_tail ( & bus_info_ptr1 - > bus_info_list , & bus_info_head ) ;
} else {
bus_info_ptr2 - > slot_min = min ( bus_info_ptr2 - > slot_min , slot_ptr - > slot_num ) ;
bus_info_ptr2 - > slot_max = max ( bus_info_ptr2 - > slot_max , slot_ptr - > slot_num ) ;
bus_info_ptr2 - > slot_count + = 1 ;
}
// end of creating the bus_info linked list
slot_ptr + + ;
addr_slot + = 1 ;
}
/* init bus structure */
bus_ptr = hpc_ptr - > buses ;
for ( bus = 0 ; bus < bus_num ; bus + + ) {
bus_ptr - > bus_num = readb ( io_mem + addr_bus + bus ) ;
bus_ptr - > slots_at_33_conv = readb ( io_mem + addr_bus + bus_num + 8 * bus ) ;
bus_ptr - > slots_at_66_conv = readb ( io_mem + addr_bus + bus_num + 8 * bus + 1 ) ;
bus_ptr - > slots_at_66_pcix = readb ( io_mem + addr_bus + bus_num + 8 * bus + 2 ) ;
bus_ptr - > slots_at_100_pcix = readb ( io_mem + addr_bus + bus_num + 8 * bus + 3 ) ;
bus_ptr - > slots_at_133_pcix = readb ( io_mem + addr_bus + bus_num + 8 * bus + 4 ) ;
bus_info_ptr2 = ibmphp_find_same_bus_num ( bus_ptr - > bus_num ) ;
if ( bus_info_ptr2 ) {
bus_info_ptr2 - > slots_at_33_conv = bus_ptr - > slots_at_33_conv ;
bus_info_ptr2 - > slots_at_66_conv = bus_ptr - > slots_at_66_conv ;
bus_info_ptr2 - > slots_at_66_pcix = bus_ptr - > slots_at_66_pcix ;
bus_info_ptr2 - > slots_at_100_pcix = bus_ptr - > slots_at_100_pcix ;
bus_info_ptr2 - > slots_at_133_pcix = bus_ptr - > slots_at_133_pcix ;
}
bus_ptr + + ;
}
hpc_ptr - > ctlr_type = temp ;
switch ( hpc_ptr - > ctlr_type ) {
case 1 :
hpc_ptr - > u . pci_ctlr . bus = readb ( io_mem + addr ) ;
hpc_ptr - > u . pci_ctlr . dev_fun = readb ( io_mem + addr + 1 ) ;
hpc_ptr - > irq = readb ( io_mem + addr + 2 ) ;
addr + = 3 ;
debug ( " ctrl bus = %x, ctlr devfun = %x, irq = %x \n " ,
hpc_ptr - > u . pci_ctlr . bus ,
hpc_ptr - > u . pci_ctlr . dev_fun , hpc_ptr - > irq ) ;
break ;
case 0 :
hpc_ptr - > u . isa_ctlr . io_start = readw ( io_mem + addr ) ;
hpc_ptr - > u . isa_ctlr . io_end = readw ( io_mem + addr + 2 ) ;
if ( ! request_region ( hpc_ptr - > u . isa_ctlr . io_start ,
( hpc_ptr - > u . isa_ctlr . io_end - hpc_ptr - > u . isa_ctlr . io_start + 1 ) ,
" ibmphp " ) ) {
rc = - ENODEV ;
goto error_no_hp_slot ;
}
hpc_ptr - > irq = readb ( io_mem + addr + 4 ) ;
addr + = 5 ;
break ;
case 2 :
case 4 :
hpc_ptr - > u . wpeg_ctlr . wpegbbar = readl ( io_mem + addr ) ;
hpc_ptr - > u . wpeg_ctlr . i2c_addr = readb ( io_mem + addr + 4 ) ;
hpc_ptr - > irq = readb ( io_mem + addr + 5 ) ;
addr + = 6 ;
break ;
default :
rc = - ENODEV ;
goto error_no_hp_slot ;
}
//reorganize chassis' linked list
combine_wpg_for_chassis ( ) ;
combine_wpg_for_expansion ( ) ;
hpc_ptr - > revision = 0xff ;
hpc_ptr - > options = 0xff ;
hpc_ptr - > starting_slot_num = hpc_ptr - > slots [ 0 ] . slot_num ;
hpc_ptr - > ending_slot_num = hpc_ptr - > slots [ slot_num - 1 ] . slot_num ;
// register slots with hpc core as well as create linked list of ibm slot
for ( index = 0 ; index < hpc_ptr - > slot_count ; index + + ) {
2006-02-28 15:34:49 +01:00
hp_slot_ptr = kzalloc ( sizeof ( * hp_slot_ptr ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! hp_slot_ptr ) {
rc = - ENOMEM ;
goto error_no_hp_slot ;
}
2006-02-28 15:34:49 +01:00
hp_slot_ptr - > info = kzalloc ( sizeof ( struct hotplug_slot_info ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! hp_slot_ptr - > info ) {
rc = - ENOMEM ;
goto error_no_hp_info ;
}
hp_slot_ptr - > name = kmalloc ( 30 , GFP_KERNEL ) ;
if ( ! hp_slot_ptr - > name ) {
rc = - ENOMEM ;
goto error_no_hp_name ;
}
2006-02-28 15:34:49 +01:00
tmp_slot = kzalloc ( sizeof ( * tmp_slot ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! tmp_slot ) {
rc = - ENOMEM ;
goto error_no_slot ;
}
2006-03-14 16:24:47 -08:00
tmp_slot - > flag = 1 ;
2005-04-16 15:20:36 -07:00
tmp_slot - > capabilities = hpc_ptr - > slots [ index ] . slot_cap ;
if ( ( hpc_ptr - > slots [ index ] . slot_cap & EBDA_SLOT_133_MAX ) = = EBDA_SLOT_133_MAX )
tmp_slot - > supported_speed = 3 ;
else if ( ( hpc_ptr - > slots [ index ] . slot_cap & EBDA_SLOT_100_MAX ) = = EBDA_SLOT_100_MAX )
tmp_slot - > supported_speed = 2 ;
else if ( ( hpc_ptr - > slots [ index ] . slot_cap & EBDA_SLOT_66_MAX ) = = EBDA_SLOT_66_MAX )
tmp_slot - > supported_speed = 1 ;
if ( ( hpc_ptr - > slots [ index ] . slot_cap & EBDA_SLOT_PCIX_CAP ) = = EBDA_SLOT_PCIX_CAP )
tmp_slot - > supported_bus_mode = 1 ;
else
tmp_slot - > supported_bus_mode = 0 ;
tmp_slot - > bus = hpc_ptr - > slots [ index ] . slot_bus_num ;
bus_info_ptr1 = ibmphp_find_same_bus_num ( hpc_ptr - > slots [ index ] . slot_bus_num ) ;
if ( ! bus_info_ptr1 ) {
rc = - ENODEV ;
goto error ;
}
tmp_slot - > bus_on = bus_info_ptr1 ;
bus_info_ptr1 = NULL ;
tmp_slot - > ctrl = hpc_ptr ;
tmp_slot - > ctlr_index = hpc_ptr - > slots [ index ] . ctl_index ;
tmp_slot - > number = hpc_ptr - > slots [ index ] . slot_num ;
tmp_slot - > hotplug_slot = hp_slot_ptr ;
hp_slot_ptr - > private = tmp_slot ;
hp_slot_ptr - > release = release_slot ;
rc = fillslotinfo ( hp_slot_ptr ) ;
if ( rc )
goto error ;
rc = ibmphp_init_devno ( ( struct slot * * ) & hp_slot_ptr - > private ) ;
if ( rc )
goto error ;
hp_slot_ptr - > ops = & ibmphp_hotplug_slot_ops ;
// end of registering ibm slot with hotplug core
list_add ( & ( ( struct slot * ) ( hp_slot_ptr - > private ) ) - > ibm_slot_list , & ibmphp_slot_head ) ;
}
print_bus_info ( ) ;
list_add ( & hpc_ptr - > ebda_hpc_list , & ebda_hpc_head ) ;
} /* each hpc */
list_for_each ( list , & ibmphp_slot_head ) {
tmp_slot = list_entry ( list , struct slot , ibm_slot_list ) ;
snprintf ( tmp_slot - > hotplug_slot - > name , 30 , " %s " , create_file_name ( tmp_slot ) ) ;
pci_hp_register ( tmp_slot - > hotplug_slot ) ;
}
print_ebda_hpc ( ) ;
print_ibm_slot ( ) ;
return 0 ;
error :
kfree ( hp_slot_ptr - > private ) ;
error_no_slot :
kfree ( hp_slot_ptr - > name ) ;
error_no_hp_name :
kfree ( hp_slot_ptr - > info ) ;
error_no_hp_info :
kfree ( hp_slot_ptr ) ;
error_no_hp_slot :
free_ebda_hpc ( hpc_ptr ) ;
error_no_hpc :
iounmap ( io_mem ) ;
return rc ;
}
/*
* map info ( bus , devfun , start addr , end addr . . ) of i / o , memory ,
* pfm from the physical addr to a list of resource .
*/
static int __init ebda_rsrc_rsrc ( void )
{
u16 addr ;
short rsrc ;
u8 type , rsrc_type ;
struct ebda_pci_rsrc * rsrc_ptr ;
addr = rsrc_list_ptr - > phys_addr ;
debug ( " now entering rsrc land \n " ) ;
debug ( " offset of rsrc: %x \n " , rsrc_list_ptr - > phys_addr ) ;
for ( rsrc = 0 ; rsrc < rsrc_list_ptr - > num_entries ; rsrc + + ) {
type = readb ( io_mem + addr ) ;
addr + = 1 ;
rsrc_type = type & EBDA_RSRC_TYPE_MASK ;
if ( rsrc_type = = EBDA_IO_RSRC_TYPE ) {
rsrc_ptr = alloc_ebda_pci_rsrc ( ) ;
if ( ! rsrc_ptr ) {
iounmap ( io_mem ) ;
return - ENOMEM ;
}
rsrc_ptr - > rsrc_type = type ;
rsrc_ptr - > bus_num = readb ( io_mem + addr ) ;
rsrc_ptr - > dev_fun = readb ( io_mem + addr + 1 ) ;
rsrc_ptr - > start_addr = readw ( io_mem + addr + 2 ) ;
rsrc_ptr - > end_addr = readw ( io_mem + addr + 4 ) ;
addr + = 6 ;
debug ( " rsrc from io type ---- \n " ) ;
debug ( " rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x \n " ,
rsrc_ptr - > rsrc_type , rsrc_ptr - > bus_num , rsrc_ptr - > dev_fun , rsrc_ptr - > start_addr , rsrc_ptr - > end_addr ) ;
list_add ( & rsrc_ptr - > ebda_pci_rsrc_list , & ibmphp_ebda_pci_rsrc_head ) ;
}
if ( rsrc_type = = EBDA_MEM_RSRC_TYPE | | rsrc_type = = EBDA_PFM_RSRC_TYPE ) {
rsrc_ptr = alloc_ebda_pci_rsrc ( ) ;
if ( ! rsrc_ptr ) {
iounmap ( io_mem ) ;
return - ENOMEM ;
}
rsrc_ptr - > rsrc_type = type ;
rsrc_ptr - > bus_num = readb ( io_mem + addr ) ;
rsrc_ptr - > dev_fun = readb ( io_mem + addr + 1 ) ;
rsrc_ptr - > start_addr = readl ( io_mem + addr + 2 ) ;
rsrc_ptr - > end_addr = readl ( io_mem + addr + 6 ) ;
addr + = 10 ;
debug ( " rsrc from mem or pfm --- \n " ) ;
debug ( " rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x \n " ,
rsrc_ptr - > rsrc_type , rsrc_ptr - > bus_num , rsrc_ptr - > dev_fun , rsrc_ptr - > start_addr , rsrc_ptr - > end_addr ) ;
list_add ( & rsrc_ptr - > ebda_pci_rsrc_list , & ibmphp_ebda_pci_rsrc_head ) ;
}
}
kfree ( rsrc_list_ptr ) ;
rsrc_list_ptr = NULL ;
print_ebda_pci_rsrc ( ) ;
return 0 ;
}
u16 ibmphp_get_total_controllers ( void )
{
return hpc_list_ptr - > num_ctlrs ;
}
struct slot * ibmphp_get_slot_from_physical_num ( u8 physical_num )
{
struct slot * slot ;
struct list_head * list ;
list_for_each ( list , & ibmphp_slot_head ) {
slot = list_entry ( list , struct slot , ibm_slot_list ) ;
if ( slot - > number = = physical_num )
return slot ;
}
return NULL ;
}
/* To find:
* - the smallest slot number
* - the largest slot number
* - the total number of the slots based on each bus
* ( if only one slot per bus slot_min = slot_max )
*/
struct bus_info * ibmphp_find_same_bus_num ( u32 num )
{
struct bus_info * ptr ;
struct list_head * ptr1 ;
list_for_each ( ptr1 , & bus_info_head ) {
ptr = list_entry ( ptr1 , struct bus_info , bus_info_list ) ;
if ( ptr - > busno = = num )
return ptr ;
}
return NULL ;
}
/* Finding relative bus number, in order to map corresponding
* bus register
*/
int ibmphp_get_bus_index ( u8 num )
{
struct bus_info * ptr ;
struct list_head * ptr1 ;
list_for_each ( ptr1 , & bus_info_head ) {
ptr = list_entry ( ptr1 , struct bus_info , bus_info_list ) ;
if ( ptr - > busno = = num )
return ptr - > index ;
}
return - ENODEV ;
}
void ibmphp_free_bus_info_queue ( void )
{
struct bus_info * bus_info ;
struct list_head * list ;
struct list_head * next ;
list_for_each_safe ( list , next , & bus_info_head ) {
bus_info = list_entry ( list , struct bus_info , bus_info_list ) ;
kfree ( bus_info ) ;
}
}
void ibmphp_free_ebda_hpc_queue ( void )
{
struct controller * controller = NULL ;
struct list_head * list ;
struct list_head * next ;
int pci_flag = 0 ;
list_for_each_safe ( list , next , & ebda_hpc_head ) {
controller = list_entry ( list , struct controller , ebda_hpc_list ) ;
if ( controller - > ctlr_type = = 0 )
release_region ( controller - > u . isa_ctlr . io_start , ( controller - > u . isa_ctlr . io_end - controller - > u . isa_ctlr . io_start + 1 ) ) ;
else if ( ( controller - > ctlr_type = = 1 ) & & ( ! pci_flag ) ) {
+ + pci_flag ;
pci_unregister_driver ( & ibmphp_driver ) ;
}
free_ebda_hpc ( controller ) ;
}
}
void ibmphp_free_ebda_pci_rsrc_queue ( void )
{
struct ebda_pci_rsrc * resource ;
struct list_head * list ;
struct list_head * next ;
list_for_each_safe ( list , next , & ibmphp_ebda_pci_rsrc_head ) {
resource = list_entry ( list , struct ebda_pci_rsrc , ebda_pci_rsrc_list ) ;
kfree ( resource ) ;
resource = NULL ;
}
}
static struct pci_device_id id_table [ ] = {
{
. vendor = PCI_VENDOR_ID_IBM ,
. device = HPC_DEVICE_ID ,
. subvendor = PCI_VENDOR_ID_IBM ,
. subdevice = HPC_SUBSYSTEM_ID ,
. class = ( ( PCI_CLASS_SYSTEM_PCI_HOTPLUG < < 8 ) | 0x00 ) ,
} , { }
} ;
MODULE_DEVICE_TABLE ( pci , id_table ) ;
static int ibmphp_probe ( struct pci_dev * , const struct pci_device_id * ) ;
static struct pci_driver ibmphp_driver = {
. name = " ibmphp " ,
. id_table = id_table ,
. probe = ibmphp_probe ,
} ;
int ibmphp_register_pci ( void )
{
struct controller * ctrl ;
struct list_head * tmp ;
int rc = 0 ;
list_for_each ( tmp , & ebda_hpc_head ) {
ctrl = list_entry ( tmp , struct controller , ebda_hpc_list ) ;
if ( ctrl - > ctlr_type = = 1 ) {
rc = pci_register_driver ( & ibmphp_driver ) ;
break ;
}
}
return rc ;
}
static int ibmphp_probe ( struct pci_dev * dev , const struct pci_device_id * ids )
{
struct controller * ctrl ;
struct list_head * tmp ;
debug ( " inside ibmphp_probe \n " ) ;
list_for_each ( tmp , & ebda_hpc_head ) {
ctrl = list_entry ( tmp , struct controller , ebda_hpc_list ) ;
if ( ctrl - > ctlr_type = = 1 ) {
if ( ( dev - > devfn = = ctrl - > u . pci_ctlr . dev_fun ) & & ( dev - > bus - > number = = ctrl - > u . pci_ctlr . bus ) ) {
ctrl - > ctrl_dev = dev ;
debug ( " found device!!! \n " ) ;
debug ( " dev->device = %x, dev->subsystem_device = %x \n " , dev - > device , dev - > subsystem_device ) ;
return 0 ;
}
}
}
return - ENODEV ;
}