2005-04-16 15:20:36 -07:00
/*
* boot . c - Architecture - Specific Low - Level ACPI Boot Support
*
* Copyright ( C ) 2001 , 2002 Paul Diefenbaugh < paul . s . diefenbaugh @ intel . com >
* Copyright ( C ) 2001 Jun Nakajima < jun . nakajima @ intel . 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/init.h>
# include <linux/acpi.h>
2007-02-16 01:27:57 -08:00
# include <linux/acpi_pmtmr.h>
2005-04-16 15:20:36 -07:00
# include <linux/efi.h>
2006-09-26 10:52:35 +02:00
# include <linux/cpumask.h>
2005-04-16 15:20:36 -07:00
# include <linux/module.h>
2005-06-25 14:54:42 -07:00
# include <linux/dmi.h>
2005-10-01 02:34:42 +10:00
# include <linux/irq.h>
2006-09-26 10:52:39 +02:00
# include <linux/bootmem.h>
# include <linux/ioport.h>
2005-04-16 15:20:36 -07:00
# include <asm/pgtable.h>
# include <asm/io_apic.h>
# include <asm/apic.h>
# include <asm/io.h>
# include <asm/mpspec.h>
2006-09-26 10:52:35 +02:00
static int __initdata acpi_force = 0 ;
2006-09-26 10:52:32 +02:00
2006-09-26 10:52:33 +02:00
# ifdef CONFIG_ACPI
int acpi_disabled = 0 ;
# else
int acpi_disabled = 1 ;
# endif
EXPORT_SYMBOL ( acpi_disabled ) ;
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_X86_64
# include <asm/proto.h>
2006-02-27 20:41:56 -08:00
static inline int acpi_madt_oem_check ( char * oem_id , char * oem_table_id ) { return 0 ; }
2005-08-05 00:44:28 -04:00
# else /* X86 */
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_X86_LOCAL_APIC
# include <mach_apic.h>
# include <mach_mpparse.h>
2005-08-05 00:44:28 -04:00
# endif /* CONFIG_X86_LOCAL_APIC */
2005-04-16 15:20:36 -07:00
2005-08-05 00:44:28 -04:00
# endif /* X86 */
2005-04-16 15:20:36 -07:00
# define BAD_MADT_ENTRY(entry, end) ( \
( ! entry ) | | ( unsigned long ) entry + sizeof ( * entry ) > end | | \
2007-02-02 19:48:22 +03:00
( ( struct acpi_subtable_header * ) entry ) - > length < sizeof ( * entry ) )
2005-04-16 15:20:36 -07:00
# define PREFIX "ACPI: "
2006-11-02 22:07:18 -08:00
int acpi_noirq ; /* skip ACPI IRQ initialization */
2005-08-05 00:44:28 -04:00
int acpi_pci_disabled __initdata ; /* skip ACPI PCI scan and IRQ initialization */
2005-04-16 15:20:36 -07:00
int acpi_ht __initdata = 1 ; /* enable HT */
int acpi_lapic ;
int acpi_ioapic ;
int acpi_strict ;
EXPORT_SYMBOL ( acpi_strict ) ;
2007-02-02 19:48:22 +03:00
u8 acpi_sci_flags __initdata ;
2005-04-16 15:20:36 -07:00
int acpi_sci_override_gsi __initdata ;
int acpi_skip_timer_override __initdata ;
2006-11-14 16:57:46 +01:00
int acpi_use_timer_override __initdata ;
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_X86_LOCAL_APIC
static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE ;
# endif
# ifndef __HAVE_ARCH_CMPXCHG
# warning ACPI uses CMPXCHG, i486 and later hardware
# endif
/* --------------------------------------------------------------------------
Boot - time Configuration
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* The default interrupt routing model is PIC ( 8259 ) . This gets
* overriden if IOAPICs are enumerated ( below ) .
*/
2005-08-05 00:44:28 -04:00
enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_PIC ;
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_X86_64
/* rely on all ACPI tables being in the direct mapping */
char * __acpi_map_table ( unsigned long phys_addr , unsigned long size )
{
if ( ! phys_addr | | ! size )
2005-08-05 00:44:28 -04:00
return NULL ;
2005-04-16 15:20:36 -07:00
2006-01-11 22:43:39 +01:00
if ( phys_addr + size < = ( end_pfn_map < < PAGE_SHIFT ) + PAGE_SIZE )
2005-04-16 15:20:36 -07:00
return __va ( phys_addr ) ;
return NULL ;
}
# else
/*
* Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END ,
* to map the target physical address . The problem is that set_fixmap ( )
* provides a single page , and it is possible that the page is not
* sufficient .
* By using this area , we can map up to MAX_IO_APICS pages temporarily ,
* i . e . until the next __va_range ( ) call .
*
* Important Safety Note : The fixed I / O APIC page numbers are * subtracted *
* from the fixed base . That ' s why we start at FIX_IO_APIC_BASE_END and
* count idx down while incrementing the phys address .
*/
char * __acpi_map_table ( unsigned long phys , unsigned long size )
{
unsigned long base , offset , mapped_size ;
int idx ;
2005-08-05 00:44:28 -04:00
if ( phys + size < 8 * 1024 * 1024 )
return __va ( phys ) ;
2005-04-16 15:20:36 -07:00
offset = phys & ( PAGE_SIZE - 1 ) ;
mapped_size = PAGE_SIZE - offset ;
set_fixmap ( FIX_ACPI_END , phys ) ;
base = fix_to_virt ( FIX_ACPI_END ) ;
/*
* Most cases can be covered by the below .
*/
idx = FIX_ACPI_END ;
while ( mapped_size < size ) {
if ( - - idx < FIX_ACPI_BEGIN )
return NULL ; /* cannot handle this */
phys + = PAGE_SIZE ;
set_fixmap ( idx , phys ) ;
mapped_size + = PAGE_SIZE ;
}
2005-08-05 00:44:28 -04:00
return ( ( unsigned char * ) base + offset ) ;
2005-04-16 15:20:36 -07:00
}
# endif
# ifdef CONFIG_PCI_MMCONFIG
2005-06-23 17:35:56 -07:00
/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */
2007-02-02 19:48:22 +03:00
struct acpi_mcfg_allocation * pci_mmcfg_config ;
2005-06-23 17:35:56 -07:00
int pci_mmcfg_config_num ;
2007-02-02 19:48:22 +03:00
int __init acpi_parse_mcfg ( struct acpi_table_header * header )
2005-04-16 15:20:36 -07:00
{
struct acpi_table_mcfg * mcfg ;
2005-06-23 17:35:56 -07:00
unsigned long i ;
int config_size ;
2005-04-16 15:20:36 -07:00
2007-02-02 19:48:22 +03:00
if ( ! header )
2005-04-16 15:20:36 -07:00
return - EINVAL ;
2007-02-02 19:48:22 +03:00
mcfg = ( struct acpi_table_mcfg * ) header ;
2005-04-16 15:20:36 -07:00
2005-06-23 17:35:56 -07:00
/* how many config structures do we have */
pci_mmcfg_config_num = 0 ;
2007-02-02 19:48:22 +03:00
i = header - > length - sizeof ( struct acpi_table_mcfg ) ;
2007-02-02 19:48:22 +03:00
while ( i > = sizeof ( struct acpi_mcfg_allocation ) ) {
2005-06-23 17:35:56 -07:00
+ + pci_mmcfg_config_num ;
2007-02-02 19:48:22 +03:00
i - = sizeof ( struct acpi_mcfg_allocation ) ;
2005-06-23 17:35:56 -07:00
} ;
if ( pci_mmcfg_config_num = = 0 ) {
printk ( KERN_ERR PREFIX " MMCONFIG has no entries \n " ) ;
2005-04-16 15:20:36 -07:00
return - ENODEV ;
}
2005-06-23 17:35:56 -07:00
config_size = pci_mmcfg_config_num * sizeof ( * pci_mmcfg_config ) ;
pci_mmcfg_config = kmalloc ( config_size , GFP_KERNEL ) ;
if ( ! pci_mmcfg_config ) {
printk ( KERN_WARNING PREFIX
" No memory for MCFG config tables \n " ) ;
return - ENOMEM ;
}
2007-02-02 19:48:22 +03:00
memcpy ( pci_mmcfg_config , & mcfg [ 1 ] , config_size ) ;
2005-06-23 17:35:56 -07:00
for ( i = 0 ; i < pci_mmcfg_config_num ; + + i ) {
2007-02-02 19:48:22 +03:00
if ( pci_mmcfg_config [ i ] . address > 0xFFFFFFFF ) {
2005-06-23 17:35:56 -07:00
printk ( KERN_ERR PREFIX
" MMCONFIG not in low 4GB of memory \n " ) ;
2006-06-15 12:08:30 -04:00
kfree ( pci_mmcfg_config ) ;
pci_mmcfg_config_num = 0 ;
2005-06-23 17:35:56 -07:00
return - ENODEV ;
}
}
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-08-05 00:44:28 -04:00
# endif /* CONFIG_PCI_MMCONFIG */
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_X86_LOCAL_APIC
2007-02-02 19:48:22 +03:00
static int __init acpi_parse_madt ( struct acpi_table_header * table )
2005-04-16 15:20:36 -07:00
{
2005-08-05 00:44:28 -04:00
struct acpi_table_madt * madt = NULL ;
2005-04-16 15:20:36 -07:00
2007-02-02 19:48:22 +03:00
if ( ! cpu_has_apic )
2005-04-16 15:20:36 -07:00
return - EINVAL ;
2007-02-02 19:48:22 +03:00
madt = ( struct acpi_table_madt * ) table ;
2005-04-16 15:20:36 -07:00
if ( ! madt ) {
printk ( KERN_WARNING PREFIX " Unable to map MADT \n " ) ;
return - ENODEV ;
}
2007-02-02 19:48:22 +03:00
if ( madt - > address ) {
acpi_lapic_addr = ( u64 ) madt - > address ;
2005-04-16 15:20:36 -07:00
printk ( KERN_DEBUG PREFIX " Local APIC address 0x%08x \n " ,
2007-02-02 19:48:22 +03:00
madt - > address ) ;
2005-04-16 15:20:36 -07:00
}
acpi_madt_oem_check ( madt - > header . oem_id , madt - > header . oem_table_id ) ;
2005-08-05 00:44:28 -04:00
2005-04-16 15:20:36 -07:00
return 0 ;
}
static int __init
2007-02-02 19:48:22 +03:00
acpi_parse_lapic ( struct acpi_subtable_header * header , const unsigned long end )
2005-04-16 15:20:36 -07:00
{
2007-02-02 19:48:22 +03:00
struct acpi_madt_local_apic * processor = NULL ;
2005-04-16 15:20:36 -07:00
2007-02-02 19:48:22 +03:00
processor = ( struct acpi_madt_local_apic * ) header ;
2005-04-16 15:20:36 -07:00
if ( BAD_MADT_ENTRY ( processor , end ) )
return - EINVAL ;
acpi_table_print_madt_entry ( header ) ;
2006-02-03 21:51:50 +01:00
/*
* We need to register disabled CPU as well to permit
* counting disabled CPUs . This allows us to size
* cpus_possible_map more accurately , to permit
* to not preallocating memory for all NR_CPUS
* when we use CPU hotplug .
*/
2005-08-05 00:44:28 -04:00
mp_register_lapic ( processor - > id , /* APIC ID */
2007-02-02 19:48:22 +03:00
processor - > lapic_flags & ACPI_MADT_ENABLED ) ; /* Enabled? */
2005-04-16 15:20:36 -07:00
return 0 ;
}
static int __init
2007-02-02 19:48:22 +03:00
acpi_parse_lapic_addr_ovr ( struct acpi_subtable_header * header ,
2005-08-05 00:44:28 -04:00
const unsigned long end )
2005-04-16 15:20:36 -07:00
{
2007-02-02 19:48:22 +03:00
struct acpi_madt_local_apic_override * lapic_addr_ovr = NULL ;
2005-04-16 15:20:36 -07:00
2007-02-02 19:48:22 +03:00
lapic_addr_ovr = ( struct acpi_madt_local_apic_override * ) header ;
2005-04-16 15:20:36 -07:00
if ( BAD_MADT_ENTRY ( lapic_addr_ovr , end ) )
return - EINVAL ;
acpi_lapic_addr = lapic_addr_ovr - > address ;
return 0 ;
}
static int __init
2007-02-02 19:48:22 +03:00
acpi_parse_lapic_nmi ( struct acpi_subtable_header * header , const unsigned long end )
2005-04-16 15:20:36 -07:00
{
2007-02-02 19:48:22 +03:00
struct acpi_madt_local_apic_nmi * lapic_nmi = NULL ;
2005-04-16 15:20:36 -07:00
2007-02-02 19:48:22 +03:00
lapic_nmi = ( struct acpi_madt_local_apic_nmi * ) header ;
2005-04-16 15:20:36 -07:00
if ( BAD_MADT_ENTRY ( lapic_nmi , end ) )
return - EINVAL ;
acpi_table_print_madt_entry ( header ) ;
if ( lapic_nmi - > lint ! = 1 )
printk ( KERN_WARNING PREFIX " NMI not connected to LINT 1! \n " ) ;
return 0 ;
}
2005-08-05 00:44:28 -04:00
# endif /*CONFIG_X86_LOCAL_APIC */
2005-04-16 15:20:36 -07:00
2005-08-24 12:09:07 -04:00
# ifdef CONFIG_X86_IO_APIC
2005-04-16 15:20:36 -07:00
static int __init
2007-02-02 19:48:22 +03:00
acpi_parse_ioapic ( struct acpi_subtable_header * header , const unsigned long end )
2005-04-16 15:20:36 -07:00
{
2007-02-02 19:48:22 +03:00
struct acpi_madt_io_apic * ioapic = NULL ;
2005-04-16 15:20:36 -07:00
2007-02-02 19:48:22 +03:00
ioapic = ( struct acpi_madt_io_apic * ) header ;
2005-04-16 15:20:36 -07:00
if ( BAD_MADT_ENTRY ( ioapic , end ) )
return - EINVAL ;
2005-08-05 00:44:28 -04:00
2005-04-16 15:20:36 -07:00
acpi_table_print_madt_entry ( header ) ;
2005-08-05 00:44:28 -04:00
mp_register_ioapic ( ioapic - > id ,
ioapic - > address , ioapic - > global_irq_base ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
/*
* Parse Interrupt Source Override for the ACPI SCI
*/
2006-12-21 01:29:59 -05:00
static void __init acpi_sci_ioapic_setup ( u32 gsi , u16 polarity , u16 trigger )
2005-04-16 15:20:36 -07:00
{
if ( trigger = = 0 ) /* compatible SCI trigger is level */
trigger = 3 ;
if ( polarity = = 0 ) /* compatible SCI polarity is low */
polarity = 3 ;
/* Command-line over-ride via acpi_sci= */
2007-02-02 19:48:22 +03:00
if ( acpi_sci_flags & ACPI_MADT_TRIGGER_MASK )
trigger = ( acpi_sci_flags & ACPI_MADT_TRIGGER_MASK ) > > 2 ;
2005-04-16 15:20:36 -07:00
2007-02-02 19:48:22 +03:00
if ( acpi_sci_flags & ACPI_MADT_POLARITY_MASK )
polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK ;
2005-04-16 15:20:36 -07:00
/*
2005-08-05 00:44:28 -04:00
* mp_config_acpi_legacy_irqs ( ) already setup IRQs < 16
2005-04-16 15:20:36 -07:00
* If GSI is < 16 , this will update its flags ,
* else it will create a new mp_irqs [ ] entry .
*/
2006-12-02 02:27:46 -05:00
mp_override_legacy_irq ( gsi , polarity , trigger , gsi ) ;
2005-04-16 15:20:36 -07:00
/*
* stash over - ride to indicate we ' ve been here
2007-02-02 19:48:22 +03:00
* and for later update of acpi_gbl_FADT
2005-04-16 15:20:36 -07:00
*/
2006-12-02 02:27:46 -05:00
acpi_sci_override_gsi = gsi ;
2005-04-16 15:20:36 -07:00
return ;
}
static int __init
2007-02-02 19:48:22 +03:00
acpi_parse_int_src_ovr ( struct acpi_subtable_header * header ,
2005-08-05 00:44:28 -04:00
const unsigned long end )
2005-04-16 15:20:36 -07:00
{
2007-02-02 19:48:22 +03:00
struct acpi_madt_interrupt_override * intsrc = NULL ;
2005-04-16 15:20:36 -07:00
2007-02-02 19:48:22 +03:00
intsrc = ( struct acpi_madt_interrupt_override * ) header ;
2005-04-16 15:20:36 -07:00
if ( BAD_MADT_ENTRY ( intsrc , end ) )
return - EINVAL ;
acpi_table_print_madt_entry ( header ) ;
2007-02-02 19:48:22 +03:00
if ( intsrc - > source_irq = = acpi_gbl_FADT . sci_interrupt ) {
2006-12-02 02:27:46 -05:00
acpi_sci_ioapic_setup ( intsrc - > global_irq ,
2007-02-02 19:48:22 +03:00
intsrc - > inti_flags & ACPI_MADT_POLARITY_MASK ,
( intsrc - > inti_flags & ACPI_MADT_TRIGGER_MASK ) > > 2 ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
if ( acpi_skip_timer_override & &
2007-02-02 19:48:22 +03:00
intsrc - > source_irq = = 0 & & intsrc - > global_irq = = 2 ) {
2005-08-05 00:44:28 -04:00
printk ( PREFIX " BIOS IRQ0 pin2 override ignored. \n " ) ;
return 0 ;
2005-04-16 15:20:36 -07:00
}
2007-02-02 19:48:22 +03:00
mp_override_legacy_irq ( intsrc - > source_irq ,
intsrc - > inti_flags & ACPI_MADT_POLARITY_MASK ,
( intsrc - > inti_flags & ACPI_MADT_TRIGGER_MASK ) > > 2 ,
intsrc - > global_irq ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
static int __init
2007-02-02 19:48:22 +03:00
acpi_parse_nmi_src ( struct acpi_subtable_header * header , const unsigned long end )
2005-04-16 15:20:36 -07:00
{
2007-02-02 19:48:22 +03:00
struct acpi_madt_nmi_source * nmi_src = NULL ;
2005-04-16 15:20:36 -07:00
2007-02-02 19:48:22 +03:00
nmi_src = ( struct acpi_madt_nmi_source * ) header ;
2005-04-16 15:20:36 -07:00
if ( BAD_MADT_ENTRY ( nmi_src , end ) )
return - EINVAL ;
acpi_table_print_madt_entry ( header ) ;
/* TBD: Support nimsrc entries? */
return 0 ;
}
2005-08-05 00:44:28 -04:00
# endif /* CONFIG_X86_IO_APIC */
2005-04-16 15:20:36 -07:00
/*
* acpi_pic_sci_set_trigger ( )
2007-02-02 19:48:22 +03:00
*
2005-04-16 15:20:36 -07:00
* use ELCR to set PIC - mode trigger type for SCI
*
* If a PIC - mode SCI is not recognized or gives spurious IRQ7 ' s
* it may require Edge Trigger - - use " acpi_sci=edge "
*
* Port 0x4d0 - 4 d1 are ECLR1 and ECLR2 , the Edge / Level Control Registers
* for the 8259 PIC . bit [ n ] = 1 means irq [ n ] is Level , otherwise Edge .
* ECLR1 is IRQ ' s 0 - 7 ( IRQ 0 , 1 , 2 must be 0 )
* ECLR2 is IRQ ' s 8 - 15 ( IRQ 8 , 13 must be 0 )
*/
2005-08-05 00:44:28 -04:00
void __init acpi_pic_sci_set_trigger ( unsigned int irq , u16 trigger )
2005-04-16 15:20:36 -07:00
{
unsigned int mask = 1 < < irq ;
unsigned int old , new ;
/* Real old ELCR mask */
old = inb ( 0x4d0 ) | ( inb ( 0x4d1 ) < < 8 ) ;
/*
* If we use ACPI to set PCI irq ' s , then we should clear ELCR
* since we will set it correctly as we enable the PCI irq
* routing .
*/
new = acpi_noirq ? old : 0 ;
/*
* Update SCI information in the ELCR , it isn ' t in the PCI
* routing tables . .
*/
switch ( trigger ) {
2005-08-05 00:44:28 -04:00
case 1 : /* Edge - clear */
2005-04-16 15:20:36 -07:00
new & = ~ mask ;
break ;
2005-08-05 00:44:28 -04:00
case 3 : /* Level - set */
2005-04-16 15:20:36 -07:00
new | = mask ;
break ;
}
if ( old = = new )
return ;
printk ( PREFIX " setting ELCR to %04x (from %04x) \n " , new , old ) ;
outb ( new , 0x4d0 ) ;
outb ( new > > 8 , 0x4d1 ) ;
}
int acpi_gsi_to_irq ( u32 gsi , unsigned int * irq )
{
2006-10-04 02:16:52 -07:00
* irq = gsi ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-07-28 14:42:00 -04:00
/*
* success : return IRQ number ( > = 0 )
* failure : return < 0
*/
2005-12-28 02:43:51 -05:00
int acpi_register_gsi ( u32 gsi , int triggering , int polarity )
2005-04-16 15:20:36 -07:00
{
unsigned int irq ;
unsigned int plat_gsi = gsi ;
# ifdef CONFIG_PCI
/*
* Make sure all ( legacy ) PCI IRQs are set as level - triggered .
*/
if ( acpi_irq_model = = ACPI_IRQ_MODEL_PIC ) {
extern void eisa_set_level_irq ( unsigned int irq ) ;
2005-12-28 02:43:51 -05:00
if ( triggering = = ACPI_LEVEL_SENSITIVE )
2005-08-05 00:44:28 -04:00
eisa_set_level_irq ( gsi ) ;
2005-04-16 15:20:36 -07:00
}
# endif
# ifdef CONFIG_X86_IO_APIC
if ( acpi_irq_model = = ACPI_IRQ_MODEL_IOAPIC ) {
2005-12-28 02:43:51 -05:00
plat_gsi = mp_register_gsi ( gsi , triggering , polarity ) ;
2005-04-16 15:20:36 -07:00
}
# endif
acpi_gsi_to_irq ( plat_gsi , & irq ) ;
return irq ;
}
2005-08-05 00:44:28 -04:00
2005-04-16 15:20:36 -07:00
EXPORT_SYMBOL ( acpi_register_gsi ) ;
/*
* ACPI based hotplug support for CPU
*/
# ifdef CONFIG_ACPI_HOTPLUG_CPU
2005-08-05 00:44:28 -04:00
int acpi_map_lsapic ( acpi_handle handle , int * pcpu )
2005-04-16 15:20:36 -07:00
{
2006-09-26 10:52:35 +02:00
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER , NULL } ;
union acpi_object * obj ;
2007-02-02 19:48:22 +03:00
struct acpi_madt_local_apic * lapic ;
2006-09-26 10:52:35 +02:00
cpumask_t tmp_map , new_map ;
u8 physid ;
int cpu ;
if ( ACPI_FAILURE ( acpi_evaluate_object ( handle , " _MAT " , NULL , & buffer ) ) )
return - EINVAL ;
if ( ! buffer . length | | ! buffer . pointer )
return - EINVAL ;
obj = buffer . pointer ;
if ( obj - > type ! = ACPI_TYPE_BUFFER | |
obj - > buffer . length < sizeof ( * lapic ) ) {
kfree ( buffer . pointer ) ;
return - EINVAL ;
}
2007-02-02 19:48:22 +03:00
lapic = ( struct acpi_madt_local_apic * ) obj - > buffer . pointer ;
2006-09-26 10:52:35 +02:00
2007-02-02 19:48:22 +03:00
if ( lapic - > header . type ! = ACPI_MADT_TYPE_LOCAL_APIC | |
! ( lapic - > lapic_flags & ACPI_MADT_ENABLED ) ) {
2006-09-26 10:52:35 +02:00
kfree ( buffer . pointer ) ;
return - EINVAL ;
}
physid = lapic - > id ;
kfree ( buffer . pointer ) ;
buffer . length = ACPI_ALLOCATE_BUFFER ;
buffer . pointer = NULL ;
tmp_map = cpu_present_map ;
2007-02-02 19:48:22 +03:00
mp_register_lapic ( physid , lapic - > lapic_flags & ACPI_MADT_ENABLED ) ;
2006-09-26 10:52:35 +02:00
/*
* If mp_register_lapic successfully generates a new logical cpu
* number , then the following will get us exactly what was mapped
*/
cpus_andnot ( new_map , cpu_present_map , tmp_map ) ;
if ( cpus_empty ( new_map ) ) {
printk ( " Unable to map lapic to logical cpu number \n " ) ;
return - EINVAL ;
}
cpu = first_cpu ( new_map ) ;
* pcpu = cpu ;
return 0 ;
2005-04-16 15:20:36 -07:00
}
2005-08-05 00:44:28 -04:00
EXPORT_SYMBOL ( acpi_map_lsapic ) ;
2005-04-16 15:20:36 -07:00
2005-08-05 00:44:28 -04:00
int acpi_unmap_lsapic ( int cpu )
2005-04-16 15:20:36 -07:00
{
2006-09-26 10:52:35 +02:00
x86_cpu_to_apicid [ cpu ] = - 1 ;
cpu_clear ( cpu , cpu_present_map ) ;
num_processors - - ;
return ( 0 ) ;
2005-04-16 15:20:36 -07:00
}
2005-08-05 00:44:28 -04:00
2005-04-16 15:20:36 -07:00
EXPORT_SYMBOL ( acpi_unmap_lsapic ) ;
2005-08-05 00:44:28 -04:00
# endif /* CONFIG_ACPI_HOTPLUG_CPU */
2005-04-16 15:20:36 -07:00
2005-08-05 00:44:28 -04:00
int acpi_register_ioapic ( acpi_handle handle , u64 phys_addr , u32 gsi_base )
2005-04-28 00:25:58 -07:00
{
/* TBD */
return - EINVAL ;
}
2005-08-05 00:44:28 -04:00
2005-04-28 00:25:58 -07:00
EXPORT_SYMBOL ( acpi_register_ioapic ) ;
2005-08-05 00:44:28 -04:00
int acpi_unregister_ioapic ( acpi_handle handle , u32 gsi_base )
2005-04-28 00:25:58 -07:00
{
/* TBD */
return - EINVAL ;
}
2005-08-05 00:44:28 -04:00
2005-04-28 00:25:58 -07:00
EXPORT_SYMBOL ( acpi_unregister_ioapic ) ;
2005-04-16 15:20:36 -07:00
static unsigned long __init
2005-08-05 00:44:28 -04:00
acpi_scan_rsdp ( unsigned long start , unsigned long length )
2005-04-16 15:20:36 -07:00
{
2005-08-05 00:44:28 -04:00
unsigned long offset = 0 ;
unsigned long sig_len = sizeof ( " RSD PTR " ) - 1 ;
2005-04-16 15:20:36 -07:00
/*
* Scan all 16 - byte boundaries of the physical memory region for the
* RSDP signature .
*/
for ( offset = 0 ; offset < length ; offset + = 16 ) {
2005-11-05 17:25:53 +01:00
if ( strncmp ( ( char * ) ( phys_to_virt ( start ) + offset ) , " RSD PTR " , sig_len ) )
2005-04-16 15:20:36 -07:00
continue ;
return ( start + offset ) ;
}
return 0 ;
}
2007-02-02 19:48:22 +03:00
static int __init acpi_parse_sbf ( struct acpi_table_header * table )
2005-04-16 15:20:36 -07:00
{
2007-02-02 19:48:22 +03:00
struct acpi_table_boot * sb ;
2005-04-16 15:20:36 -07:00
2007-02-02 19:48:22 +03:00
sb = ( struct acpi_table_boot * ) table ;
2005-04-16 15:20:36 -07:00
if ( ! sb ) {
printk ( KERN_WARNING PREFIX " Unable to map SBF \n " ) ;
return - ENODEV ;
}
2007-02-02 19:48:22 +03:00
sbf_port = sb - > cmos_index ; /* Save CMOS port */
2005-04-16 15:20:36 -07:00
return 0 ;
}
# ifdef CONFIG_HPET_TIMER
2007-02-02 19:48:22 +03:00
static int __init acpi_parse_hpet ( struct acpi_table_header * table )
2005-04-16 15:20:36 -07:00
{
struct acpi_table_hpet * hpet_tbl ;
2006-09-26 10:52:39 +02:00
struct resource * hpet_res ;
resource_size_t res_start ;
2005-04-16 15:20:36 -07:00
2007-02-02 19:48:22 +03:00
hpet_tbl = ( struct acpi_table_hpet * ) table ;
2005-04-16 15:20:36 -07:00
if ( ! hpet_tbl ) {
printk ( KERN_WARNING PREFIX " Unable to map HPET \n " ) ;
return - ENODEV ;
}
2007-02-02 19:48:22 +03:00
if ( hpet_tbl - > address . space_id ! = ACPI_SPACE_MEM ) {
2005-04-16 15:20:36 -07:00
printk ( KERN_WARNING PREFIX " HPET timers must be located in "
" memory. \n " ) ;
return - 1 ;
}
2006-09-26 10:52:39 +02:00
# define HPET_RESOURCE_NAME_SIZE 9
hpet_res = alloc_bootmem ( sizeof ( * hpet_res ) + HPET_RESOURCE_NAME_SIZE ) ;
if ( hpet_res ) {
memset ( hpet_res , 0 , sizeof ( * hpet_res ) ) ;
hpet_res - > name = ( void * ) & hpet_res [ 1 ] ;
hpet_res - > flags = IORESOURCE_MEM | IORESOURCE_BUSY ;
snprintf ( ( char * ) hpet_res - > name , HPET_RESOURCE_NAME_SIZE ,
2007-02-02 19:48:22 +03:00
" HPET %u " , hpet_tbl - > sequence ) ;
2006-09-26 10:52:39 +02:00
hpet_res - > end = ( 1 * 1024 ) - 1 ;
}
2007-02-02 19:48:22 +03:00
# ifdef CONFIG_X86_64
vxtime . hpet_address = hpet_tbl - > address . address ;
2005-04-16 15:20:36 -07:00
2005-08-05 00:44:28 -04:00
printk ( KERN_INFO PREFIX " HPET id: %#x base: %#lx \n " ,
2007-02-02 19:48:22 +03:00
hpet_tbl - > id , vxtime . hpet_address ) ;
2006-09-26 10:52:39 +02:00
res_start = vxtime . hpet_address ;
2007-02-02 19:48:22 +03:00
# else /* X86 */
2005-04-16 15:20:36 -07:00
{
extern unsigned long hpet_address ;
2007-02-02 19:48:22 +03:00
hpet_address = hpet_tbl - > address . address ;
2005-04-16 15:20:36 -07:00
printk ( KERN_INFO PREFIX " HPET id: %#x base: %#lx \n " ,
2007-02-02 19:48:22 +03:00
hpet_tbl - > id , hpet_address ) ;
2006-09-26 10:52:39 +02:00
res_start = hpet_address ;
2005-04-16 15:20:36 -07:00
}
2007-02-02 19:48:22 +03:00
# endif /* X86 */
2005-04-16 15:20:36 -07:00
2006-09-26 10:52:39 +02:00
if ( hpet_res ) {
hpet_res - > start = res_start ;
hpet_res - > end + = res_start ;
insert_resource ( & iomem_resource , hpet_res ) ;
}
2005-04-16 15:20:36 -07:00
return 0 ;
}
# else
# define acpi_parse_hpet NULL
# endif
2007-02-02 19:48:22 +03:00
static int __init acpi_parse_fadt ( struct acpi_table_header * table )
2005-04-16 15:20:36 -07:00
{
2005-04-16 15:24:53 -07:00
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_X86_PM_TIMER
/* detect the location of the ACPI PM Timer */
2007-02-02 19:48:22 +03:00
if ( acpi_gbl_FADT . header . revision > = FADT2_REVISION_ID ) {
2005-04-16 15:20:36 -07:00
/* FADT rev. 2 */
2007-02-02 19:48:22 +03:00
if ( acpi_gbl_FADT . xpm_timer_block . space_id ! =
2005-08-05 00:44:28 -04:00
ACPI_ADR_SPACE_SYSTEM_IO )
2005-04-16 15:20:36 -07:00
return 0 ;
2007-02-02 19:48:22 +03:00
pmtmr_ioport = acpi_gbl_FADT . xpm_timer_block . address ;
2005-09-21 01:35:00 -04:00
/*
* " X " fields are optional extensions to the original V1 .0
* fields , so we must selectively expand V1 .0 fields if the
* corresponding X field is zero .
*/
if ( ! pmtmr_ioport )
2007-02-02 19:48:22 +03:00
pmtmr_ioport = acpi_gbl_FADT . pm_timer_block ;
2005-04-16 15:20:36 -07:00
} else {
/* FADT rev. 1 */
2007-02-02 19:48:22 +03:00
pmtmr_ioport = acpi_gbl_FADT . pm_timer_block ;
2005-04-16 15:20:36 -07:00
}
if ( pmtmr_ioport )
2005-08-05 00:44:28 -04:00
printk ( KERN_INFO PREFIX " PM-Timer IO Port: %#x \n " ,
pmtmr_ioport ) ;
2005-04-16 15:20:36 -07:00
# endif
return 0 ;
}
2005-08-05 00:44:28 -04:00
unsigned long __init acpi_find_rsdp ( void )
2005-04-16 15:20:36 -07:00
{
2005-08-05 00:44:28 -04:00
unsigned long rsdp_phys = 0 ;
2005-04-16 15:20:36 -07:00
if ( efi_enabled ) {
2006-03-26 01:37:08 -08:00
if ( efi . acpi20 ! = EFI_INVALID_TABLE_ADDR )
return efi . acpi20 ;
else if ( efi . acpi ! = EFI_INVALID_TABLE_ADDR )
return efi . acpi ;
2005-04-16 15:20:36 -07:00
}
/*
* Scan memory looking for the RSDP signature . First search EBDA ( low
* memory ) paragraphs and then search upper memory ( E0000 - FFFFF ) .
*/
2005-08-05 00:44:28 -04:00
rsdp_phys = acpi_scan_rsdp ( 0 , 0x400 ) ;
2005-04-16 15:20:36 -07:00
if ( ! rsdp_phys )
2005-08-05 00:44:28 -04:00
rsdp_phys = acpi_scan_rsdp ( 0xE0000 , 0x20000 ) ;
2005-04-16 15:20:36 -07:00
return rsdp_phys ;
}
# ifdef CONFIG_X86_LOCAL_APIC
/*
* Parse LAPIC entries in MADT
* returns 0 on success , < 0 on error
*/
2005-08-05 00:44:28 -04:00
static int __init acpi_parse_madt_lapic_entries ( void )
2005-04-16 15:20:36 -07:00
{
int count ;
2006-04-11 12:54:36 +02:00
if ( ! cpu_has_apic )
return - ENODEV ;
2007-02-02 19:48:22 +03:00
/*
2005-04-16 15:20:36 -07:00
* Note that the LAPIC address is obtained from the MADT ( 32 - bit value )
* and ( optionally ) overriden by a LAPIC_ADDR_OVR entry ( 64 - bit value ) .
*/
2005-08-05 00:44:28 -04:00
count =
2007-02-02 19:48:22 +03:00
acpi_table_parse_madt ( ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE ,
2005-08-05 00:44:28 -04:00
acpi_parse_lapic_addr_ovr , 0 ) ;
2005-04-16 15:20:36 -07:00
if ( count < 0 ) {
2005-08-05 00:44:28 -04:00
printk ( KERN_ERR PREFIX
" Error parsing LAPIC address override entry \n " ) ;
2005-04-16 15:20:36 -07:00
return count ;
}
mp_register_lapic_address ( acpi_lapic_addr ) ;
2007-02-02 19:48:22 +03:00
count = acpi_table_parse_madt ( ACPI_MADT_TYPE_LOCAL_APIC , acpi_parse_lapic ,
2005-08-05 00:44:28 -04:00
MAX_APICS ) ;
if ( ! count ) {
2005-04-16 15:20:36 -07:00
printk ( KERN_ERR PREFIX " No LAPIC entries present \n " ) ;
/* TBD: Cleanup to allow fallback to MPS */
return - ENODEV ;
2005-08-05 00:44:28 -04:00
} else if ( count < 0 ) {
2005-04-16 15:20:36 -07:00
printk ( KERN_ERR PREFIX " Error parsing LAPIC entry \n " ) ;
/* TBD: Cleanup to allow fallback to MPS */
return count ;
}
2005-08-05 00:44:28 -04:00
count =
2007-02-02 19:48:22 +03:00
acpi_table_parse_madt ( ACPI_MADT_TYPE_LOCAL_APIC_NMI , acpi_parse_lapic_nmi , 0 ) ;
2005-04-16 15:20:36 -07:00
if ( count < 0 ) {
printk ( KERN_ERR PREFIX " Error parsing LAPIC NMI entry \n " ) ;
/* TBD: Cleanup to allow fallback to MPS */
return count ;
}
return 0 ;
}
2005-08-05 00:44:28 -04:00
# endif /* CONFIG_X86_LOCAL_APIC */
2005-04-16 15:20:36 -07:00
2005-08-24 12:09:07 -04:00
# ifdef CONFIG_X86_IO_APIC
2005-04-16 15:20:36 -07:00
/*
* Parse IOAPIC related entries in MADT
* returns 0 on success , < 0 on error
*/
2005-08-05 00:44:28 -04:00
static int __init acpi_parse_madt_ioapic_entries ( void )
2005-04-16 15:20:36 -07:00
{
int count ;
/*
* ACPI interpreter is required to complete interrupt setup ,
* so if it is off , don ' t enumerate the io - apics with ACPI .
* If MPS is present , it will handle them ,
* otherwise the system will stay in PIC mode
*/
if ( acpi_disabled | | acpi_noirq ) {
return - ENODEV ;
2005-08-05 00:44:28 -04:00
}
2005-04-16 15:20:36 -07:00
2007-02-02 19:48:22 +03:00
if ( ! cpu_has_apic )
2006-04-07 19:49:39 +02:00
return - ENODEV ;
2005-04-16 15:20:36 -07:00
/*
2005-08-05 00:44:28 -04:00
* if " noapic " boot option , don ' t look for IO - APICs
2005-04-16 15:20:36 -07:00
*/
if ( skip_ioapic_setup ) {
printk ( KERN_INFO PREFIX " Skipping IOAPIC probe "
2005-08-05 00:44:28 -04:00
" due to 'noapic' option. \n " ) ;
2005-04-16 15:20:36 -07:00
return - ENODEV ;
}
2005-08-05 00:44:28 -04:00
count =
2007-02-02 19:48:22 +03:00
acpi_table_parse_madt ( ACPI_MADT_TYPE_IO_APIC , acpi_parse_ioapic ,
2005-08-05 00:44:28 -04:00
MAX_IO_APICS ) ;
2005-04-16 15:20:36 -07:00
if ( ! count ) {
printk ( KERN_ERR PREFIX " No IOAPIC entries present \n " ) ;
return - ENODEV ;
2005-08-05 00:44:28 -04:00
} else if ( count < 0 ) {
2005-04-16 15:20:36 -07:00
printk ( KERN_ERR PREFIX " Error parsing IOAPIC entry \n " ) ;
return count ;
}
2005-08-05 00:44:28 -04:00
count =
2007-02-02 19:48:22 +03:00
acpi_table_parse_madt ( ACPI_MADT_TYPE_INTERRUPT_OVERRIDE , acpi_parse_int_src_ovr ,
2005-08-05 00:44:28 -04:00
NR_IRQ_VECTORS ) ;
2005-04-16 15:20:36 -07:00
if ( count < 0 ) {
2005-08-05 00:44:28 -04:00
printk ( KERN_ERR PREFIX
" Error parsing interrupt source overrides entry \n " ) ;
2005-04-16 15:20:36 -07:00
/* TBD: Cleanup to allow fallback to MPS */
return count ;
}
/*
* If BIOS did not supply an INT_SRC_OVR for the SCI
* pretend we got one so we can set the SCI flags .
*/
if ( ! acpi_sci_override_gsi )
2007-02-02 19:48:22 +03:00
acpi_sci_ioapic_setup ( acpi_gbl_FADT . sci_interrupt , 0 , 0 ) ;
2005-04-16 15:20:36 -07:00
/* Fill in identity legacy mapings where no override */
mp_config_acpi_legacy_irqs ( ) ;
2005-08-05 00:44:28 -04:00
count =
2007-02-02 19:48:22 +03:00
acpi_table_parse_madt ( ACPI_MADT_TYPE_NMI_SOURCE , acpi_parse_nmi_src ,
2005-08-05 00:44:28 -04:00
NR_IRQ_VECTORS ) ;
2005-04-16 15:20:36 -07:00
if ( count < 0 ) {
printk ( KERN_ERR PREFIX " Error parsing NMI SRC entry \n " ) ;
/* TBD: Cleanup to allow fallback to MPS */
return count ;
}
return 0 ;
}
# else
static inline int acpi_parse_madt_ioapic_entries ( void )
{
return - 1 ;
}
2005-08-24 12:09:07 -04:00
# endif /* !CONFIG_X86_IO_APIC */
2005-04-16 15:20:36 -07:00
2005-08-05 00:44:28 -04:00
static void __init acpi_process_madt ( void )
2005-04-16 15:20:36 -07:00
{
# ifdef CONFIG_X86_LOCAL_APIC
int count , error ;
2007-02-02 19:48:22 +03:00
count = acpi_table_parse ( ACPI_SIG_MADT , acpi_parse_madt ) ;
2005-04-16 15:20:36 -07:00
if ( count > = 1 ) {
/*
* Parse MADT LAPIC entries
*/
error = acpi_parse_madt_lapic_entries ( ) ;
if ( ! error ) {
acpi_lapic = 1 ;
2005-09-03 15:56:31 -07:00
# ifdef CONFIG_X86_GENERICARCH
generic_bigsmp_probe ( ) ;
# endif
2005-04-16 15:20:36 -07:00
/*
* Parse MADT IO - APIC entries
*/
error = acpi_parse_madt_ioapic_entries ( ) ;
if ( ! error ) {
acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC ;
acpi_irq_balance_set ( NULL ) ;
acpi_ioapic = 1 ;
smp_found_config = 1 ;
clustered_apic_check ( ) ;
}
}
if ( error = = - EINVAL ) {
/*
* Dell Precision Workstation 410 , 610 come here .
*/
2005-08-05 00:44:28 -04:00
printk ( KERN_ERR PREFIX
" Invalid BIOS MADT, disabling ACPI \n " ) ;
2005-04-16 15:20:36 -07:00
disable_acpi ( ) ;
}
}
# endif
return ;
}
2005-06-25 14:54:42 -07:00
# ifdef __i386__
static int __init disable_acpi_irq ( struct dmi_system_id * d )
{
if ( ! acpi_force ) {
printk ( KERN_NOTICE " %s detected: force use of acpi=noirq \n " ,
d - > ident ) ;
acpi_noirq_set ( ) ;
}
return 0 ;
}
static int __init disable_acpi_pci ( struct dmi_system_id * d )
{
if ( ! acpi_force ) {
printk ( KERN_NOTICE " %s detected: force use of pci=noacpi \n " ,
d - > ident ) ;
acpi_disable_pci ( ) ;
}
return 0 ;
}
static int __init dmi_disable_acpi ( struct dmi_system_id * d )
{
if ( ! acpi_force ) {
2005-08-05 00:44:28 -04:00
printk ( KERN_NOTICE " %s detected: acpi off \n " , d - > ident ) ;
2005-06-25 14:54:42 -07:00
disable_acpi ( ) ;
} else {
printk ( KERN_NOTICE
" Warning: DMI blacklist says broken, but acpi forced \n " ) ;
}
return 0 ;
}
/*
* Limit ACPI to CPU enumeration for HT
*/
static int __init force_acpi_ht ( struct dmi_system_id * d )
{
if ( ! acpi_force ) {
2005-08-05 00:44:28 -04:00
printk ( KERN_NOTICE " %s detected: force use of acpi=ht \n " ,
d - > ident ) ;
2005-06-25 14:54:42 -07:00
disable_acpi ( ) ;
acpi_ht = 1 ;
} else {
printk ( KERN_NOTICE
" Warning: acpi=force overrules DMI blacklist: acpi=ht \n " ) ;
}
return 0 ;
}
/*
* If your system is blacklisted here , but you find that acpi = force
* works for you , please contact acpi - devel @ sourceforge . net
*/
static struct dmi_system_id __initdata acpi_dmi_table [ ] = {
/*
* Boxes that need ACPI disabled
*/
{
2005-08-05 00:44:28 -04:00
. callback = dmi_disable_acpi ,
. ident = " IBM Thinkpad " ,
. matches = {
DMI_MATCH ( DMI_BOARD_VENDOR , " IBM " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " 2629H1G " ) ,
} ,
} ,
2005-06-25 14:54:42 -07:00
/*
* Boxes that need acpi = ht
*/
{
2005-08-05 00:44:28 -04:00
. callback = force_acpi_ht ,
. ident = " FSC Primergy T850 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " FUJITSU SIEMENS " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " PRIMERGY T850 " ) ,
} ,
} ,
2005-06-25 14:54:42 -07:00
{
2005-08-05 00:44:28 -04:00
. callback = force_acpi_ht ,
. ident = " DELL GX240 " ,
. matches = {
DMI_MATCH ( DMI_BOARD_VENDOR , " Dell Computer Corporation " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " OptiPlex GX240 " ) ,
} ,
} ,
2005-06-25 14:54:42 -07:00
{
2005-08-05 00:44:28 -04:00
. callback = force_acpi_ht ,
. ident = " HP VISUALIZE NT Workstation " ,
. matches = {
DMI_MATCH ( DMI_BOARD_VENDOR , " Hewlett-Packard " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " HP VISUALIZE NT Workstation " ) ,
} ,
} ,
2005-06-25 14:54:42 -07:00
{
2005-08-05 00:44:28 -04:00
. callback = force_acpi_ht ,
. ident = " Compaq Workstation W8000 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Compaq " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " Workstation W8000 " ) ,
} ,
} ,
2005-06-25 14:54:42 -07:00
{
2005-08-05 00:44:28 -04:00
. callback = force_acpi_ht ,
. ident = " ASUS P4B266 " ,
. matches = {
DMI_MATCH ( DMI_BOARD_VENDOR , " ASUSTeK Computer INC. " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " P4B266 " ) ,
} ,
} ,
2005-06-25 14:54:42 -07:00
{
2005-08-05 00:44:28 -04:00
. callback = force_acpi_ht ,
. ident = " ASUS P2B-DS " ,
. matches = {
DMI_MATCH ( DMI_BOARD_VENDOR , " ASUSTeK Computer INC. " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " P2B-DS " ) ,
} ,
} ,
2005-06-25 14:54:42 -07:00
{
2005-08-05 00:44:28 -04:00
. callback = force_acpi_ht ,
. ident = " ASUS CUR-DLS " ,
. matches = {
DMI_MATCH ( DMI_BOARD_VENDOR , " ASUSTeK Computer INC. " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " CUR-DLS " ) ,
} ,
} ,
2005-06-25 14:54:42 -07:00
{
2005-08-05 00:44:28 -04:00
. callback = force_acpi_ht ,
. ident = " ABIT i440BX-W83977 " ,
. matches = {
DMI_MATCH ( DMI_BOARD_VENDOR , " ABIT <http://www.abit.com> " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " i440BX-W83977 (BP6) " ) ,
} ,
} ,
2005-06-25 14:54:42 -07:00
{
2005-08-05 00:44:28 -04:00
. callback = force_acpi_ht ,
. ident = " IBM Bladecenter " ,
. matches = {
DMI_MATCH ( DMI_BOARD_VENDOR , " IBM " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " IBM eServer BladeCenter HS20 " ) ,
} ,
} ,
2005-06-25 14:54:42 -07:00
{
2005-08-05 00:44:28 -04:00
. callback = force_acpi_ht ,
. ident = " IBM eServer xSeries 360 " ,
. matches = {
DMI_MATCH ( DMI_BOARD_VENDOR , " IBM " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " eServer xSeries 360 " ) ,
} ,
} ,
2005-06-25 14:54:42 -07:00
{
2005-08-05 00:44:28 -04:00
. callback = force_acpi_ht ,
. ident = " IBM eserver xSeries 330 " ,
. matches = {
DMI_MATCH ( DMI_BOARD_VENDOR , " IBM " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " eserver xSeries 330 " ) ,
} ,
} ,
2005-06-25 14:54:42 -07:00
{
2005-08-05 00:44:28 -04:00
. callback = force_acpi_ht ,
. ident = " IBM eserver xSeries 440 " ,
. matches = {
DMI_MATCH ( DMI_BOARD_VENDOR , " IBM " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " eserver xSeries 440 " ) ,
} ,
} ,
2005-06-25 14:54:42 -07:00
/*
* Boxes that need ACPI PCI IRQ routing disabled
*/
{
2005-08-05 00:44:28 -04:00
. callback = disable_acpi_irq ,
. ident = " ASUS A7V " ,
. matches = {
DMI_MATCH ( DMI_BOARD_VENDOR , " ASUSTeK Computer INC " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " <A7V> " ) ,
/* newer BIOS, Revision 1011, does work */
DMI_MATCH ( DMI_BIOS_VERSION ,
" ASUS A7V ACPI BIOS Revision 1007 " ) ,
} ,
} ,
2005-06-25 14:54:42 -07:00
/*
* Boxes that need ACPI PCI IRQ routing and PCI scan disabled
*/
2005-08-05 00:44:28 -04:00
{ /* _BBN 0 bug */
. callback = disable_acpi_pci ,
. ident = " ASUS PR-DLS " ,
. matches = {
DMI_MATCH ( DMI_BOARD_VENDOR , " ASUSTeK Computer INC. " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " PR-DLS " ) ,
DMI_MATCH ( DMI_BIOS_VERSION ,
" ASUS PR-DLS ACPI BIOS Revision 1010 " ) ,
DMI_MATCH ( DMI_BIOS_DATE , " 03/21/2003 " )
} ,
} ,
2005-06-25 14:54:42 -07:00
{
2005-08-05 00:44:28 -04:00
. callback = disable_acpi_pci ,
. ident = " Acer TravelMate 36x Laptop " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " TravelMate 360 " ) ,
} ,
} ,
{ }
2005-06-25 14:54:42 -07:00
} ;
2005-08-05 00:44:28 -04:00
# endif /* __i386__ */
2005-06-25 14:54:42 -07:00
2005-04-16 15:20:36 -07:00
/*
* acpi_boot_table_init ( ) and acpi_boot_init ( )
* called from setup_arch ( ) , always .
* 1. checksums all tables
* 2. enumerates lapics
* 3. enumerates io - apics
*
* acpi_table_init ( ) is separate to allow reading SRAT without
* other side effects .
*
* side effects of acpi_boot_init :
* acpi_lapic = 1 if LAPIC found
* acpi_ioapic = 1 if IOAPIC found
* if ( acpi_lapic & & acpi_ioapic ) smp_found_config = 1 ;
* if acpi_blacklisted ( ) acpi_disabled = 1 ;
* acpi_irq_model = . . .
* . . .
*
* return value : ( currently ignored )
* 0 : success
* ! 0 : failure
*/
2005-08-05 00:44:28 -04:00
int __init acpi_boot_table_init ( void )
2005-04-16 15:20:36 -07:00
{
int error ;
2005-06-25 14:54:42 -07:00
# ifdef __i386__
dmi_check_system ( acpi_dmi_table ) ;
# endif
2005-04-16 15:20:36 -07:00
/*
* If acpi_disabled , bail out
* One exception : acpi = ht continues far enough to enumerate LAPICs
*/
if ( acpi_disabled & & ! acpi_ht )
2005-08-05 00:44:28 -04:00
return 1 ;
2005-04-16 15:20:36 -07:00
2007-02-02 19:48:22 +03:00
/*
2005-04-16 15:20:36 -07:00
* Initialize the ACPI boot - time table parser .
*/
error = acpi_table_init ( ) ;
if ( error ) {
disable_acpi ( ) ;
return error ;
}
2007-02-02 19:48:22 +03:00
acpi_table_parse ( ACPI_SIG_BOOT , acpi_parse_sbf ) ;
2005-04-16 15:20:36 -07:00
/*
* blacklist may disable ACPI entirely
*/
error = acpi_blacklisted ( ) ;
if ( error ) {
if ( acpi_force ) {
printk ( KERN_WARNING PREFIX " acpi=force override \n " ) ;
} else {
printk ( KERN_WARNING PREFIX " Disabling ACPI support \n " ) ;
disable_acpi ( ) ;
return error ;
}
}
return 0 ;
}
int __init acpi_boot_init ( void )
{
/*
* If acpi_disabled , bail out
* One exception : acpi = ht continues far enough to enumerate LAPICs
*/
if ( acpi_disabled & & ! acpi_ht )
2005-08-05 00:44:28 -04:00
return 1 ;
2005-04-16 15:20:36 -07:00
2007-02-02 19:48:22 +03:00
acpi_table_parse ( ACPI_SIG_BOOT , acpi_parse_sbf ) ;
2005-04-16 15:20:36 -07:00
/*
* set sci_int and PM timer address
*/
2007-02-02 19:48:22 +03:00
acpi_table_parse ( ACPI_SIG_FADT , acpi_parse_fadt ) ;
2005-04-16 15:20:36 -07:00
/*
* Process the Multiple APIC Description Table ( MADT ) , if present
*/
acpi_process_madt ( ) ;
2007-02-02 19:48:22 +03:00
acpi_table_parse ( ACPI_SIG_HPET , acpi_parse_hpet ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2006-09-26 10:52:32 +02:00
static int __init parse_acpi ( char * arg )
{
if ( ! arg )
return - EINVAL ;
/* "acpi=off" disables both ACPI table parsing and interpreter */
if ( strcmp ( arg , " off " ) = = 0 ) {
disable_acpi ( ) ;
}
/* acpi=force to over-ride black-list */
else if ( strcmp ( arg , " force " ) = = 0 ) {
acpi_force = 1 ;
acpi_ht = 1 ;
acpi_disabled = 0 ;
}
/* acpi=strict disables out-of-spec workarounds */
else if ( strcmp ( arg , " strict " ) = = 0 ) {
acpi_strict = 1 ;
}
/* Limit ACPI just to boot-time to enable HT */
else if ( strcmp ( arg , " ht " ) = = 0 ) {
if ( ! acpi_force )
disable_acpi ( ) ;
acpi_ht = 1 ;
}
/* "acpi=noirq" disables ACPI interrupt routing */
else if ( strcmp ( arg , " noirq " ) = = 0 ) {
acpi_noirq_set ( ) ;
} else {
/* Core will printk when we return error. */
return - EINVAL ;
}
return 0 ;
}
early_param ( " acpi " , parse_acpi ) ;
/* FIXME: Using pci= for an ACPI parameter is a travesty. */
static int __init parse_pci ( char * arg )
{
if ( arg & & strcmp ( arg , " noacpi " ) = = 0 )
acpi_disable_pci ( ) ;
return 0 ;
}
early_param ( " pci " , parse_pci ) ;
# ifdef CONFIG_X86_IO_APIC
static int __init parse_acpi_skip_timer_override ( char * arg )
{
acpi_skip_timer_override = 1 ;
return 0 ;
}
early_param ( " acpi_skip_timer_override " , parse_acpi_skip_timer_override ) ;
2006-11-14 16:57:46 +01:00
static int __init parse_acpi_use_timer_override ( char * arg )
{
acpi_use_timer_override = 1 ;
return 0 ;
}
early_param ( " acpi_use_timer_override " , parse_acpi_use_timer_override ) ;
2006-09-26 10:52:32 +02:00
# endif /* CONFIG_X86_IO_APIC */
static int __init setup_acpi_sci ( char * s )
{
if ( ! s )
return - EINVAL ;
if ( ! strcmp ( s , " edge " ) )
2007-02-02 19:48:22 +03:00
acpi_sci_flags = ACPI_MADT_TRIGGER_EDGE |
( acpi_sci_flags & ~ ACPI_MADT_TRIGGER_MASK ) ;
2006-09-26 10:52:32 +02:00
else if ( ! strcmp ( s , " level " ) )
2007-02-02 19:48:22 +03:00
acpi_sci_flags = ACPI_MADT_TRIGGER_LEVEL |
( acpi_sci_flags & ~ ACPI_MADT_TRIGGER_MASK ) ;
2006-09-26 10:52:32 +02:00
else if ( ! strcmp ( s , " high " ) )
2007-02-02 19:48:22 +03:00
acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_HIGH |
( acpi_sci_flags & ~ ACPI_MADT_POLARITY_MASK ) ;
2006-09-26 10:52:32 +02:00
else if ( ! strcmp ( s , " low " ) )
2007-02-02 19:48:22 +03:00
acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_LOW |
( acpi_sci_flags & ~ ACPI_MADT_POLARITY_MASK ) ;
2006-09-26 10:52:32 +02:00
else
return - EINVAL ;
return 0 ;
}
early_param ( " acpi_sci " , setup_acpi_sci ) ;
2006-10-20 14:30:27 -07:00
int __acpi_acquire_global_lock ( unsigned int * lock )
{
unsigned int old , new , val ;
do {
old = * lock ;
new = ( ( ( old & ~ 0x3 ) + 2 ) + ( ( old > > 1 ) & 0x1 ) ) ;
val = cmpxchg ( lock , old , new ) ;
} while ( unlikely ( val ! = old ) ) ;
return ( new < 3 ) ? - 1 : 0 ;
}
int __acpi_release_global_lock ( unsigned int * lock )
{
unsigned int old , new , val ;
do {
old = * lock ;
new = old & ~ 0x3 ;
val = cmpxchg ( lock , old , new ) ;
} while ( unlikely ( val ! = old ) ) ;
return old & 0x1 ;
}