2005-04-16 15:20:36 -07:00
# include <linux/init.h>
# include <linux/pci.h>
# include <asm/mpspec.h>
# include <linux/cpumask.h>
/*
* This discovers the pcibus < - > node mapping on AMD K8 .
*
* RED - PEN need to call this again on PCI hotplug
* RED - PEN empty cpus get reported wrong
*/
# define NODE_ID_REGISTER 0x60
# define NODE_ID(dword) (dword & 0x07)
# define LDT_BUS_NUMBER_REGISTER_0 0x94
# define LDT_BUS_NUMBER_REGISTER_1 0xB4
# define LDT_BUS_NUMBER_REGISTER_2 0xD4
# define NR_LDT_BUS_NUMBER_REGISTERS 3
# define SECONDARY_LDT_BUS_NUMBER(dword) ((dword >> 8) & 0xFF)
# define SUBORDINATE_LDT_BUS_NUMBER(dword) ((dword >> 16) & 0xFF)
2006-07-29 21:42:46 +02:00
# define PCI_DEVICE_ID_K8HTCONFIG 0x1100
2005-04-16 15:20:36 -07:00
/**
* fill_mp_bus_to_cpumask ( )
* fills the mp_bus_to_cpumask array based according to the LDT Bus Number
* Registers found in the K8 northbridge
*/
__init static int
fill_mp_bus_to_cpumask ( void )
{
2006-07-29 21:42:46 +02:00
struct pci_dev * nb_dev = NULL ;
int i , j ;
2005-04-16 15:20:36 -07:00
u32 ldtbus , nid ;
static int lbnr [ 3 ] = {
LDT_BUS_NUMBER_REGISTER_0 ,
LDT_BUS_NUMBER_REGISTER_1 ,
LDT_BUS_NUMBER_REGISTER_2
} ;
2006-07-29 21:42:46 +02:00
while ( ( nb_dev = pci_get_device ( PCI_VENDOR_ID_AMD ,
PCI_DEVICE_ID_K8HTCONFIG , nb_dev ) ) ) {
2005-04-16 15:20:36 -07:00
pci_read_config_dword ( nb_dev , NODE_ID_REGISTER , & nid ) ;
for ( i = 0 ; i < NR_LDT_BUS_NUMBER_REGISTERS ; i + + ) {
pci_read_config_dword ( nb_dev , lbnr [ i ] , & ldtbus ) ;
/*
* if there are no busses hanging off of the current
* ldt link then both the secondary and subordinate
* bus number fields are set to 0.
2005-08-23 03:14:27 +02:00
*
* RED - PEN
* This is slightly broken because it assumes
* HT node IDs = = Linux node ids , which is not always
* true . However it is probably mostly true .
2005-04-16 15:20:36 -07:00
*/
if ( ! ( SECONDARY_LDT_BUS_NUMBER ( ldtbus ) = = 0
& & SUBORDINATE_LDT_BUS_NUMBER ( ldtbus ) = = 0 ) ) {
for ( j = SECONDARY_LDT_BUS_NUMBER ( ldtbus ) ;
j < = SUBORDINATE_LDT_BUS_NUMBER ( ldtbus ) ;
2005-08-23 03:14:27 +02:00
j + + ) {
2005-09-12 18:49:24 +02:00
struct pci_bus * bus ;
long node = NODE_ID ( nid ) ;
/* Algorithm a bit dumb, but
it shouldn ' t matter here */
bus = pci_find_bus ( 0 , j ) ;
if ( ! bus )
continue ;
2005-08-23 03:14:27 +02:00
if ( ! node_online ( node ) )
node = 0 ;
2005-09-12 18:49:24 +02:00
bus - > sysdata = ( void * ) node ;
2005-08-23 03:14:27 +02:00
}
2005-04-16 15:20:36 -07:00
}
}
}
return 0 ;
}
fs_initcall ( fill_mp_bus_to_cpumask ) ;