2005-04-17 02:20:36 +04:00
/*
2007-10-13 05:10:53 +04:00
* IBM Summit - Specific Code
2005-04-17 02:20:36 +04:00
*
* Written By : Matthew Dobson , IBM Corporation
*
* Copyright ( c ) 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 < colpatch @ us . ibm . com >
*
*/
# include <linux/mm.h>
# include <linux/init.h>
# include <asm/io.h>
# include <asm/mach-summit/mach_mpparse.h>
static struct rio_table_hdr * rio_table_hdr __initdata ;
static struct scal_detail * scal_devs [ MAX_NUMNODES ] __initdata ;
static struct rio_detail * rio_devs [ MAX_NUMNODES * 4 ] __initdata ;
static int __init setup_pci_node_map_for_wpeg ( int wpeg_num , int last_bus )
{
int twister = 0 , node = 0 ;
int i , bus , num_buses ;
for ( i = 0 ; i < rio_table_hdr - > num_rio_dev ; i + + ) {
if ( rio_devs [ i ] - > node_id = = rio_devs [ wpeg_num ] - > owner_id ) {
twister = rio_devs [ i ] - > owner_id ;
break ;
}
}
if ( i = = rio_table_hdr - > num_rio_dev ) {
printk ( KERN_ERR " %s: Couldn't find owner Cyclone for Winnipeg! \n " , __FUNCTION__ ) ;
return last_bus ;
}
for ( i = 0 ; i < rio_table_hdr - > num_scal_dev ; i + + ) {
if ( scal_devs [ i ] - > node_id = = twister ) {
node = scal_devs [ i ] - > node_id ;
break ;
}
}
if ( i = = rio_table_hdr - > num_scal_dev ) {
printk ( KERN_ERR " %s: Couldn't find owner Twister for Cyclone! \n " , __FUNCTION__ ) ;
return last_bus ;
}
switch ( rio_devs [ wpeg_num ] - > type ) {
case CompatWPEG :
2007-10-20 03:13:56 +04:00
/* The Compatibility Winnipeg controls the 2 legacy buses,
2005-04-17 02:20:36 +04:00
* the 66 MHz PCI bus [ 2 slots ] and the 2 " extra " buses in case
* a PCI - PCI bridge card is used in either slot : total 5 buses .
*/
num_buses = 5 ;
break ;
case AltWPEG :
/* The Alternate Winnipeg controls the 2 133MHz buses [1 slot
* each ] , their 2 " extra " buses , the 100 MHz bus [ 2 slots ] and
* the " extra " buses for each of those slots : total 7 buses .
*/
num_buses = 7 ;
break ;
case LookOutAWPEG :
case LookOutBWPEG :
/* A Lookout Winnipeg controls 3 100MHz buses [2 slots each]
* & the " extra " buses for each of those slots : total 9 buses .
*/
num_buses = 9 ;
break ;
default :
printk ( KERN_INFO " %s: Unsupported Winnipeg type! \n " , __FUNCTION__ ) ;
return last_bus ;
}
for ( bus = last_bus ; bus < last_bus + num_buses ; bus + + )
mp_bus_id_to_node [ bus ] = node ;
return bus ;
}
static int __init build_detail_arrays ( void )
{
unsigned long ptr ;
int i , scal_detail_size , rio_detail_size ;
if ( rio_table_hdr - > num_scal_dev > MAX_NUMNODES ) {
printk ( KERN_WARNING " %s: MAX_NUMNODES too low! Defined as %d, but system has %d nodes. \n " , __FUNCTION__ , MAX_NUMNODES , rio_table_hdr - > num_scal_dev ) ;
return 0 ;
}
switch ( rio_table_hdr - > version ) {
default :
printk ( KERN_WARNING " %s: Invalid Rio Grande Table Version: %d \n " , __FUNCTION__ , rio_table_hdr - > version ) ;
return 0 ;
case 2 :
scal_detail_size = 11 ;
rio_detail_size = 13 ;
break ;
case 3 :
scal_detail_size = 12 ;
rio_detail_size = 15 ;
break ;
}
ptr = ( unsigned long ) rio_table_hdr + 3 ;
for ( i = 0 ; i < rio_table_hdr - > num_scal_dev ; i + + , ptr + = scal_detail_size )
scal_devs [ i ] = ( struct scal_detail * ) ptr ;
for ( i = 0 ; i < rio_table_hdr - > num_rio_dev ; i + + , ptr + = rio_detail_size )
rio_devs [ i ] = ( struct rio_detail * ) ptr ;
return 1 ;
}
void __init setup_summit ( void )
{
unsigned long ptr ;
unsigned short offset ;
int i , next_wpeg , next_bus = 0 ;
/* The pointer to the EBDA is stored in the word @ phys 0x40E(40:0E) */
ptr = * ( unsigned short * ) phys_to_virt ( 0x40Eul ) ;
ptr = ( unsigned long ) phys_to_virt ( ptr < < 4 ) ;
rio_table_hdr = NULL ;
offset = 0x180 ;
while ( offset ) {
/* The block id is stored in the 2nd word */
if ( * ( ( unsigned short * ) ( ptr + offset + 2 ) ) = = 0x4752 ) {
/* set the pointer past the offset & block id */
rio_table_hdr = ( struct rio_table_hdr * ) ( ptr + offset + 4 ) ;
break ;
}
/* The next offset is stored in the 1st word. 0 means no more */
offset = * ( ( unsigned short * ) ( ptr + offset ) ) ;
}
if ( ! rio_table_hdr ) {
printk ( KERN_ERR " %s: Unable to locate Rio Grande Table in EBDA - bailing! \n " , __FUNCTION__ ) ;
return ;
}
if ( ! build_detail_arrays ( ) )
return ;
/* The first Winnipeg we're looking for has an index of 0 */
next_wpeg = 0 ;
do {
for ( i = 0 ; i < rio_table_hdr - > num_rio_dev ; i + + ) {
if ( is_WPEG ( rio_devs [ i ] ) & & rio_devs [ i ] - > WP_index = = next_wpeg ) {
/* It's the Winnipeg we're looking for! */
next_bus = setup_pci_node_map_for_wpeg ( i , next_bus ) ;
next_wpeg + + ;
break ;
}
}
/*
* If we go through all Rio devices and don ' t find one with
* the next index , it means we ' ve found all the Winnipegs ,
* and thus all the PCI buses .
*/
if ( i = = rio_table_hdr - > num_rio_dev )
next_wpeg = 0 ;
} while ( next_wpeg ! = 0 ) ;
}