2005-04-17 02:20:36 +04:00
/*
* acpi . c - Architecture - Specific Low - Level ACPI Support
*
* Copyright ( C ) 1999 VA Linux Systems
* Copyright ( C ) 1999 , 2000 Walt Drummond < drummond @ valinux . com >
* Copyright ( C ) 2000 , 2002 - 2003 Hewlett - Packard Co .
* David Mosberger - Tang < davidm @ hpl . hp . com >
* Copyright ( C ) 2000 Intel Corp .
* Copyright ( C ) 2000 , 2001 J . I . Lee < jung - ik . lee @ intel . com >
* Copyright ( C ) 2001 Paul Diefenbaugh < paul . s . diefenbaugh @ intel . com >
* Copyright ( C ) 2001 Jenna Hall < jenna . s . hall @ intel . com >
* Copyright ( C ) 2001 Takayoshi Kochi < t - kochi @ bq . jp . nec . com >
* Copyright ( C ) 2002 Erich Focht < efocht @ ess . nec . de >
2005-04-01 07:51:10 +04:00
* Copyright ( C ) 2004 Ashok Raj < ashok . raj @ intel . com >
2005-04-17 02:20:36 +04:00
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* 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/config.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/sched.h>
# include <linux/smp.h>
# include <linux/string.h>
# include <linux/types.h>
# include <linux/irq.h>
# include <linux/acpi.h>
# include <linux/efi.h>
# include <linux/mmzone.h>
# include <linux/nodemask.h>
# include <asm/io.h>
# include <asm/iosapic.h>
# include <asm/machvec.h>
# include <asm/page.h>
# include <asm/system.h>
# include <asm/numa.h>
# include <asm/sal.h>
# include <asm/cyclone.h>
# define BAD_MADT_ENTRY(entry, end) ( \
( ! entry ) | | ( unsigned long ) entry + sizeof ( * entry ) > end | | \
( ( acpi_table_entry_header * ) entry ) - > length ! = sizeof ( * entry ) )
# define PREFIX "ACPI: "
void ( * pm_idle ) ( void ) ;
EXPORT_SYMBOL ( pm_idle ) ;
void ( * pm_power_off ) ( void ) ;
EXPORT_SYMBOL ( pm_power_off ) ;
unsigned char acpi_kbd_controller_present = 1 ;
unsigned char acpi_legacy_devices ;
2005-04-01 07:51:10 +04:00
unsigned int acpi_cpei_override ;
unsigned int acpi_cpei_phys_cpuid ;
2005-04-17 02:20:36 +04:00
# define MAX_SAPICS 256
2005-08-08 09:09:00 +04:00
u16 ia64_acpiid_to_sapicid [ MAX_SAPICS ] = { [ 0 . . . MAX_SAPICS - 1 ] = - 1 } ;
2005-08-05 08:44:28 +04:00
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( ia64_acpiid_to_sapicid ) ;
2005-08-05 08:44:28 +04:00
const char * acpi_get_sysname ( void )
2005-04-17 02:20:36 +04:00
{
# ifdef CONFIG_IA64_GENERIC
unsigned long rsdp_phys ;
struct acpi20_table_rsdp * rsdp ;
struct acpi_table_xsdt * xsdt ;
struct acpi_table_header * hdr ;
rsdp_phys = acpi_find_rsdp ( ) ;
if ( ! rsdp_phys ) {
2005-08-05 08:44:28 +04:00
printk ( KERN_ERR
" ACPI 2.0 RSDP not found, default to \" dig \" \n " ) ;
2005-04-17 02:20:36 +04:00
return " dig " ;
}
2005-08-05 08:44:28 +04:00
rsdp = ( struct acpi20_table_rsdp * ) __va ( rsdp_phys ) ;
2005-04-17 02:20:36 +04:00
if ( strncmp ( rsdp - > signature , RSDP_SIG , sizeof ( RSDP_SIG ) - 1 ) ) {
2005-08-05 08:44:28 +04:00
printk ( KERN_ERR
" ACPI 2.0 RSDP signature incorrect, default to \" dig \" \n " ) ;
2005-04-17 02:20:36 +04:00
return " dig " ;
}
2005-08-05 08:44:28 +04:00
xsdt = ( struct acpi_table_xsdt * ) __va ( rsdp - > xsdt_address ) ;
2005-04-17 02:20:36 +04:00
hdr = & xsdt - > header ;
if ( strncmp ( hdr - > signature , XSDT_SIG , sizeof ( XSDT_SIG ) - 1 ) ) {
2005-08-05 08:44:28 +04:00
printk ( KERN_ERR
" ACPI 2.0 XSDT signature incorrect, default to \" dig \" \n " ) ;
2005-04-17 02:20:36 +04:00
return " dig " ;
}
if ( ! strcmp ( hdr - > oem_id , " HP " ) ) {
return " hpzx1 " ;
2005-08-05 08:44:28 +04:00
} else if ( ! strcmp ( hdr - > oem_id , " SGI " ) ) {
2005-04-17 02:20:36 +04:00
return " sn2 " ;
}
return " dig " ;
# else
# if defined (CONFIG_IA64_HP_SIM)
return " hpsim " ;
# elif defined (CONFIG_IA64_HP_ZX1)
return " hpzx1 " ;
# elif defined (CONFIG_IA64_HP_ZX1_SWIOTLB)
return " hpzx1_swiotlb " ;
# elif defined (CONFIG_IA64_SGI_SN2)
return " sn2 " ;
# elif defined (CONFIG_IA64_DIG)
return " dig " ;
# else
# error Unknown platform. Fix acpi.c.
# endif
# endif
}
2005-08-24 20:07:20 +04:00
# ifdef CONFIG_ACPI
2005-04-17 02:20:36 +04:00
# define ACPI_MAX_PLATFORM_INTERRUPTS 256
/* Array to record platform interrupt vectors for generic interrupt routing. */
int platform_intr_list [ ACPI_MAX_PLATFORM_INTERRUPTS ] = {
[ 0 . . . ACPI_MAX_PLATFORM_INTERRUPTS - 1 ] = - 1
} ;
enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_IOSAPIC ;
/*
* Interrupt routing API for device drivers . Provides interrupt vector for
* a generic platform event . Currently only CPEI is implemented .
*/
2005-08-05 08:44:28 +04:00
int acpi_request_vector ( u32 int_type )
2005-04-17 02:20:36 +04:00
{
int vector = - 1 ;
if ( int_type < ACPI_MAX_PLATFORM_INTERRUPTS ) {
/* corrected platform error interrupt */
vector = platform_intr_list [ int_type ] ;
} else
2005-08-05 08:44:28 +04:00
printk ( KERN_ERR
" acpi_request_vector(): invalid interrupt type \n " ) ;
2005-04-17 02:20:36 +04:00
return vector ;
}
2005-08-05 08:44:28 +04:00
char * __acpi_map_table ( unsigned long phys_addr , unsigned long size )
2005-04-17 02:20:36 +04:00
{
return __va ( phys_addr ) ;
}
/* --------------------------------------------------------------------------
Boot - time Table Parsing
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2005-08-05 08:44:28 +04:00
static int total_cpus __initdata ;
static int available_cpus __initdata ;
struct acpi_table_madt * acpi_madt __initdata ;
static u8 has_8259 ;
2005-04-17 02:20:36 +04:00
static int __init
2005-08-05 08:44:28 +04:00
acpi_parse_lapic_addr_ovr ( acpi_table_entry_header * header ,
const unsigned long end )
2005-04-17 02:20:36 +04:00
{
struct acpi_table_lapic_addr_ovr * lapic ;
2005-08-05 08:44:28 +04:00
lapic = ( struct acpi_table_lapic_addr_ovr * ) header ;
2005-04-17 02:20:36 +04:00
if ( BAD_MADT_ENTRY ( lapic , end ) )
return - EINVAL ;
if ( lapic - > address ) {
iounmap ( ipi_base_addr ) ;
ipi_base_addr = ioremap ( lapic - > address , 0 ) ;
}
return 0 ;
}
static int __init
2005-08-05 08:44:28 +04:00
acpi_parse_lsapic ( acpi_table_entry_header * header , const unsigned long end )
2005-04-17 02:20:36 +04:00
{
struct acpi_table_lsapic * lsapic ;
2005-08-05 08:44:28 +04:00
lsapic = ( struct acpi_table_lsapic * ) header ;
2005-04-17 02:20:36 +04:00
if ( BAD_MADT_ENTRY ( lsapic , end ) )
return - EINVAL ;
if ( lsapic - > flags . enabled ) {
# ifdef CONFIG_SMP
2005-08-05 08:44:28 +04:00
smp_boot_data . cpu_phys_id [ available_cpus ] =
( lsapic - > id < < 8 ) | lsapic - > eid ;
2005-04-17 02:20:36 +04:00
# endif
2005-08-05 08:44:28 +04:00
ia64_acpiid_to_sapicid [ lsapic - > acpi_id ] =
( lsapic - > id < < 8 ) | lsapic - > eid ;
2005-04-17 02:20:36 +04:00
+ + available_cpus ;
}
total_cpus + + ;
return 0 ;
}
static int __init
2005-08-05 08:44:28 +04:00
acpi_parse_lapic_nmi ( acpi_table_entry_header * header , const unsigned long end )
2005-04-17 02:20:36 +04:00
{
struct acpi_table_lapic_nmi * lacpi_nmi ;
2005-08-05 08:44:28 +04:00
lacpi_nmi = ( struct acpi_table_lapic_nmi * ) header ;
2005-04-17 02:20:36 +04:00
if ( BAD_MADT_ENTRY ( lacpi_nmi , end ) )
return - EINVAL ;
/* TBD: Support lapic_nmi entries */
return 0 ;
}
static int __init
2005-08-05 08:44:28 +04:00
acpi_parse_iosapic ( acpi_table_entry_header * header , const unsigned long end )
2005-04-17 02:20:36 +04:00
{
struct acpi_table_iosapic * iosapic ;
2005-08-05 08:44:28 +04:00
iosapic = ( struct acpi_table_iosapic * ) header ;
2005-04-17 02:20:36 +04:00
if ( BAD_MADT_ENTRY ( iosapic , end ) )
return - EINVAL ;
2005-04-28 11:25:58 +04:00
return iosapic_init ( iosapic - > address , iosapic - > global_irq_base ) ;
2005-04-17 02:20:36 +04:00
}
2006-05-13 09:12:15 +04:00
static unsigned int __initdata acpi_madt_rev ;
2005-04-17 02:20:36 +04:00
static int __init
2005-08-05 08:44:28 +04:00
acpi_parse_plat_int_src ( acpi_table_entry_header * header ,
const unsigned long end )
2005-04-17 02:20:36 +04:00
{
struct acpi_table_plat_int_src * plintsrc ;
int vector ;
2005-08-05 08:44:28 +04:00
plintsrc = ( struct acpi_table_plat_int_src * ) header ;
2005-04-17 02:20:36 +04:00
if ( BAD_MADT_ENTRY ( plintsrc , end ) )
return - EINVAL ;
/*
* Get vector assignment for this interrupt , set attributes ,
* and program the IOSAPIC routing table .
*/
vector = iosapic_register_platform_intr ( plintsrc - > type ,
plintsrc - > global_irq ,
plintsrc - > iosapic_vector ,
plintsrc - > eid ,
plintsrc - > id ,
2005-08-05 08:44:28 +04:00
( plintsrc - > flags . polarity = =
1 ) ? IOSAPIC_POL_HIGH :
IOSAPIC_POL_LOW ,
( plintsrc - > flags . trigger = =
1 ) ? IOSAPIC_EDGE :
IOSAPIC_LEVEL ) ;
2005-04-17 02:20:36 +04:00
platform_intr_list [ plintsrc - > type ] = vector ;
2005-04-01 07:51:10 +04:00
if ( acpi_madt_rev > 1 ) {
acpi_cpei_override = plintsrc - > plint_flags . cpei_override_flag ;
}
/*
* Save the physical id , so we can check when its being removed
*/
acpi_cpei_phys_cpuid = ( ( plintsrc - > id < < 8 ) | ( plintsrc - > eid ) ) & 0xffff ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2006-01-20 03:18:47 +03:00
# ifdef CONFIG_HOTPLUG_CPU
2005-04-01 07:51:10 +04:00
unsigned int can_cpei_retarget ( void )
{
extern int cpe_vector ;
2005-11-12 01:32:40 +03:00
extern unsigned int force_cpei_retarget ;
2005-04-01 07:51:10 +04:00
/*
* Only if CPEI is supported and the override flag
* is present , otherwise return that its re - targettable
* if we are in polling mode .
*/
2005-11-12 01:32:40 +03:00
if ( cpe_vector > 0 ) {
if ( acpi_cpei_override | | force_cpei_retarget )
return 1 ;
else
return 0 ;
}
return 1 ;
2005-04-01 07:51:10 +04:00
}
unsigned int is_cpu_cpei_target ( unsigned int cpu )
{
unsigned int logical_id ;
logical_id = cpu_logical_id ( acpi_cpei_phys_cpuid ) ;
if ( logical_id = = cpu )
return 1 ;
else
return 0 ;
}
void set_cpei_target_cpu ( unsigned int cpu )
{
acpi_cpei_phys_cpuid = cpu_physical_id ( cpu ) ;
}
2006-01-20 03:18:47 +03:00
# endif
2005-04-01 07:51:10 +04:00
unsigned int get_cpei_target_cpu ( void )
{
return acpi_cpei_phys_cpuid ;
}
2005-04-17 02:20:36 +04:00
static int __init
2005-08-05 08:44:28 +04:00
acpi_parse_int_src_ovr ( acpi_table_entry_header * header ,
const unsigned long end )
2005-04-17 02:20:36 +04:00
{
struct acpi_table_int_src_ovr * p ;
2005-08-05 08:44:28 +04:00
p = ( struct acpi_table_int_src_ovr * ) header ;
2005-04-17 02:20:36 +04:00
if ( BAD_MADT_ENTRY ( p , end ) )
return - EINVAL ;
iosapic_override_isa_irq ( p - > bus_irq , p - > global_irq ,
2005-08-05 08:44:28 +04:00
( p - > flags . polarity = =
1 ) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW ,
( p - > flags . trigger = =
1 ) ? IOSAPIC_EDGE : IOSAPIC_LEVEL ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int __init
2005-08-05 08:44:28 +04:00
acpi_parse_nmi_src ( acpi_table_entry_header * header , const unsigned long end )
2005-04-17 02:20:36 +04:00
{
struct acpi_table_nmi_src * nmi_src ;
2005-08-05 08:44:28 +04:00
nmi_src = ( struct acpi_table_nmi_src * ) header ;
2005-04-17 02:20:36 +04:00
if ( BAD_MADT_ENTRY ( nmi_src , end ) )
return - EINVAL ;
/* TBD: Support nimsrc entries */
return 0 ;
}
2005-08-05 08:44:28 +04:00
static void __init acpi_madt_oem_check ( char * oem_id , char * oem_table_id )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
if ( ! strncmp ( oem_id , " IBM " , 3 ) & & ( ! strncmp ( oem_table_id , " SERMOW " , 6 ) ) ) {
2005-04-17 02:20:36 +04:00
/*
* Unfortunately ITC_DRIFT is not yet part of the
* official SAL spec , so the ITC_DRIFT bit is not
* set by the BIOS on this hardware .
*/
sal_platform_features | = IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT ;
cyclone_setup ( ) ;
}
}
2005-08-05 08:44:28 +04:00
static int __init acpi_parse_madt ( unsigned long phys_addr , unsigned long size )
2005-04-17 02:20:36 +04:00
{
if ( ! phys_addr | | ! size )
return - EINVAL ;
2005-08-05 08:44:28 +04:00
acpi_madt = ( struct acpi_table_madt * ) __va ( phys_addr ) ;
2005-04-17 02:20:36 +04:00
2005-04-01 07:51:10 +04:00
acpi_madt_rev = acpi_madt - > header . revision ;
2005-04-17 02:20:36 +04:00
/* remember the value for reference after free_initmem() */
# ifdef CONFIG_ITANIUM
2005-08-05 08:44:28 +04:00
has_8259 = 1 ; /* Firmware on old Itanium systems is broken */
2005-04-17 02:20:36 +04:00
# else
has_8259 = acpi_madt - > flags . pcat_compat ;
# endif
iosapic_system_init ( has_8259 ) ;
/* Get base address of IPI Message Block */
if ( acpi_madt - > lapic_address )
ipi_base_addr = ioremap ( acpi_madt - > lapic_address , 0 ) ;
printk ( KERN_INFO PREFIX " Local APIC address %p \n " , ipi_base_addr ) ;
acpi_madt_oem_check ( acpi_madt - > header . oem_id ,
2005-08-05 08:44:28 +04:00
acpi_madt - > header . oem_table_id ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
# ifdef CONFIG_ACPI_NUMA
# undef SLIT_DEBUG
# define PXM_FLAG_LEN ((MAX_PXM_DOMAINS + 1) / 32)
2005-08-05 08:44:28 +04:00
static int __initdata srat_num_cpus ; /* number of cpus */
2005-04-17 02:20:36 +04:00
static u32 __devinitdata pxm_flag [ PXM_FLAG_LEN ] ;
# define pxm_bit_set(bit) (set_bit(bit,(void *)pxm_flag))
# define pxm_bit_test(bit) (test_bit(bit,(void *)pxm_flag))
static struct acpi_table_slit __initdata * slit_table ;
2006-03-03 01:02:25 +03:00
static int get_processor_proximity_domain ( struct acpi_table_processor_affinity * pa )
{
int pxm ;
pxm = pa - > proximity_domain ;
if ( ia64_platform_is ( " sn2 " ) )
pxm + = pa - > reserved [ 0 ] < < 8 ;
return pxm ;
}
static int get_memory_proximity_domain ( struct acpi_table_memory_affinity * ma )
{
int pxm ;
pxm = ma - > proximity_domain ;
if ( ia64_platform_is ( " sn2 " ) )
pxm + = ma - > reserved1 [ 0 ] < < 8 ;
return pxm ;
}
2005-04-17 02:20:36 +04:00
/*
* ACPI 2.0 SLIT ( System Locality Information Table )
* http : //devresource.hp.com/devresource/Docs/TechPapers/IA64/slit.pdf
*/
2005-08-05 08:44:28 +04:00
void __init acpi_numa_slit_init ( struct acpi_table_slit * slit )
2005-04-17 02:20:36 +04:00
{
u32 len ;
len = sizeof ( struct acpi_table_header ) + 8
2005-08-05 08:44:28 +04:00
+ slit - > localities * slit - > localities ;
2005-04-17 02:20:36 +04:00
if ( slit - > header . length ! = len ) {
2005-08-05 08:44:28 +04:00
printk ( KERN_ERR
" ACPI 2.0 SLIT: size mismatch: %d expected, %d actual \n " ,
2005-04-17 02:20:36 +04:00
len , slit - > header . length ) ;
memset ( numa_slit , 10 , sizeof ( numa_slit ) ) ;
return ;
}
slit_table = slit ;
}
void __init
2005-08-05 08:44:28 +04:00
acpi_numa_processor_affinity_init ( struct acpi_table_processor_affinity * pa )
2005-04-17 02:20:36 +04:00
{
2006-03-03 01:02:25 +03:00
int pxm ;
2006-03-15 08:45:11 +03:00
if ( ! pa - > flags . enabled )
return ;
2006-03-03 01:02:25 +03:00
pxm = get_processor_proximity_domain ( pa ) ;
2005-04-17 02:20:36 +04:00
/* record this node in proximity bitmap */
2006-03-03 01:02:25 +03:00
pxm_bit_set ( pxm ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
node_cpuid [ srat_num_cpus ] . phys_id =
( pa - > apic_id < < 8 ) | ( pa - > lsapic_eid ) ;
2005-04-17 02:20:36 +04:00
/* nid should be overridden as logical node id later */
2006-03-03 01:02:25 +03:00
node_cpuid [ srat_num_cpus ] . nid = pxm ;
2005-04-17 02:20:36 +04:00
srat_num_cpus + + ;
}
void __init
2005-08-05 08:44:28 +04:00
acpi_numa_memory_affinity_init ( struct acpi_table_memory_affinity * ma )
2005-04-17 02:20:36 +04:00
{
unsigned long paddr , size ;
2006-03-03 01:02:25 +03:00
int pxm ;
2005-04-17 02:20:36 +04:00
struct node_memblk_s * p , * q , * pend ;
2006-03-03 01:02:25 +03:00
pxm = get_memory_proximity_domain ( ma ) ;
2005-04-17 02:20:36 +04:00
/* fill node memory chunk structure */
paddr = ma - > base_addr_hi ;
paddr = ( paddr < < 32 ) | ma - > base_addr_lo ;
size = ma - > length_hi ;
size = ( size < < 32 ) | ma - > length_lo ;
/* Ignore disabled entries */
if ( ! ma - > flags . enabled )
return ;
/* record this node in proximity bitmap */
pxm_bit_set ( pxm ) ;
/* Insertion sort based on base address */
pend = & node_memblk [ num_node_memblks ] ;
for ( p = & node_memblk [ 0 ] ; p < pend ; p + + ) {
if ( paddr < p - > start_paddr )
break ;
}
if ( p < pend ) {
for ( q = pend - 1 ; q > = p ; q - - )
* ( q + 1 ) = * q ;
}
p - > start_paddr = paddr ;
p - > size = size ;
p - > nid = pxm ;
num_node_memblks + + ;
}
2005-08-05 08:44:28 +04:00
void __init acpi_numa_arch_fixup ( void )
2005-04-17 02:20:36 +04:00
{
int i , j , node_from , node_to ;
/* If there's no SRAT, fix the phys_id and mark node 0 online */
if ( srat_num_cpus = = 0 ) {
node_set_online ( 0 ) ;
node_cpuid [ 0 ] . phys_id = hard_smp_processor_id ( ) ;
return ;
}
/*
* MCD - This can probably be dropped now . No need for pxm ID to node ID
* mapping with sparse node numbering iff MAX_PXM_DOMAINS < = MAX_NUMNODES .
*/
nodes_clear ( node_online_map ) ;
for ( i = 0 ; i < MAX_PXM_DOMAINS ; i + + ) {
if ( pxm_bit_test ( i ) ) {
2006-06-23 13:03:19 +04:00
int nid = acpi_map_pxm_to_node ( i ) ;
2005-04-17 02:20:36 +04:00
node_set_online ( nid ) ;
}
}
/* set logical node id in memory chunk structure */
for ( i = 0 ; i < num_node_memblks ; i + + )
2006-06-23 13:03:19 +04:00
node_memblk [ i ] . nid = pxm_to_node ( node_memblk [ i ] . nid ) ;
2005-04-17 02:20:36 +04:00
/* assign memory bank numbers for each chunk on each node */
for_each_online_node ( i ) {
int bank ;
bank = 0 ;
for ( j = 0 ; j < num_node_memblks ; j + + )
if ( node_memblk [ j ] . nid = = i )
node_memblk [ j ] . bank = bank + + ;
}
/* set logical node id in cpu structure */
for ( i = 0 ; i < srat_num_cpus ; i + + )
2006-06-23 13:03:19 +04:00
node_cpuid [ i ] . nid = pxm_to_node ( node_cpuid [ i ] . nid ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
printk ( KERN_INFO " Number of logical nodes in system = %d \n " ,
num_online_nodes ( ) ) ;
printk ( KERN_INFO " Number of memory chunks in system = %d \n " ,
num_node_memblks ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
if ( ! slit_table )
return ;
2005-04-17 02:20:36 +04:00
memset ( numa_slit , - 1 , sizeof ( numa_slit ) ) ;
2005-08-05 08:44:28 +04:00
for ( i = 0 ; i < slit_table - > localities ; i + + ) {
2005-04-17 02:20:36 +04:00
if ( ! pxm_bit_test ( i ) )
continue ;
2006-06-23 13:03:19 +04:00
node_from = pxm_to_node ( i ) ;
2005-08-05 08:44:28 +04:00
for ( j = 0 ; j < slit_table - > localities ; j + + ) {
2005-04-17 02:20:36 +04:00
if ( ! pxm_bit_test ( j ) )
continue ;
2006-06-23 13:03:19 +04:00
node_to = pxm_to_node ( j ) ;
2005-04-17 02:20:36 +04:00
node_distance ( node_from , node_to ) =
2005-08-05 08:44:28 +04:00
slit_table - > entry [ i * slit_table - > localities + j ] ;
2005-04-17 02:20:36 +04:00
}
}
# ifdef SLIT_DEBUG
printk ( " ACPI 2.0 SLIT locality table: \n " ) ;
for_each_online_node ( i ) {
for_each_online_node ( j )
2005-08-05 08:44:28 +04:00
printk ( " %03d " , node_distance ( i , j ) ) ;
2005-04-17 02:20:36 +04:00
printk ( " \n " ) ;
}
# endif
}
2005-08-05 08:44:28 +04:00
# endif /* CONFIG_ACPI_NUMA */
2005-04-17 02:20:36 +04:00
2005-07-28 22:42:00 +04:00
/*
* success : return IRQ number ( > = 0 )
* failure : return < 0
*/
2005-12-28 10:43:51 +03:00
int acpi_register_gsi ( u32 gsi , int triggering , int polarity )
2005-04-17 02:20:36 +04:00
{
if ( has_8259 & & gsi < 16 )
return isa_irq_to_vector ( gsi ) ;
return iosapic_register_intr ( gsi ,
2005-12-28 10:43:51 +03:00
( polarity = =
2005-08-05 08:44:28 +04:00
ACPI_ACTIVE_HIGH ) ? IOSAPIC_POL_HIGH :
IOSAPIC_POL_LOW ,
2005-12-28 10:43:51 +03:00
( triggering = =
2005-08-05 08:44:28 +04:00
ACPI_EDGE_SENSITIVE ) ? IOSAPIC_EDGE :
IOSAPIC_LEVEL ) ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( acpi_register_gsi ) ;
2005-08-05 08:44:28 +04:00
void acpi_unregister_gsi ( u32 gsi )
2005-04-17 02:20:36 +04:00
{
iosapic_unregister_intr ( gsi ) ;
}
2005-08-05 08:44:28 +04:00
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( acpi_unregister_gsi ) ;
2005-08-05 08:44:28 +04:00
static int __init acpi_parse_fadt ( unsigned long phys_addr , unsigned long size )
2005-04-17 02:20:36 +04:00
{
struct acpi_table_header * fadt_header ;
2006-06-24 00:49:25 +04:00
struct fadt_descriptor * fadt ;
2005-04-17 02:20:36 +04:00
if ( ! phys_addr | | ! size )
return - EINVAL ;
2005-08-05 08:44:28 +04:00
fadt_header = ( struct acpi_table_header * ) __va ( phys_addr ) ;
2005-04-17 02:20:36 +04:00
if ( fadt_header - > revision ! = 3 )
2005-08-05 08:44:28 +04:00
return - ENODEV ; /* Only deal with ACPI 2.0 FADT */
2005-04-17 02:20:36 +04:00
2006-06-24 00:49:25 +04:00
fadt = ( struct fadt_descriptor * ) fadt_header ;
2005-04-17 02:20:36 +04:00
if ( ! ( fadt - > iapc_boot_arch & BAF_8042_KEYBOARD_CONTROLLER ) )
acpi_kbd_controller_present = 0 ;
if ( fadt - > iapc_boot_arch & BAF_LEGACY_DEVICES )
acpi_legacy_devices = 1 ;
acpi_register_gsi ( fadt - > sci_int , ACPI_LEVEL_SENSITIVE , ACPI_ACTIVE_LOW ) ;
return 0 ;
}
2005-08-05 08:44:28 +04:00
unsigned long __init acpi_find_rsdp ( void )
2005-04-17 02:20:36 +04:00
{
unsigned long rsdp_phys = 0 ;
2006-03-26 13:37:08 +04:00
if ( efi . acpi20 ! = EFI_INVALID_TABLE_ADDR )
rsdp_phys = efi . acpi20 ;
else if ( efi . acpi ! = EFI_INVALID_TABLE_ADDR )
2005-08-05 08:44:28 +04:00
printk ( KERN_WARNING PREFIX
" v1.0/r0.71 tables no longer supported \n " ) ;
2005-04-17 02:20:36 +04:00
return rsdp_phys ;
}
2005-08-05 08:44:28 +04:00
int __init acpi_boot_init ( void )
2005-04-17 02:20:36 +04:00
{
/*
* MADT
* - - - -
* Parse the Multiple APIC Description Table ( MADT ) , if exists .
* Note that this table provides platform SMP configuration
* information - - the successor to MPS tables .
*/
if ( acpi_table_parse ( ACPI_APIC , acpi_parse_madt ) < 1 ) {
printk ( KERN_ERR PREFIX " Can't find MADT \n " ) ;
goto skip_madt ;
}
/* Local APIC */
2005-08-05 08:44:28 +04:00
if ( acpi_table_parse_madt
( ACPI_MADT_LAPIC_ADDR_OVR , acpi_parse_lapic_addr_ovr , 0 ) < 0 )
printk ( KERN_ERR PREFIX
" Error parsing LAPIC address override entry \n " ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
if ( acpi_table_parse_madt ( ACPI_MADT_LSAPIC , acpi_parse_lsapic , NR_CPUS )
< 1 )
printk ( KERN_ERR PREFIX
" Error parsing MADT - no LAPIC entries \n " ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
if ( acpi_table_parse_madt ( ACPI_MADT_LAPIC_NMI , acpi_parse_lapic_nmi , 0 )
< 0 )
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR PREFIX " Error parsing LAPIC NMI entry \n " ) ;
/* I/O APIC */
2005-08-05 08:44:28 +04:00
if ( acpi_table_parse_madt
( ACPI_MADT_IOSAPIC , acpi_parse_iosapic , NR_IOSAPICS ) < 1 )
printk ( KERN_ERR PREFIX
" Error parsing MADT - no IOSAPIC entries \n " ) ;
2005-04-17 02:20:36 +04:00
/* System-Level Interrupt Routing */
2005-08-05 08:44:28 +04:00
if ( acpi_table_parse_madt
( ACPI_MADT_PLAT_INT_SRC , acpi_parse_plat_int_src ,
ACPI_MAX_PLATFORM_INTERRUPTS ) < 0 )
printk ( KERN_ERR PREFIX
" Error parsing platform interrupt source entry \n " ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
if ( acpi_table_parse_madt
( ACPI_MADT_INT_SRC_OVR , acpi_parse_int_src_ovr , 0 ) < 0 )
printk ( KERN_ERR PREFIX
" Error parsing interrupt source overrides entry \n " ) ;
2005-04-17 02:20:36 +04:00
if ( acpi_table_parse_madt ( ACPI_MADT_NMI_SRC , acpi_parse_nmi_src , 0 ) < 0 )
printk ( KERN_ERR PREFIX " Error parsing NMI SRC entry \n " ) ;
2005-08-05 08:44:28 +04:00
skip_madt :
2005-04-17 02:20:36 +04:00
/*
* FADT says whether a legacy keyboard controller is present .
* The FADT also contains an SCI_INT line , by which the system
* gets interrupts such as power and sleep buttons . If it ' s not
* on a Legacy interrupt , it needs to be setup .
*/
if ( acpi_table_parse ( ACPI_FADT , acpi_parse_fadt ) < 1 )
printk ( KERN_ERR PREFIX " Can't find FADT \n " ) ;
# ifdef CONFIG_SMP
if ( available_cpus = = 0 ) {
printk ( KERN_INFO " ACPI: Found 0 CPUS; assuming 1 \n " ) ;
printk ( KERN_INFO " CPU 0 (0x%04x) " , hard_smp_processor_id ( ) ) ;
2005-08-05 08:44:28 +04:00
smp_boot_data . cpu_phys_id [ available_cpus ] =
hard_smp_processor_id ( ) ;
available_cpus = 1 ; /* We've got at least one of these, no? */
2005-04-17 02:20:36 +04:00
}
smp_boot_data . cpu_count = available_cpus ;
smp_build_cpu_map ( ) ;
# ifdef CONFIG_ACPI_NUMA
if ( srat_num_cpus = = 0 ) {
int cpu , i = 1 ;
for ( cpu = 0 ; cpu < smp_boot_data . cpu_count ; cpu + + )
2005-08-05 08:44:28 +04:00
if ( smp_boot_data . cpu_phys_id [ cpu ] ! =
hard_smp_processor_id ( ) )
node_cpuid [ i + + ] . phys_id =
smp_boot_data . cpu_phys_id [ cpu ] ;
2005-04-17 02:20:36 +04:00
}
# endif
2005-07-07 05:18:10 +04:00
# endif
# ifdef CONFIG_ACPI_NUMA
build_cpu_to_node_map ( ) ;
2005-04-17 02:20:36 +04:00
# endif
/* Make boot-up look pretty */
2005-08-05 08:44:28 +04:00
printk ( KERN_INFO " %d CPUs available, %d CPUs total \n " , available_cpus ,
total_cpus ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2005-08-05 08:44:28 +04:00
int acpi_gsi_to_irq ( u32 gsi , unsigned int * irq )
2005-04-17 02:20:36 +04:00
{
int vector ;
if ( has_8259 & & gsi < 16 )
* irq = isa_irq_to_vector ( gsi ) ;
else {
vector = gsi_to_vector ( gsi ) ;
if ( vector = = - 1 )
return - 1 ;
* irq = vector ;
}
return 0 ;
}
/*
* ACPI based hotplug CPU support
*/
# ifdef CONFIG_ACPI_HOTPLUG_CPU
static
2005-08-05 08:44:28 +04:00
int acpi_map_cpu2node ( acpi_handle handle , int cpu , long physid )
2005-04-17 02:20:36 +04:00
{
# ifdef CONFIG_ACPI_NUMA
2005-08-05 08:44:28 +04:00
int pxm_id ;
2005-04-17 02:20:36 +04:00
pxm_id = acpi_get_pxm ( handle ) ;
/*
* Assuming that the container driver would have set the proximity
2006-06-23 13:03:19 +04:00
* domain and would have initialized pxm_to_node ( pxm_id ) & & pxm_flag
2005-04-17 02:20:36 +04:00
*/
2006-06-23 13:03:19 +04:00
node_cpuid [ cpu ] . nid = ( pxm_id < 0 ) ? 0 : pxm_to_node ( pxm_id ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
node_cpuid [ cpu ] . phys_id = physid ;
2005-04-17 02:20:36 +04:00
# endif
2005-08-05 08:44:28 +04:00
return ( 0 ) ;
2005-04-17 02:20:36 +04:00
}
2006-02-15 02:01:12 +03:00
int additional_cpus __initdata = - 1 ;
static __init int setup_additional_cpus ( char * s )
{
if ( s )
additional_cpus = simple_strtol ( s , NULL , 0 ) ;
return 0 ;
}
early_param ( " additional_cpus " , setup_additional_cpus ) ;
/*
* cpu_possible_map should be static , it cannot change as cpu ' s
* are onlined , or offlined . The reason is per - cpu data - structures
* are allocated by some modules at init time , and dont expect to
* do this dynamically on cpu arrival / departure .
* cpu_present_map on the other hand can change dynamically .
* In case when cpu_hotplug is not compiled , then we resort to current
* behaviour , which is cpu_possible = = cpu_present .
* - Ashok Raj
*
* Three ways to find out the number of additional hotplug CPUs :
* - If the BIOS specified disabled CPUs in ACPI / mptables use that .
* - The user can overwrite it with additional_cpus = NUM
* - Otherwise don ' t reserve additional CPUs .
*/
__init void prefill_possible_map ( void )
{
int i ;
int possible , disabled_cpus ;
disabled_cpus = total_cpus - available_cpus ;
2006-02-17 01:01:48 +03:00
2006-02-15 02:01:12 +03:00
if ( additional_cpus = = - 1 ) {
2006-02-17 01:01:48 +03:00
if ( disabled_cpus > 0 )
2006-02-15 02:01:12 +03:00
additional_cpus = disabled_cpus ;
2006-02-17 01:01:48 +03:00
else
2006-02-15 02:01:12 +03:00
additional_cpus = 0 ;
2006-02-17 01:01:48 +03:00
}
possible = available_cpus + additional_cpus ;
2006-02-15 02:01:12 +03:00
if ( possible > NR_CPUS )
possible = NR_CPUS ;
printk ( KERN_INFO " SMP: Allowing %d CPUs, %d hotplug CPUs \n " ,
2006-02-17 01:01:48 +03:00
possible , max ( ( possible - available_cpus ) , 0 ) ) ;
2006-02-15 02:01:12 +03:00
for ( i = 0 ; i < possible ; i + + )
cpu_set ( i , cpu_possible_map ) ;
}
2005-08-05 08:44:28 +04:00
int acpi_map_lsapic ( acpi_handle handle , int * pcpu )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER , NULL } ;
2005-04-17 02:20:36 +04:00
union acpi_object * obj ;
struct acpi_table_lsapic * lsapic ;
cpumask_t tmp_map ;
long physid ;
int cpu ;
2005-08-05 08:44:28 +04:00
2005-04-17 02:20:36 +04:00
if ( ACPI_FAILURE ( acpi_evaluate_object ( handle , " _MAT " , NULL , & buffer ) ) )
return - EINVAL ;
2005-08-05 08:44:28 +04:00
if ( ! buffer . length | | ! buffer . pointer )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2005-08-05 08:44:28 +04:00
2005-04-17 02:20:36 +04:00
obj = buffer . pointer ;
if ( obj - > type ! = ACPI_TYPE_BUFFER | |
obj - > buffer . length < sizeof ( * lsapic ) ) {
acpi_os_free ( buffer . pointer ) ;
return - EINVAL ;
}
lsapic = ( struct acpi_table_lsapic * ) obj - > buffer . pointer ;
if ( ( lsapic - > header . type ! = ACPI_MADT_LSAPIC ) | |
( ! lsapic - > flags . enabled ) ) {
acpi_os_free ( buffer . pointer ) ;
return - EINVAL ;
}
2005-08-05 08:44:28 +04:00
physid = ( ( lsapic - > id < < 8 ) | ( lsapic - > eid ) ) ;
2005-04-17 02:20:36 +04:00
acpi_os_free ( buffer . pointer ) ;
buffer . length = ACPI_ALLOCATE_BUFFER ;
buffer . pointer = NULL ;
cpus_complement ( tmp_map , cpu_present_map ) ;
cpu = first_cpu ( tmp_map ) ;
2005-08-05 08:44:28 +04:00
if ( cpu > = NR_CPUS )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
acpi_map_cpu2node ( handle , cpu , physid ) ;
2005-08-05 08:44:28 +04:00
cpu_set ( cpu , cpu_present_map ) ;
2005-04-17 02:20:36 +04:00
ia64_cpu_to_sapicid [ cpu ] = physid ;
ia64_acpiid_to_sapicid [ lsapic - > acpi_id ] = ia64_cpu_to_sapicid [ cpu ] ;
* pcpu = cpu ;
2005-08-05 08:44:28 +04:00
return ( 0 ) ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
EXPORT_SYMBOL ( acpi_map_lsapic ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
int acpi_unmap_lsapic ( int cpu )
2005-04-17 02:20:36 +04:00
{
int i ;
2005-08-05 08:44:28 +04:00
for ( i = 0 ; i < MAX_SAPICS ; i + + ) {
if ( ia64_acpiid_to_sapicid [ i ] = = ia64_cpu_to_sapicid [ cpu ] ) {
ia64_acpiid_to_sapicid [ i ] = - 1 ;
break ;
}
}
2005-04-17 02:20:36 +04:00
ia64_cpu_to_sapicid [ cpu ] = - 1 ;
2005-08-05 08:44:28 +04:00
cpu_clear ( cpu , cpu_present_map ) ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_ACPI_NUMA
/* NUMA specific cleanup's */
# endif
2005-08-05 08:44:28 +04:00
return ( 0 ) ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( acpi_unmap_lsapic ) ;
2005-08-05 08:44:28 +04:00
# endif /* CONFIG_ACPI_HOTPLUG_CPU */
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_ACPI_NUMA
2005-09-16 21:43:45 +04:00
static acpi_status __devinit
2005-08-05 08:44:28 +04:00
acpi_map_iosapic ( acpi_handle handle , u32 depth , void * context , void * * ret )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER , NULL } ;
2005-04-17 02:20:36 +04:00
union acpi_object * obj ;
struct acpi_table_iosapic * iosapic ;
unsigned int gsi_base ;
2005-03-25 08:58:00 +03:00
int pxm , node ;
2005-04-17 02:20:36 +04:00
/* Only care about objects w/ a method that returns the MADT */
if ( ACPI_FAILURE ( acpi_evaluate_object ( handle , " _MAT " , NULL , & buffer ) ) )
return AE_OK ;
if ( ! buffer . length | | ! buffer . pointer )
return AE_OK ;
obj = buffer . pointer ;
if ( obj - > type ! = ACPI_TYPE_BUFFER | |
obj - > buffer . length < sizeof ( * iosapic ) ) {
acpi_os_free ( buffer . pointer ) ;
return AE_OK ;
}
iosapic = ( struct acpi_table_iosapic * ) obj - > buffer . pointer ;
if ( iosapic - > header . type ! = ACPI_MADT_IOSAPIC ) {
acpi_os_free ( buffer . pointer ) ;
return AE_OK ;
}
gsi_base = iosapic - > global_irq_base ;
acpi_os_free ( buffer . pointer ) ;
/*
2005-03-25 08:58:00 +03:00
* OK , it ' s an IOSAPIC MADT entry , look for a _PXM value to tell
2005-04-17 02:20:36 +04:00
* us which node to associate this with .
*/
2005-03-25 08:58:00 +03:00
pxm = acpi_get_pxm ( handle ) ;
if ( pxm < 0 )
2005-04-17 02:20:36 +04:00
return AE_OK ;
2006-06-23 13:03:19 +04:00
node = pxm_to_node ( pxm ) ;
2005-04-17 02:20:36 +04:00
if ( node > = MAX_NUMNODES | | ! node_online ( node ) | |
cpus_empty ( node_to_cpumask ( node ) ) )
return AE_OK ;
/* We know a gsi to node mapping! */
map_iosapic_to_node ( gsi_base , node ) ;
return AE_OK ;
}
2005-09-16 21:43:45 +04:00
static int __init
acpi_map_iosapics ( void )
{
acpi_get_devices ( NULL , acpi_map_iosapic , NULL , NULL ) ;
return 0 ;
}
fs_initcall ( acpi_map_iosapics ) ;
# endif /* CONFIG_ACPI_NUMA */
2005-04-28 11:25:58 +04:00
2005-08-05 08:44:28 +04:00
int acpi_register_ioapic ( acpi_handle handle , u64 phys_addr , u32 gsi_base )
2005-04-28 11:25:58 +04:00
{
2005-04-28 11:25:58 +04:00
int err ;
if ( ( err = iosapic_init ( phys_addr , gsi_base ) ) )
return err ;
2005-09-15 09:36:35 +04:00
# ifdef CONFIG_ACPI_NUMA
2005-04-28 11:25:58 +04:00
acpi_map_iosapic ( handle , 0 , NULL , NULL ) ;
2005-08-05 08:44:28 +04:00
# endif /* CONFIG_ACPI_NUMA */
2005-04-28 11:25:58 +04:00
return 0 ;
2005-04-28 11:25:58 +04:00
}
2005-08-05 08:44:28 +04:00
2005-04-28 11:25:58 +04:00
EXPORT_SYMBOL ( acpi_register_ioapic ) ;
2005-08-05 08:44:28 +04:00
int acpi_unregister_ioapic ( acpi_handle handle , u32 gsi_base )
2005-04-28 11:25:58 +04:00
{
2005-04-28 11:25:58 +04:00
return iosapic_remove ( gsi_base ) ;
2005-04-28 11:25:58 +04:00
}
2005-08-05 08:44:28 +04:00
2005-04-28 11:25:58 +04:00
EXPORT_SYMBOL ( acpi_unregister_ioapic ) ;
2005-08-24 20:07:20 +04:00
# endif /* CONFIG_ACPI */