2005-04-17 02:20:36 +04:00
/*
* acpi_numa . c - ACPI NUMA support
*
* Copyright ( C ) 2002 Takayoshi Kochi < t - kochi @ bq . jp . nec . com >
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* 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 . 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 . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/types.h>
# include <linux/errno.h>
# include <linux/acpi.h>
# include <acpi/acpi_bus.h>
# define ACPI_NUMA 0x80000000
# define _COMPONENT ACPI_NUMA
2007-02-13 06:42:12 +03:00
ACPI_MODULE_NAME ( " numa " ) ;
2005-04-17 02:20:36 +04:00
2006-06-23 13:03:19 +04:00
static nodemask_t nodes_found_map = NODE_MASK_NONE ;
/* maps to convert between proximity domain and logical node ID */
2007-12-13 11:32:26 +03:00
static int pxm_to_node_map [ MAX_PXM_DOMAINS ]
2006-06-23 13:03:19 +04:00
= { [ 0 . . . MAX_PXM_DOMAINS - 1 ] = NID_INVAL } ;
2007-12-13 11:32:26 +03:00
static int node_to_pxm_map [ MAX_NUMNODES ]
2006-06-23 13:03:19 +04:00
= { [ 0 . . . MAX_NUMNODES - 1 ] = PXM_INVAL } ;
2007-05-17 09:11:06 +04:00
int pxm_to_node ( int pxm )
2006-06-23 13:03:19 +04:00
{
if ( pxm < 0 )
return NID_INVAL ;
return pxm_to_node_map [ pxm ] ;
}
2007-05-17 09:11:06 +04:00
int node_to_pxm ( int node )
2006-06-23 13:03:19 +04:00
{
if ( node < 0 )
return PXM_INVAL ;
return node_to_pxm_map [ node ] ;
}
2007-07-21 19:10:32 +04:00
void __acpi_map_pxm_to_node ( int pxm , int node )
{
pxm_to_node_map [ pxm ] = node ;
node_to_pxm_map [ node ] = pxm ;
}
2007-05-25 00:57:40 +04:00
int acpi_map_pxm_to_node ( int pxm )
2006-06-23 13:03:19 +04:00
{
int node = pxm_to_node_map [ pxm ] ;
if ( node < 0 ) {
if ( nodes_weight ( nodes_found_map ) > = MAX_NUMNODES )
return NID_INVAL ;
node = first_unset_node ( nodes_found_map ) ;
2007-07-21 19:10:32 +04:00
__acpi_map_pxm_to_node ( pxm , node ) ;
2006-06-23 13:03:19 +04:00
node_set ( node , nodes_found_map ) ;
}
return node ;
}
2007-10-24 20:24:42 +04:00
#if 0
2006-06-23 13:03:19 +04:00
void __cpuinit acpi_unmap_pxm_to_node ( int node )
{
int pxm = node_to_pxm_map [ node ] ;
pxm_to_node_map [ pxm ] = NID_INVAL ;
node_to_pxm_map [ node ] = PXM_INVAL ;
node_clear ( node , nodes_found_map ) ;
}
2007-10-24 20:24:42 +04:00
# endif /* 0 */
2006-06-23 13:03:19 +04:00
2007-07-21 19:09:56 +04:00
static void __init
acpi_table_print_srat_entry ( struct acpi_subtable_header * header )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
ACPI_FUNCTION_NAME ( " acpi_table_print_srat_entry " ) ;
2005-04-17 02:20:36 +04:00
if ( ! header )
return ;
switch ( header - > type ) {
2007-02-02 19:48:22 +03:00
case ACPI_SRAT_TYPE_CPU_AFFINITY :
2005-04-17 02:20:36 +04:00
# ifdef ACPI_DEBUG_OUTPUT
2005-08-05 08:44:28 +04:00
{
2007-02-02 19:48:22 +03:00
struct acpi_srat_cpu_affinity * p =
( struct acpi_srat_cpu_affinity * ) header ;
2005-08-05 08:44:28 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
" SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s \n " ,
2007-02-02 19:48:22 +03:00
p - > apic_id , p - > local_sapic_eid ,
p - > proximity_domain_lo ,
( p - > flags & ACPI_SRAT_CPU_ENABLED ) ?
" enabled " : " disabled " ) ) ;
2005-08-05 08:44:28 +04:00
}
# endif /* ACPI_DEBUG_OUTPUT */
2005-04-17 02:20:36 +04:00
break ;
2007-02-02 19:48:22 +03:00
case ACPI_SRAT_TYPE_MEMORY_AFFINITY :
2005-04-17 02:20:36 +04:00
# ifdef ACPI_DEBUG_OUTPUT
2005-08-05 08:44:28 +04:00
{
2007-02-02 19:48:22 +03:00
struct acpi_srat_mem_affinity * p =
( struct acpi_srat_mem_affinity * ) header ;
2005-08-05 08:44:28 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
2008-06-10 11:54:40 +04:00
" SRAT Memory (0x%lx length 0x%lx) in proximity domain %d %s%s \n " ,
2007-02-02 19:48:22 +03:00
( unsigned long ) p - > base_address ,
( unsigned long ) p - > length ,
2008-06-10 11:54:40 +04:00
p - > proximity_domain ,
2007-02-02 19:48:22 +03:00
( p - > flags & ACPI_SRAT_MEM_ENABLED ) ?
" enabled " : " disabled " ,
( p - > flags & ACPI_SRAT_MEM_HOT_PLUGGABLE ) ?
" hot-pluggable " : " " ) ) ;
2005-08-05 08:44:28 +04:00
}
# endif /* ACPI_DEBUG_OUTPUT */
2005-04-17 02:20:36 +04:00
break ;
default :
2005-08-05 08:44:28 +04:00
printk ( KERN_WARNING PREFIX
" Found unsupported SRAT entry (type = 0x%x) \n " ,
header - > type ) ;
2005-04-17 02:20:36 +04:00
break ;
}
}
2008-06-10 03:48:18 +04:00
/*
* A lot of BIOS fill in 10 ( = no distance ) everywhere . This messes
* up the NUMA heuristics which wants the local node to have a smaller
* distance than the others .
* Do some quick checks here and only use the SLIT if it passes .
*/
static __init int slit_valid ( struct acpi_table_slit * slit )
{
int i , j ;
int d = slit - > locality_count ;
for ( i = 0 ; i < d ; i + + ) {
for ( j = 0 ; j < d ; j + + ) {
u8 val = slit - > entry [ d * i + j ] ;
if ( i = = j ) {
if ( val ! = LOCAL_DISTANCE )
return 0 ;
} else if ( val < = LOCAL_DISTANCE )
return 0 ;
}
}
return 1 ;
}
2007-02-02 19:48:22 +03:00
static int __init acpi_parse_slit ( struct acpi_table_header * table )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct acpi_table_slit * slit ;
2005-04-17 02:20:36 +04:00
2007-02-02 19:48:22 +03:00
if ( ! table )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2007-02-02 19:48:22 +03:00
slit = ( struct acpi_table_slit * ) table ;
2005-04-17 02:20:36 +04:00
2008-06-10 03:48:18 +04:00
if ( ! slit_valid ( slit ) ) {
printk ( KERN_INFO " ACPI: SLIT table looks invalid. Not used. \n " ) ;
return - EINVAL ;
}
2005-04-17 02:20:36 +04:00
acpi_numa_slit_init ( slit ) ;
return 0 ;
}
static int __init
2007-02-02 19:48:22 +03:00
acpi_parse_processor_affinity ( struct acpi_subtable_header * header ,
2005-08-05 08:44:28 +04:00
const unsigned long end )
2005-04-17 02:20:36 +04:00
{
2007-02-02 19:48:22 +03:00
struct acpi_srat_cpu_affinity * processor_affinity ;
2005-04-17 02:20:36 +04:00
2007-02-02 19:48:22 +03:00
processor_affinity = ( struct acpi_srat_cpu_affinity * ) header ;
2005-04-17 02:20:36 +04:00
if ( ! processor_affinity )
return - EINVAL ;
acpi_table_print_srat_entry ( header ) ;
/* let architecture-dependent part to do it */
acpi_numa_processor_affinity_init ( processor_affinity ) ;
return 0 ;
}
static int __init
2007-02-02 19:48:22 +03:00
acpi_parse_memory_affinity ( struct acpi_subtable_header * header ,
2005-08-05 08:44:28 +04:00
const unsigned long end )
2005-04-17 02:20:36 +04:00
{
2007-02-02 19:48:22 +03:00
struct acpi_srat_mem_affinity * memory_affinity ;
2005-04-17 02:20:36 +04:00
2007-02-02 19:48:22 +03:00
memory_affinity = ( struct acpi_srat_mem_affinity * ) header ;
2005-04-17 02:20:36 +04:00
if ( ! memory_affinity )
return - EINVAL ;
acpi_table_print_srat_entry ( header ) ;
/* let architecture-dependent part to do it */
acpi_numa_memory_affinity_init ( memory_affinity ) ;
return 0 ;
}
2007-02-02 19:48:22 +03:00
static int __init acpi_parse_srat ( struct acpi_table_header * table )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct acpi_table_srat * srat ;
2005-04-17 02:20:36 +04:00
2007-02-02 19:48:22 +03:00
if ( ! table )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2007-02-02 19:48:22 +03:00
srat = ( struct acpi_table_srat * ) table ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-07-21 19:09:56 +04:00
static int __init
2007-02-02 19:48:22 +03:00
acpi_table_parse_srat ( enum acpi_srat_type id ,
2007-02-11 05:35:47 +03:00
acpi_table_entry_handler handler , unsigned int max_entries )
2005-04-17 02:20:36 +04:00
{
2007-02-11 06:17:07 +03:00
return acpi_table_parse_entries ( ACPI_SIG_SRAT ,
2005-08-05 08:44:28 +04:00
sizeof ( struct acpi_table_srat ) , id ,
handler , max_entries ) ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
int __init acpi_numa_init ( void )
2005-04-17 02:20:36 +04:00
{
/* SRAT: Static Resource Affinity Table */
2007-02-11 05:28:03 +03:00
if ( ! acpi_table_parse ( ACPI_SIG_SRAT , acpi_parse_srat ) ) {
2007-07-21 19:09:56 +04:00
acpi_table_parse_srat ( ACPI_SRAT_TYPE_CPU_AFFINITY ,
acpi_parse_processor_affinity , NR_CPUS ) ;
acpi_table_parse_srat ( ACPI_SRAT_TYPE_MEMORY_AFFINITY ,
acpi_parse_memory_affinity ,
NR_NODE_MEMBLKS ) ;
2005-04-17 02:20:36 +04:00
}
/* SLIT: System Locality Information Table */
2007-02-11 05:28:03 +03:00
acpi_table_parse ( ACPI_SIG_SLIT , acpi_parse_slit ) ;
2005-04-17 02:20:36 +04:00
acpi_numa_arch_fixup ( ) ;
return 0 ;
}
2007-05-09 07:27:01 +04:00
int acpi_get_pxm ( acpi_handle h )
2005-04-17 02:20:36 +04:00
{
2008-10-10 10:22:59 +04:00
unsigned long long pxm ;
2005-04-17 02:20:36 +04:00
acpi_status status ;
acpi_handle handle ;
acpi_handle phandle = h ;
do {
handle = phandle ;
status = acpi_evaluate_integer ( handle , " _PXM " , NULL , & pxm ) ;
if ( ACPI_SUCCESS ( status ) )
2006-10-01 02:28:50 +04:00
return pxm ;
2005-04-17 02:20:36 +04:00
status = acpi_get_parent ( handle , & phandle ) ;
2005-08-05 08:44:28 +04:00
} while ( ACPI_SUCCESS ( status ) ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
2006-06-27 13:53:31 +04:00
2007-05-09 07:27:01 +04:00
int acpi_get_node ( acpi_handle * handle )
2006-06-27 13:53:31 +04:00
{
int pxm , node = - 1 ;
pxm = acpi_get_pxm ( handle ) ;
if ( pxm > = 0 )
node = acpi_map_pxm_to_node ( pxm ) ;
2006-07-02 00:48:23 +04:00
return node ;
2006-06-27 13:53:31 +04:00
}
EXPORT_SYMBOL ( acpi_get_node ) ;