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>
2009-05-06 10:06:15 -07:00
# include <linux/pci.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>
2008-04-04 23:41:50 +04:00
# include <asm/smp.h>
2005-04-16 15:20:36 -07:00
2006-09-26 10:52:35 +02:00
static int __initdata acpi_force = 0 ;
2008-12-17 16:55:18 +08:00
u32 acpi_rsdt_forced ;
2009-05-19 23:47:38 -04:00
int acpi_disabled ;
2006-09-26 10:52:33 +02:00
EXPORT_SYMBOL ( acpi_disabled ) ;
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_X86_64
2009-01-28 17:55:37 +01:00
# include <asm / proto.h>
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 */
2008-02-05 00:01:48 -08:00
int acpi_pci_disabled ; /* skip ACPI PCI scan and IRQ initialization */
EXPORT_SYMBOL ( acpi_pci_disabled ) ;
2005-04-16 15:20:36 -07:00
int acpi_ht __initdata = 1 ; /* enable HT */
int acpi_lapic ;
int acpi_ioapic ;
int 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
2007-10-20 01:13:56 +02:00
* overridden if IOAPICs are enumerated ( below ) .
2005-04-16 15:20:36 -07:00
*/
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
/*
* 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 .
*/
2007-12-13 08:33:59 +00:00
char * __init __acpi_map_table ( unsigned long phys , unsigned long size )
2005-04-16 15:20:36 -07:00
{
2008-07-09 20:16:36 -07:00
if ( ! phys | | ! size )
return NULL ;
2009-02-07 15:39:41 -08:00
return early_ioremap ( phys , size ) ;
}
void __init __acpi_unmap_table ( char * map , unsigned long size )
{
if ( ! map | | ! size )
return ;
2005-04-16 15:20:36 -07:00
2009-02-07 15:39:41 -08:00
early_iounmap ( map , size ) ;
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
}
2009-01-28 03:43:47 +01:00
default_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 ;
}
2008-04-04 23:41:50 +04:00
static void __cpuinit acpi_register_lapic ( int id , u8 enabled )
{
2008-05-22 18:22:30 -07:00
unsigned int ver = 0 ;
2008-04-04 23:41:50 +04:00
if ( ! enabled ) {
+ + disabled_cpus ;
return ;
}
2008-05-22 18:22:30 -07:00
if ( boot_cpu_physical_apicid ! = - 1U )
ver = apic_version [ boot_cpu_physical_apicid ] ;
generic_processor_info ( id , ver ) ;
2008-04-04 23:41:50 +04:00
}
2009-03-30 13:55:30 -08:00
static int __init
acpi_parse_x2apic ( struct acpi_subtable_header * header , const unsigned long end )
{
struct acpi_madt_local_x2apic * processor = NULL ;
processor = ( struct acpi_madt_local_x2apic * ) header ;
if ( BAD_MADT_ENTRY ( processor , end ) )
return - EINVAL ;
acpi_table_print_madt_entry ( header ) ;
# ifdef CONFIG_X86_X2APIC
/*
* 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 .
*/
acpi_register_lapic ( processor - > local_apic_id , /* APIC ID */
processor - > lapic_flags & ACPI_MADT_ENABLED ) ;
# else
printk ( KERN_WARNING PREFIX " x2apic entry ignored \n " ) ;
# endif
return 0 ;
}
2005-04-16 15:20:36 -07:00
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 .
*/
2008-04-04 23:41:50 +04:00
acpi_register_lapic ( processor - > id , /* APIC ID */
processor - > lapic_flags & ACPI_MADT_ENABLED ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2008-03-28 14:12:09 -05:00
static int __init
acpi_parse_sapic ( struct acpi_subtable_header * header , const unsigned long end )
{
struct acpi_madt_local_sapic * processor = NULL ;
processor = ( struct acpi_madt_local_sapic * ) header ;
if ( BAD_MADT_ENTRY ( processor , end ) )
return - EINVAL ;
acpi_table_print_madt_entry ( header ) ;
2008-04-04 23:41:50 +04:00
acpi_register_lapic ( ( processor - > id < < 8 ) | processor - > eid , /* APIC ID */
processor - > lapic_flags & ACPI_MADT_ENABLED ) ;
2008-03-28 14:12:09 -05:00
return 0 ;
}
2005-04-16 15:20:36 -07:00
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 ;
}
2009-03-30 13:55:30 -08:00
static int __init
acpi_parse_x2apic_nmi ( struct acpi_subtable_header * header ,
const unsigned long end )
{
struct acpi_madt_local_x2apic_nmi * x2apic_nmi = NULL ;
x2apic_nmi = ( struct acpi_madt_local_x2apic_nmi * ) header ;
if ( BAD_MADT_ENTRY ( x2apic_nmi , end ) )
return - EINVAL ;
acpi_table_print_madt_entry ( header ) ;
if ( x2apic_nmi - > lint ! = 1 )
printk ( KERN_WARNING PREFIX " NMI not connected to LINT 1! \n " ) ;
return 0 ;
}
2005-04-16 15:20:36 -07:00
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 .
2007-10-20 01:13:56 +02:00
* ECLR1 is IRQs 0 - 7 ( IRQ 0 , 1 , 2 must be 0 )
* ECLR2 is IRQs 8 - 15 ( IRQ 8 , 13 must be 0 )
2005-04-16 15:20:36 -07:00
*/
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 ) ;
/*
2007-10-20 01:13:56 +02:00
* If we use ACPI to set PCI IRQs , then we should clear ELCR
2005-04-16 15:20:36 -07:00
* 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
*/
2009-05-15 13:05:16 -07:00
int acpi_register_gsi ( struct device * dev , u32 gsi , int trigger , 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 ) {
2009-05-15 13:05:16 -07:00
if ( trigger = = 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 ) {
2009-05-15 13:05:16 -07:00
plat_gsi = mp_register_gsi ( dev , gsi , trigger , 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
/*
* ACPI based hotplug support for CPU
*/
# ifdef CONFIG_ACPI_HOTPLUG_CPU
2008-02-01 17:49:42 +01:00
static int __cpuinit _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 ;
2008-12-31 18:08:47 -08:00
cpumask_var_t tmp_map , new_map ;
2006-09-26 10:52:35 +02:00
u8 physid ;
int cpu ;
2008-12-31 18:08:47 -08:00
int retval = - ENOMEM ;
2006-09-26 10:52:35 +02:00
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 ;
2008-12-31 18:08:47 -08:00
if ( ! alloc_cpumask_var ( & tmp_map , GFP_KERNEL ) )
goto out ;
if ( ! alloc_cpumask_var ( & new_map , GFP_KERNEL ) )
goto free_tmp_map ;
cpumask_copy ( tmp_map , cpu_present_mask ) ;
2008-04-04 23:41:50 +04:00
acpi_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
*/
2008-12-31 18:08:47 -08:00
cpumask_andnot ( new_map , cpu_present_mask , tmp_map ) ;
if ( cpumask_empty ( new_map ) ) {
2006-09-26 10:52:35 +02:00
printk ( " Unable to map lapic to logical cpu number \n " ) ;
2008-12-31 18:08:47 -08:00
retval = - EINVAL ;
goto free_new_map ;
2006-09-26 10:52:35 +02:00
}
2008-12-31 18:08:47 -08:00
cpu = cpumask_first ( new_map ) ;
2006-09-26 10:52:35 +02:00
* pcpu = cpu ;
2008-12-31 18:08:47 -08:00
retval = 0 ;
free_new_map :
free_cpumask_var ( new_map ) ;
free_tmp_map :
free_cpumask_var ( tmp_map ) ;
out :
return retval ;
2005-04-16 15:20:36 -07:00
}
2008-02-01 17:49:42 +01:00
/* wrapper to silence section mismatch warning */
int __ref acpi_map_lsapic ( acpi_handle handle , int * pcpu )
{
return _acpi_map_lsapic ( handle , pcpu ) ;
}
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
{
2007-10-19 20:35:03 +02:00
per_cpu ( x86_cpu_to_apicid , cpu ) = - 1 ;
2008-12-31 18:08:46 -08:00
set_cpu_present ( cpu , false ) ;
2006-09-26 10:52:35 +02:00
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 ) ;
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-16 01:28:18 -08:00
# include <asm/hpet.h>
2005-04-16 15:20:36 -07:00
2007-07-21 17:11:39 +02:00
static struct __initdata resource * hpet_res ;
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 ;
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
2007-02-16 01:28:18 -08:00
hpet_address = hpet_tbl - > address . address ;
2007-11-15 21:41:50 -05:00
/*
* Some broken BIOSes advertise HPET at 0x0 . We really do not
* want to allocate a resource there .
*/
if ( ! hpet_address ) {
printk ( KERN_WARNING PREFIX
" HPET id: %#x base: %#lx is invalid \n " ,
hpet_tbl - > id , hpet_address ) ;
return 0 ;
}
# ifdef CONFIG_X86_64
/*
* Some even more broken BIOSes advertise HPET at
* 0xfed0000000000000 instead of 0xfed00000 . Fix it up and add
* some noise :
*/
if ( hpet_address = = 0xfed0000000000000UL ) {
if ( ! hpet_force_user ) {
printk ( KERN_WARNING PREFIX " HPET id: %#x "
" base: 0xfed0000000000000 is bogus \n "
" try hpet=force on the kernel command line to "
" fix it up to 0xfed00000. \n " , hpet_tbl - > id ) ;
hpet_address = 0 ;
return 0 ;
}
printk ( KERN_WARNING PREFIX
" HPET id: %#x base: 0xfed0000000000000 fixed up "
" to 0xfed00000. \n " , hpet_tbl - > id ) ;
hpet_address > > = 32 ;
}
# endif
2005-08-05 00:44:28 -04:00
printk ( KERN_INFO PREFIX " HPET id: %#x base: %#lx \n " ,
2007-02-16 01:28:18 -08:00
hpet_tbl - > id , hpet_address ) ;
2005-04-16 15:20:36 -07:00
2007-07-21 17:11:39 +02:00
/*
* Allocate and initialize the HPET firmware resource for adding into
* the resource tree during the lateinit timeframe .
*/
# define HPET_RESOURCE_NAME_SIZE 9
hpet_res = alloc_bootmem ( sizeof ( * hpet_res ) + HPET_RESOURCE_NAME_SIZE ) ;
hpet_res - > name = ( void * ) & hpet_res [ 1 ] ;
hpet_res - > flags = IORESOURCE_MEM ;
snprintf ( ( char * ) hpet_res - > name , HPET_RESOURCE_NAME_SIZE , " HPET %u " ,
hpet_tbl - > sequence ) ;
hpet_res - > start = hpet_address ;
hpet_res - > end = hpet_address + ( 1 * 1024 ) - 1 ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2007-07-21 17:11:39 +02:00
/*
* hpet_insert_resource inserts the HPET resources used into the resource
* tree .
*/
static __init int hpet_insert_resource ( void )
{
if ( ! hpet_res )
return 1 ;
return insert_resource ( & iomem_resource , hpet_res ) ;
}
late_initcall ( hpet_insert_resource ) ;
2005-04-16 15:20:36 -07:00
# 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 ;
}
# ifdef CONFIG_X86_LOCAL_APIC
/*
* Parse LAPIC entries in MADT
* returns 0 on success , < 0 on error
*/
2008-04-04 23:41:57 +04:00
static void __init acpi_register_lapic_address ( unsigned long address )
{
mp_lapic_addr = address ;
set_fixmap_nocache ( FIX_APIC_BASE , address ) ;
2008-05-22 18:22:30 -07:00
if ( boot_cpu_physical_apicid = = - 1U ) {
2008-07-11 18:44:16 -07:00
boot_cpu_physical_apicid = read_apic_id ( ) ;
2008-05-22 18:22:30 -07:00
apic_version [ boot_cpu_physical_apicid ] =
GET_APIC_VERSION ( apic_read ( APIC_LVR ) ) ;
}
2008-04-04 23:41:57 +04:00
}
2008-02-19 03:21:06 -08:00
static int __init early_acpi_parse_madt_lapic_addr_ovr ( void )
{
int count ;
if ( ! cpu_has_apic )
return - ENODEV ;
/*
* 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 ) .
*/
count =
acpi_table_parse_madt ( ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE ,
acpi_parse_lapic_addr_ovr , 0 ) ;
if ( count < 0 ) {
printk ( KERN_ERR PREFIX
" Error parsing LAPIC address override entry \n " ) ;
return count ;
}
acpi_register_lapic_address ( acpi_lapic_addr ) ;
return count ;
}
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 ;
2009-03-30 13:55:30 -08:00
int x2count = 0 ;
2005-04-16 15:20:36 -07:00
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 ;
}
2008-04-04 23:41:57 +04:00
acpi_register_lapic_address ( acpi_lapic_addr ) ;
2005-04-16 15:20:36 -07:00
2008-03-28 14:12:09 -05:00
count = acpi_table_parse_madt ( ACPI_MADT_TYPE_LOCAL_SAPIC ,
acpi_parse_sapic , MAX_APICS ) ;
2009-03-30 13:55:30 -08:00
if ( ! count ) {
x2count = acpi_table_parse_madt ( ACPI_MADT_TYPE_LOCAL_X2APIC ,
acpi_parse_x2apic , MAX_APICS ) ;
2008-03-28 14:12:09 -05:00
count = acpi_table_parse_madt ( ACPI_MADT_TYPE_LOCAL_APIC ,
acpi_parse_lapic , MAX_APICS ) ;
2009-03-30 13:55:30 -08:00
}
if ( ! count & & ! x2count ) {
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 ;
2009-03-30 13:55:30 -08:00
} else if ( count < 0 | | x2count < 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 ;
}
2009-03-30 13:55:30 -08:00
x2count =
acpi_table_parse_madt ( ACPI_MADT_TYPE_LOCAL_X2APIC_NMI ,
acpi_parse_x2apic_nmi , 0 ) ;
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 ) ;
2009-03-30 13:55:30 -08:00
if ( count < 0 | | x2count < 0 ) {
2005-04-16 15:20:36 -07:00
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
2008-05-14 19:02:57 +04:00
# define MP_ISA_BUS 0
2008-06-08 18:31:54 -07:00
# ifdef CONFIG_X86_ES7000
2008-05-14 19:02:57 +04:00
extern int es7000_plat ;
# endif
2009-02-08 16:18:03 -08:00
int __init acpi_probe_gsi ( void )
{
int idx ;
int gsi ;
int max_gsi = 0 ;
if ( acpi_disabled )
return 0 ;
if ( ! acpi_ioapic )
return 0 ;
max_gsi = 0 ;
for ( idx = 0 ; idx < nr_ioapics ; idx + + ) {
2009-07-07 23:01:15 -04:00
gsi = mp_gsi_routing [ idx ] . gsi_end ;
2009-02-08 16:18:03 -08:00
if ( gsi > max_gsi )
max_gsi = gsi ;
}
return max_gsi + 1 ;
}
2009-01-12 17:47:22 +05:30
static void assign_to_mp_irq ( struct mpc_intsrc * m ,
struct mpc_intsrc * mp_irq )
2008-06-18 17:29:31 -07:00
{
2009-01-12 17:47:22 +05:30
memcpy ( mp_irq , m , sizeof ( struct mpc_intsrc ) ) ;
2008-06-18 17:29:31 -07:00
}
2009-01-12 17:47:22 +05:30
static int mp_irq_cmp ( struct mpc_intsrc * mp_irq ,
struct mpc_intsrc * m )
2008-06-18 17:29:31 -07:00
{
2009-01-12 17:47:22 +05:30
return memcmp ( mp_irq , m , sizeof ( struct mpc_intsrc ) ) ;
2008-06-18 17:29:31 -07:00
}
2009-01-12 17:47:22 +05:30
static void save_mp_irq ( struct mpc_intsrc * m )
2008-06-18 17:29:31 -07:00
{
int i ;
for ( i = 0 ; i < mp_irq_entries ; i + + ) {
if ( ! mp_irq_cmp ( & mp_irqs [ i ] , m ) )
return ;
}
assign_to_mp_irq ( m , & mp_irqs [ mp_irq_entries ] ) ;
if ( + + mp_irq_entries = = MAX_IRQ_SOURCES )
panic ( " Max # of irq sources exceeded!! \n " ) ;
}
2008-05-14 19:02:57 +04:00
void __init mp_override_legacy_irq ( u8 bus_irq , u8 polarity , u8 trigger , u32 gsi )
{
2008-06-15 18:19:46 -07:00
int ioapic ;
int pin ;
2009-01-12 17:47:22 +05:30
struct mpc_intsrc mp_irq ;
2008-05-14 19:02:57 +04:00
/*
* Convert ' gsi ' to ' ioapic . pin ' .
*/
ioapic = mp_find_ioapic ( gsi ) ;
if ( ioapic < 0 )
return ;
2009-02-09 12:05:47 -08:00
pin = mp_find_ioapic_pin ( ioapic , gsi ) ;
2008-05-14 19:02:57 +04:00
/*
* TBD : This check is for faulty timer entries , where the override
* erroneously sets the trigger to level , resulting in a HUGE
* increase of timer interrupts !
*/
if ( ( bus_irq = = 0 ) & & ( trigger = = 3 ) )
trigger = 1 ;
2009-01-12 17:47:22 +05:30
mp_irq . type = MP_INTSRC ;
mp_irq . irqtype = mp_INT ;
mp_irq . irqflag = ( trigger < < 2 ) | polarity ;
mp_irq . srcbus = MP_ISA_BUS ;
mp_irq . srcbusirq = bus_irq ; /* IRQ */
mp_irq . dstapic = mp_ioapics [ ioapic ] . apicid ; /* APIC ID */
mp_irq . dstirq = pin ; /* INTIN# */
2008-05-14 19:02:57 +04:00
2008-06-18 17:29:31 -07:00
save_mp_irq ( & mp_irq ) ;
2008-05-14 19:02:57 +04:00
}
void __init mp_config_acpi_legacy_irqs ( void )
{
2008-06-15 18:19:46 -07:00
int i ;
int ioapic ;
unsigned int dstapic ;
2009-01-12 17:47:22 +05:30
struct mpc_intsrc mp_irq ;
2008-05-14 19:02:57 +04:00
# if defined (CONFIG_MCA) || defined (CONFIG_EISA)
/*
* Fabricate the legacy ISA bus ( bus # 31 ) .
*/
mp_bus_id_to_type [ MP_ISA_BUS ] = MP_BUS_ISA ;
# endif
set_bit ( MP_ISA_BUS , mp_bus_not_pci ) ;
2008-07-21 21:35:38 +02:00
pr_debug ( " Bus #%d is ISA \n " , MP_ISA_BUS ) ;
2008-05-14 19:02:57 +04:00
2008-06-08 18:31:54 -07:00
# ifdef CONFIG_X86_ES7000
2008-05-14 19:02:57 +04:00
/*
* Older generations of ES7000 have no legacy identity mappings
*/
if ( es7000_plat = = 1 )
return ;
# endif
/*
* Locate the IOAPIC that manages the ISA IRQs ( 0 - 15 ) .
*/
ioapic = mp_find_ioapic ( 0 ) ;
if ( ioapic < 0 )
return ;
2009-01-12 17:46:17 +05:30
dstapic = mp_ioapics [ ioapic ] . apicid ;
2008-05-14 19:02:57 +04:00
/*
* Use the default configuration for the IRQs 0 - 15. Unless
* overridden by ( MADT ) interrupt source override entries .
*/
for ( i = 0 ; i < 16 ; i + + ) {
int idx ;
for ( idx = 0 ; idx < mp_irq_entries ; idx + + ) {
2009-01-12 17:47:22 +05:30
struct mpc_intsrc * irq = mp_irqs + idx ;
2008-05-14 19:02:57 +04:00
/* Do we already have a mapping for this ISA IRQ? */
2009-01-12 17:47:22 +05:30
if ( irq - > srcbus = = MP_ISA_BUS & & irq - > srcbusirq = = i )
2008-05-14 19:02:57 +04:00
break ;
/* Do we already have a mapping for this IOAPIC pin */
2009-01-12 17:47:22 +05:30
if ( irq - > dstapic = = dstapic & & irq - > dstirq = = i )
2008-05-14 19:02:57 +04:00
break ;
}
if ( idx ! = mp_irq_entries ) {
printk ( KERN_DEBUG " ACPI: IRQ%d used by override. \n " , i ) ;
continue ; /* IRQ already used */
}
2009-01-12 17:47:22 +05:30
mp_irq . type = MP_INTSRC ;
mp_irq . irqflag = 0 ; /* Conforming */
mp_irq . srcbus = MP_ISA_BUS ;
mp_irq . dstapic = dstapic ;
mp_irq . irqtype = mp_INT ;
mp_irq . srcbusirq = i ; /* Identity mapped */
mp_irq . dstirq = i ;
2008-05-14 19:02:57 +04:00
2008-06-18 17:29:31 -07:00
save_mp_irq ( & mp_irq ) ;
2008-05-14 19:02:57 +04:00
}
}
2009-05-15 13:05:16 -07:00
static int mp_config_acpi_gsi ( struct device * dev , u32 gsi , int trigger ,
2009-05-06 10:06:15 -07:00
int polarity )
{
# ifdef CONFIG_X86_MPPARSE
struct mpc_intsrc mp_irq ;
struct pci_dev * pdev ;
unsigned char number ;
unsigned int devfn ;
int ioapic ;
u8 pin ;
if ( ! acpi_ioapic )
return 0 ;
if ( ! dev )
return 0 ;
if ( dev - > bus ! = & pci_bus_type )
return 0 ;
pdev = to_pci_dev ( dev ) ;
number = pdev - > bus - > number ;
devfn = pdev - > devfn ;
pin = pdev - > pin ;
/* print the entry should happen on mptable identically */
mp_irq . type = MP_INTSRC ;
mp_irq . irqtype = mp_INT ;
2009-05-15 13:05:16 -07:00
mp_irq . irqflag = ( trigger = = ACPI_EDGE_SENSITIVE ? 4 : 0x0c ) |
2009-05-06 10:06:15 -07:00
( polarity = = ACPI_ACTIVE_HIGH ? 1 : 3 ) ;
mp_irq . srcbus = number ;
mp_irq . srcbusirq = ( ( ( devfn > > 3 ) & 0x1f ) < < 2 ) | ( ( pin - 1 ) & 3 ) ;
ioapic = mp_find_ioapic ( gsi ) ;
2009-05-06 10:07:41 -07:00
mp_irq . dstapic = mp_ioapics [ ioapic ] . apicid ;
2009-05-06 10:06:15 -07:00
mp_irq . dstirq = mp_find_ioapic_pin ( ioapic , gsi ) ;
save_mp_irq ( & mp_irq ) ;
# endif
return 0 ;
}
2009-05-15 13:05:16 -07:00
int mp_register_gsi ( struct device * dev , u32 gsi , int trigger , int polarity )
2008-05-14 19:02:57 +04:00
{
int ioapic ;
int ioapic_pin ;
2009-05-15 13:05:16 -07:00
struct io_apic_irq_attr irq_attr ;
2008-05-14 19:02:57 +04:00
if ( acpi_irq_model ! = ACPI_IRQ_MODEL_IOAPIC )
return gsi ;
/* Don't set up the ACPI SCI because it's already set up */
if ( acpi_gbl_FADT . sci_interrupt = = gsi )
return gsi ;
ioapic = mp_find_ioapic ( gsi ) ;
if ( ioapic < 0 ) {
printk ( KERN_WARNING " No IOAPIC for GSI %u \n " , gsi ) ;
return gsi ;
}
2009-02-09 12:05:47 -08:00
ioapic_pin = mp_find_ioapic_pin ( ioapic , gsi ) ;
2008-05-14 19:02:57 +04:00
# ifdef CONFIG_X86_32
if ( ioapic_renumber_irq )
gsi = ioapic_renumber_irq ( ioapic , gsi ) ;
# endif
if ( ioapic_pin > MP_MAX_IOAPIC_PIN ) {
printk ( KERN_ERR " Invalid reference to IOAPIC pin "
2009-05-06 10:07:41 -07:00
" %d-%d \n " , mp_ioapics [ ioapic ] . apicid ,
2008-05-14 19:02:57 +04:00
ioapic_pin ) ;
return gsi ;
}
2009-05-15 13:05:16 -07:00
if ( enable_update_mptable )
mp_config_acpi_gsi ( dev , gsi , trigger , polarity ) ;
x86/acpi: remove irq-compression trick on 32-bit
We already have a per cpu vector on 32-bit via recent changes, and
don't need this trick any more (which trick obfuscates the real GSI
mappings and which only triggers on larger systems to begin with):
On 3 ioapic system (24 per ioapic) before patch I got:
ACPI: PCI Interrupt Link [ILSB] enabled at IRQ 71
IOAPIC[2]: Set routing entry (10-23 -> 0xa9 -> IRQ 64 Mode:1 Active:1)
pci 0000:80:01.1: PCI INT A -> Link[ILSB] -> GSI 71 (level, low) -> IRQ 64
ACPI: PCI Interrupt Link [LE5B] enabled at IRQ 67
IOAPIC[2]: Set routing entry (10-19 -> 0xb1 -> IRQ 65 Mode:1 Active:1)
pci 0000:83:00.0: PCI INT B -> Link[LE5B] -> GSI 67 (level, low) -> IRQ 65
ACPI: PCI Interrupt Link [LE5A] enabled at IRQ 66
IOAPIC[2]: Set routing entry (10-18 -> 0xb9 -> IRQ 66 Mode:1 Active:1)
pci 0000:83:00.1: PCI INT A -> Link[LE5A] -> GSI 66 (level, low) -> IRQ 66
ACPI: PCI Interrupt Link [LE5D] enabled at IRQ 65
IOAPIC[2]: Set routing entry (10-17 -> 0xc1 -> IRQ 67 Mode:1 Active:1)
pci 0000:84:00.0: PCI INT B -> Link[LE5D] -> GSI 65 (level, low) -> IRQ 67
ACPI: PCI Interrupt Link [LE5C] enabled at IRQ 64
IOAPIC[2]: Set routing entry (10-16 -> 0xc9 -> IRQ 68 Mode:1 Active:1)
pci 0000:84:00.1: PCI INT A -> Link[LE5C] -> GSI 64 (level, low) -> IRQ 68
pci 0000:87:00.0: PCI INT B -> Link[LE5A] -> GSI 66 (level, low) -> IRQ 66
pci 0000:87:00.1: PCI INT A -> Link[LE5D] -> GSI 65 (level, low) -> IRQ 67
pci 0000:88:00.0: PCI INT B -> Link[LE5C] -> GSI 64 (level, low) -> IRQ 68
pci 0000:88:00.1: PCI INT A -> Link[LE5B] -> GSI 67 (level, low) -> IRQ 65
pci 0000:8b:00.0: PCI INT B -> Link[LE5A] -> GSI 66 (level, low) -> IRQ 66
pci 0000:8b:00.1: PCI INT A -> Link[LE5D] -> GSI 65 (level, low) -> IRQ 67
pci 0000:8c:00.0: PCI INT B -> Link[LE5C] -> GSI 64 (level, low) -> IRQ 68
pci 0000:8c:00.1: PCI INT A -> Link[LE5B] -> GSI 67 (level, low) -> IRQ 65
after the patch we get:
ACPI: PCI Interrupt Link [ILSB] enabled at IRQ 71
IOAPIC[2]: Set routing entry (10-23 -> 0xa9 -> IRQ 71 Mode:1 Active:1)
pci 0000:80:01.1: PCI INT A -> Link[ILSB] -> GSI 71 (level, low) -> IRQ 71
ACPI: PCI Interrupt Link [LE5B] enabled at IRQ 67
IOAPIC[2]: Set routing entry (10-19 -> 0xb1 -> IRQ 67 Mode:1 Active:1)
pci 0000:83:00.0: PCI INT B -> Link[LE5B] -> GSI 67 (level, low) -> IRQ 67
ACPI: PCI Interrupt Link [LE5A] enabled at IRQ 66
IOAPIC[2]: Set routing entry (10-18 -> 0xb9 -> IRQ 66 Mode:1 Active:1)
pci 0000:83:00.1: PCI INT A -> Link[LE5A] -> GSI 66 (level, low) -> IRQ 66
ACPI: PCI Interrupt Link [LE5D] enabled at IRQ 65
IOAPIC[2]: Set routing entry (10-17 -> 0xc1 -> IRQ 65 Mode:1 Active:1)
pci 0000:84:00.0: PCI INT B -> Link[LE5D] -> GSI 65 (level, low) -> IRQ 65
ACPI: PCI Interrupt Link [LE5C] enabled at IRQ 64
IOAPIC[2]: Set routing entry (10-16 -> 0xc9 -> IRQ 64 Mode:1 Active:1)
pci 0000:84:00.1: PCI INT A -> Link[LE5C] -> GSI 64 (level, low) -> IRQ 64
pci 0000:87:00.0: PCI INT B -> Link[LE5A] -> GSI 66 (level, low) -> IRQ 66
pci 0000:87:00.1: PCI INT A -> Link[LE5D] -> GSI 65 (level, low) -> IRQ 65
pci 0000:88:00.0: PCI INT B -> Link[LE5C] -> GSI 64 (level, low) -> IRQ 64
pci 0000:88:00.1: PCI INT A -> Link[LE5B] -> GSI 67 (level, low) -> IRQ 67
pci 0000:8b:00.0: PCI INT B -> Link[LE5A] -> GSI 66 (level, low) -> IRQ 66
pci 0000:8b:00.1: PCI INT A -> Link[LE5D] -> GSI 65 (level, low) -> IRQ 65
pci 0000:8c:00.0: PCI INT B -> Link[LE5C] -> GSI 64 (level, low) -> IRQ 64
pci 0000:8c:00.1: PCI INT A -> Link[LE5B] -> GSI 67 (level, low) -> IRQ 67
As it can be seen that GSIs now get mapped lineary.
[ Impact: simplify irq number mapping on bigger 32-bit systems ]
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: Len Brown <lenb@kernel.org>
LKML-Reference: <4A01C35C.7060207@kernel.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2009-05-06 10:05:32 -07:00
2009-05-15 13:05:16 -07:00
set_io_apic_irq_attr ( & irq_attr , ioapic , ioapic_pin ,
trigger = = ACPI_EDGE_SENSITIVE ? 0 : 1 ,
polarity = = ACPI_ACTIVE_HIGH ? 0 : 1 ) ;
io_apic_set_pci_routing ( dev , gsi , & irq_attr ) ;
x86/acpi: remove irq-compression trick on 32-bit
We already have a per cpu vector on 32-bit via recent changes, and
don't need this trick any more (which trick obfuscates the real GSI
mappings and which only triggers on larger systems to begin with):
On 3 ioapic system (24 per ioapic) before patch I got:
ACPI: PCI Interrupt Link [ILSB] enabled at IRQ 71
IOAPIC[2]: Set routing entry (10-23 -> 0xa9 -> IRQ 64 Mode:1 Active:1)
pci 0000:80:01.1: PCI INT A -> Link[ILSB] -> GSI 71 (level, low) -> IRQ 64
ACPI: PCI Interrupt Link [LE5B] enabled at IRQ 67
IOAPIC[2]: Set routing entry (10-19 -> 0xb1 -> IRQ 65 Mode:1 Active:1)
pci 0000:83:00.0: PCI INT B -> Link[LE5B] -> GSI 67 (level, low) -> IRQ 65
ACPI: PCI Interrupt Link [LE5A] enabled at IRQ 66
IOAPIC[2]: Set routing entry (10-18 -> 0xb9 -> IRQ 66 Mode:1 Active:1)
pci 0000:83:00.1: PCI INT A -> Link[LE5A] -> GSI 66 (level, low) -> IRQ 66
ACPI: PCI Interrupt Link [LE5D] enabled at IRQ 65
IOAPIC[2]: Set routing entry (10-17 -> 0xc1 -> IRQ 67 Mode:1 Active:1)
pci 0000:84:00.0: PCI INT B -> Link[LE5D] -> GSI 65 (level, low) -> IRQ 67
ACPI: PCI Interrupt Link [LE5C] enabled at IRQ 64
IOAPIC[2]: Set routing entry (10-16 -> 0xc9 -> IRQ 68 Mode:1 Active:1)
pci 0000:84:00.1: PCI INT A -> Link[LE5C] -> GSI 64 (level, low) -> IRQ 68
pci 0000:87:00.0: PCI INT B -> Link[LE5A] -> GSI 66 (level, low) -> IRQ 66
pci 0000:87:00.1: PCI INT A -> Link[LE5D] -> GSI 65 (level, low) -> IRQ 67
pci 0000:88:00.0: PCI INT B -> Link[LE5C] -> GSI 64 (level, low) -> IRQ 68
pci 0000:88:00.1: PCI INT A -> Link[LE5B] -> GSI 67 (level, low) -> IRQ 65
pci 0000:8b:00.0: PCI INT B -> Link[LE5A] -> GSI 66 (level, low) -> IRQ 66
pci 0000:8b:00.1: PCI INT A -> Link[LE5D] -> GSI 65 (level, low) -> IRQ 67
pci 0000:8c:00.0: PCI INT B -> Link[LE5C] -> GSI 64 (level, low) -> IRQ 68
pci 0000:8c:00.1: PCI INT A -> Link[LE5B] -> GSI 67 (level, low) -> IRQ 65
after the patch we get:
ACPI: PCI Interrupt Link [ILSB] enabled at IRQ 71
IOAPIC[2]: Set routing entry (10-23 -> 0xa9 -> IRQ 71 Mode:1 Active:1)
pci 0000:80:01.1: PCI INT A -> Link[ILSB] -> GSI 71 (level, low) -> IRQ 71
ACPI: PCI Interrupt Link [LE5B] enabled at IRQ 67
IOAPIC[2]: Set routing entry (10-19 -> 0xb1 -> IRQ 67 Mode:1 Active:1)
pci 0000:83:00.0: PCI INT B -> Link[LE5B] -> GSI 67 (level, low) -> IRQ 67
ACPI: PCI Interrupt Link [LE5A] enabled at IRQ 66
IOAPIC[2]: Set routing entry (10-18 -> 0xb9 -> IRQ 66 Mode:1 Active:1)
pci 0000:83:00.1: PCI INT A -> Link[LE5A] -> GSI 66 (level, low) -> IRQ 66
ACPI: PCI Interrupt Link [LE5D] enabled at IRQ 65
IOAPIC[2]: Set routing entry (10-17 -> 0xc1 -> IRQ 65 Mode:1 Active:1)
pci 0000:84:00.0: PCI INT B -> Link[LE5D] -> GSI 65 (level, low) -> IRQ 65
ACPI: PCI Interrupt Link [LE5C] enabled at IRQ 64
IOAPIC[2]: Set routing entry (10-16 -> 0xc9 -> IRQ 64 Mode:1 Active:1)
pci 0000:84:00.1: PCI INT A -> Link[LE5C] -> GSI 64 (level, low) -> IRQ 64
pci 0000:87:00.0: PCI INT B -> Link[LE5A] -> GSI 66 (level, low) -> IRQ 66
pci 0000:87:00.1: PCI INT A -> Link[LE5D] -> GSI 65 (level, low) -> IRQ 65
pci 0000:88:00.0: PCI INT B -> Link[LE5C] -> GSI 64 (level, low) -> IRQ 64
pci 0000:88:00.1: PCI INT A -> Link[LE5B] -> GSI 67 (level, low) -> IRQ 67
pci 0000:8b:00.0: PCI INT B -> Link[LE5A] -> GSI 66 (level, low) -> IRQ 66
pci 0000:8b:00.1: PCI INT A -> Link[LE5D] -> GSI 65 (level, low) -> IRQ 65
pci 0000:8c:00.0: PCI INT B -> Link[LE5C] -> GSI 64 (level, low) -> IRQ 64
pci 0000:8c:00.1: PCI INT A -> Link[LE5B] -> GSI 67 (level, low) -> IRQ 67
As it can be seen that GSIs now get mapped lineary.
[ Impact: simplify irq number mapping on bigger 32-bit systems ]
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: Len Brown <lenb@kernel.org>
LKML-Reference: <4A01C35C.7060207@kernel.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2009-05-06 10:05:32 -07:00
2008-05-14 19:02:57 +04:00
return gsi ;
}
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
*/
2009-06-08 02:53:50 -07:00
if ( acpi_disabled | | acpi_noirq )
2005-04-16 15:20:36 -07:00
return - ENODEV ;
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 ,
2008-08-19 20:50:03 -07:00
nr_irqs ) ;
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 ,
2008-08-19 20:50:03 -07:00
nr_irqs ) ;
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
2008-02-19 03:21:06 -08:00
static void __init early_acpi_process_madt ( void )
{
# ifdef CONFIG_X86_LOCAL_APIC
int error ;
if ( ! acpi_table_parse ( ACPI_SIG_MADT , acpi_parse_madt ) ) {
/*
* Parse MADT LAPIC entries
*/
error = early_acpi_parse_madt_lapic_addr_ovr ( ) ;
if ( ! error ) {
acpi_lapic = 1 ;
smp_found_config = 1 ;
}
if ( error = = - EINVAL ) {
/*
* Dell Precision Workstation 410 , 610 come here .
*/
printk ( KERN_ERR PREFIX
" Invalid BIOS MADT, disabling ACPI \n " ) ;
disable_acpi ( ) ;
}
}
# endif
}
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
2007-02-10 21:28:03 -05:00
int error ;
2005-04-16 15:20:36 -07:00
2007-02-10 21:28:03 -05:00
if ( ! acpi_table_parse ( ACPI_SIG_MADT , acpi_parse_madt ) ) {
2005-04-16 15:20:36 -07:00
/*
* Parse MADT LAPIC entries
*/
error = acpi_parse_madt_lapic_entries ( ) ;
if ( ! error ) {
acpi_lapic = 1 ;
2009-01-29 14:19:22 -08:00
# ifdef CONFIG_X86_BIGSMP
2005-09-03 15:56:31 -07:00
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_ioapic = 1 ;
smp_found_config = 1 ;
2009-01-28 06:50:47 +01:00
if ( apic - > setup_apic_routing )
apic - > setup_apic_routing ( ) ;
2005-04-16 15:20:36 -07:00
}
}
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 ( ) ;
}
2008-12-23 01:47:42 -05:00
} else {
/*
* ACPI found no MADT , and so ACPI wants UP PIC mode .
* In the event an MPS table was found , forget it .
* Boot with " acpi=off " to use MPS on such a system .
*/
if ( smp_found_config ) {
printk ( KERN_WARNING PREFIX
" No APIC-table, disabling MPS \n " ) ;
smp_found_config = 0 ;
}
2005-04-16 15:20:36 -07:00
}
2008-12-05 22:45:50 -08:00
/*
* ACPI supports both logical ( e . g . Hyper - Threading ) and physical
* processors , where MPS only supports physical .
*/
if ( acpi_lapic & & acpi_ioapic )
printk ( KERN_INFO " Using ACPI (MADT) for SMP configuration "
" information \n " ) ;
else if ( acpi_lapic )
printk ( KERN_INFO " Using ACPI for processor (LAPIC) "
" configuration information \n " ) ;
2005-04-16 15:20:36 -07:00
# endif
return ;
}
2007-10-03 15:15:40 -04:00
static int __init disable_acpi_irq ( const struct dmi_system_id * d )
2005-06-25 14:54:42 -07:00
{
if ( ! acpi_force ) {
printk ( KERN_NOTICE " %s detected: force use of acpi=noirq \n " ,
d - > ident ) ;
acpi_noirq_set ( ) ;
}
return 0 ;
}
2007-10-03 15:15:40 -04:00
static int __init disable_acpi_pci ( const struct dmi_system_id * d )
2005-06-25 14:54:42 -07:00
{
if ( ! acpi_force ) {
printk ( KERN_NOTICE " %s detected: force use of pci=noacpi \n " ,
d - > ident ) ;
acpi_disable_pci ( ) ;
}
return 0 ;
}
2007-10-03 15:15:40 -04:00
static int __init dmi_disable_acpi ( const struct dmi_system_id * d )
2005-06-25 14:54:42 -07:00
{
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
*/
2007-10-03 15:15:40 -04:00
static int __init force_acpi_ht ( const struct dmi_system_id * d )
2005-06-25 14:54:42 -07:00
{
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 ;
}
x86: fix C1E && nx6325 stability problem
The problems are that, with the ACPI vs timer overring issue _fixed_,
after using the box for some time (between several seconds and 1 hour, at
random) processes get very high CPU loads (once I've got X using 107% of
the CPU, for example) and the system becomes unresponsive, as though there
were interrupts lost or something similar.
Andreas Herrman reproduced similar problems:
> Ok, now I've reproduced the stability problem.
> - Using tip/master,
> - reverting e38502eb8aa82314d5ab0eba45f50e6790dadd88 and
> - applying your patch from this posting
> http://marc.info/?l=linux-kernel&m=121539354224562&w=4
>
> Starting X, firefox, gimp, tuxpaint and doing some drawing in tuxpaint
> results in a slow system. Drawing is almost not possible anymore --
> Selections of new colors, cursors etc. is performed with huge delay
> if it's performed at all.
>
> BTW, the code sets up timer IRQ as Virtual Wire IRQ:
>
> Jul 8 14:57:58 kodscha IO-APIC (apicid-pin) 2-22, 2-23 not connected.
> Jul 8 14:57:58 kodscha ..TIMER: vector=0x30 apic1=0 pin1=2 apic2=-1 pin2=-1
> Jul 8 14:57:58 kodscha ...trying to set up timer as Virtual Wire IRQ... works.
>
> and both INT0 and INT2 of IOAPIC are masked:
>
> Jul 8 14:57:58 kodscha NR Dst Mask Trig IRR Pol Stat Dmod Deli Vect:
> Jul 8 14:57:58 kodscha 00 000 1 0 0 0 0 0 0 00
> Jul 8 14:57:58 kodscha 01 003 0 0 0 0 0 1 1 31
> Jul 8 14:57:58 kodscha 02 003 1 0 0 0 0 0 0 30
>
> I've also seen strange CPU utilization -- with syslog-ng:
>
> top - 15:33:06 up 35 min, 4 users, load average: 1.70, 0.68, 0.37
> Tasks: 64 total, 4 running, 60 sleeping, 0 stopped, 0 zombie
> Cpu0 : 0.0%us,100.0%sy, 0.0%ni, 0.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
> Cpu1 : 6.4%us, 87.2%sy, 0.0%ni, 5.8%id, 0.0%wa, 0.6%hi, 0.0%si, 0.0%st
> Mem: 895384k total, 283568k used, 611816k free, 35492k buffers
> Swap: 1959920k total, 0k used, 1959920k free, 163044k cached
>
> PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
> 4632 root 20 0 17216 800 580 S 104 0.1 0:34.22 syslog-ng
> 28505 root 20 0 205m 11m 4024 S 6 1.3 0:21.16 X
> 28518 root 20 0 56292 5652 4492 S 1 0.6 0:01.80 fluxbox
> 1 root 20 0 3724 608 508 S 0 0.1 0:00.36 init
>
> So far I have no clue why C1E-idle in conjunction with virtual wire
> mode causes this strange behaviour.
>
> ... and I start to think about the root cause of all this.
>
> I've performed similar tests under X with the IRQ0/INT0 configuration and
> I did not see above symptoms.
So lets fall back to the IRQ0/INT0 configuration on this box.
This basically restores the dont-use-the-lapic-timer exception mechanism
that was unconditional on this box prior commit 8750bf5 ("x86: add C1E
aware idle function").
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2008-07-08 16:12:26 +02:00
/*
* Force ignoring BIOS IRQ0 pin2 override
*/
static int __init dmi_ignore_irq0_timer_override ( const struct dmi_system_id * d )
{
2008-10-07 06:47:52 +02:00
/*
* The ati_ixp4x0_rev ( ) early PCI quirk should have set
* the acpi_skip_timer_override flag already :
*/
if ( ! acpi_skip_timer_override ) {
WARN ( 1 , KERN_ERR " ati_ixp4x0 quirk not complete. \n " ) ;
pr_notice ( " %s detected: Ignoring BIOS IRQ0 pin2 override \n " ,
d - > ident ) ;
acpi_skip_timer_override = 1 ;
}
x86: fix C1E && nx6325 stability problem
The problems are that, with the ACPI vs timer overring issue _fixed_,
after using the box for some time (between several seconds and 1 hour, at
random) processes get very high CPU loads (once I've got X using 107% of
the CPU, for example) and the system becomes unresponsive, as though there
were interrupts lost or something similar.
Andreas Herrman reproduced similar problems:
> Ok, now I've reproduced the stability problem.
> - Using tip/master,
> - reverting e38502eb8aa82314d5ab0eba45f50e6790dadd88 and
> - applying your patch from this posting
> http://marc.info/?l=linux-kernel&m=121539354224562&w=4
>
> Starting X, firefox, gimp, tuxpaint and doing some drawing in tuxpaint
> results in a slow system. Drawing is almost not possible anymore --
> Selections of new colors, cursors etc. is performed with huge delay
> if it's performed at all.
>
> BTW, the code sets up timer IRQ as Virtual Wire IRQ:
>
> Jul 8 14:57:58 kodscha IO-APIC (apicid-pin) 2-22, 2-23 not connected.
> Jul 8 14:57:58 kodscha ..TIMER: vector=0x30 apic1=0 pin1=2 apic2=-1 pin2=-1
> Jul 8 14:57:58 kodscha ...trying to set up timer as Virtual Wire IRQ... works.
>
> and both INT0 and INT2 of IOAPIC are masked:
>
> Jul 8 14:57:58 kodscha NR Dst Mask Trig IRR Pol Stat Dmod Deli Vect:
> Jul 8 14:57:58 kodscha 00 000 1 0 0 0 0 0 0 00
> Jul 8 14:57:58 kodscha 01 003 0 0 0 0 0 1 1 31
> Jul 8 14:57:58 kodscha 02 003 1 0 0 0 0 0 0 30
>
> I've also seen strange CPU utilization -- with syslog-ng:
>
> top - 15:33:06 up 35 min, 4 users, load average: 1.70, 0.68, 0.37
> Tasks: 64 total, 4 running, 60 sleeping, 0 stopped, 0 zombie
> Cpu0 : 0.0%us,100.0%sy, 0.0%ni, 0.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
> Cpu1 : 6.4%us, 87.2%sy, 0.0%ni, 5.8%id, 0.0%wa, 0.6%hi, 0.0%si, 0.0%st
> Mem: 895384k total, 283568k used, 611816k free, 35492k buffers
> Swap: 1959920k total, 0k used, 1959920k free, 163044k cached
>
> PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
> 4632 root 20 0 17216 800 580 S 104 0.1 0:34.22 syslog-ng
> 28505 root 20 0 205m 11m 4024 S 6 1.3 0:21.16 X
> 28518 root 20 0 56292 5652 4492 S 1 0.6 0:01.80 fluxbox
> 1 root 20 0 3724 608 508 S 0 0.1 0:00.36 init
>
> So far I have no clue why C1E-idle in conjunction with virtual wire
> mode causes this strange behaviour.
>
> ... and I start to think about the root cause of all this.
>
> I've performed similar tests under X with the IRQ0/INT0 configuration and
> I did not see above symptoms.
So lets fall back to the IRQ0/INT0 configuration on this box.
This basically restores the dont-use-the-lapic-timer exception mechanism
that was unconditional on this box prior commit 8750bf5 ("x86: add C1E
aware idle function").
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2008-07-08 16:12:26 +02:00
return 0 ;
}
2005-06-25 14:54:42 -07:00
/*
* If your system is blacklisted here , but you find that acpi = force
2009-04-01 01:49:42 -04:00
* works for you , please contact linux - acpi @ vger . kernel . org
2005-06-25 14:54:42 -07:00
*/
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 = " 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 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 " ) ,
} ,
} ,
2007-03-08 02:48:30 -05:00
{
/*
* Latest BIOS for IBM 600 E ( 1.16 ) has bad pcinum
* for LPC bridge , which is needed for the PCI
* interrupt links to work . DSDT fix is in bug 5966.
* 2645 , 2646 model numbers are shared with 600 / 600 E / 600 X
*/
. callback = disable_acpi_irq ,
. ident = " IBM Thinkpad 600 Series 2645 " ,
. matches = {
DMI_MATCH ( DMI_BOARD_VENDOR , " IBM " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " 2645 " ) ,
} ,
} ,
{
. callback = disable_acpi_irq ,
. ident = " IBM Thinkpad 600 Series 2646 " ,
. matches = {
DMI_MATCH ( DMI_BOARD_VENDOR , " IBM " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " 2646 " ) ,
} ,
} ,
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 " ) ,
} ,
} ,
2008-10-22 13:08:31 +02:00
{ }
} ;
/* second table for DMI checks that should run after early-quirks */
static struct dmi_system_id __initdata acpi_dmi_table_late [ ] = {
x86: fix C1E && nx6325 stability problem
The problems are that, with the ACPI vs timer overring issue _fixed_,
after using the box for some time (between several seconds and 1 hour, at
random) processes get very high CPU loads (once I've got X using 107% of
the CPU, for example) and the system becomes unresponsive, as though there
were interrupts lost or something similar.
Andreas Herrman reproduced similar problems:
> Ok, now I've reproduced the stability problem.
> - Using tip/master,
> - reverting e38502eb8aa82314d5ab0eba45f50e6790dadd88 and
> - applying your patch from this posting
> http://marc.info/?l=linux-kernel&m=121539354224562&w=4
>
> Starting X, firefox, gimp, tuxpaint and doing some drawing in tuxpaint
> results in a slow system. Drawing is almost not possible anymore --
> Selections of new colors, cursors etc. is performed with huge delay
> if it's performed at all.
>
> BTW, the code sets up timer IRQ as Virtual Wire IRQ:
>
> Jul 8 14:57:58 kodscha IO-APIC (apicid-pin) 2-22, 2-23 not connected.
> Jul 8 14:57:58 kodscha ..TIMER: vector=0x30 apic1=0 pin1=2 apic2=-1 pin2=-1
> Jul 8 14:57:58 kodscha ...trying to set up timer as Virtual Wire IRQ... works.
>
> and both INT0 and INT2 of IOAPIC are masked:
>
> Jul 8 14:57:58 kodscha NR Dst Mask Trig IRR Pol Stat Dmod Deli Vect:
> Jul 8 14:57:58 kodscha 00 000 1 0 0 0 0 0 0 00
> Jul 8 14:57:58 kodscha 01 003 0 0 0 0 0 1 1 31
> Jul 8 14:57:58 kodscha 02 003 1 0 0 0 0 0 0 30
>
> I've also seen strange CPU utilization -- with syslog-ng:
>
> top - 15:33:06 up 35 min, 4 users, load average: 1.70, 0.68, 0.37
> Tasks: 64 total, 4 running, 60 sleeping, 0 stopped, 0 zombie
> Cpu0 : 0.0%us,100.0%sy, 0.0%ni, 0.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
> Cpu1 : 6.4%us, 87.2%sy, 0.0%ni, 5.8%id, 0.0%wa, 0.6%hi, 0.0%si, 0.0%st
> Mem: 895384k total, 283568k used, 611816k free, 35492k buffers
> Swap: 1959920k total, 0k used, 1959920k free, 163044k cached
>
> PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
> 4632 root 20 0 17216 800 580 S 104 0.1 0:34.22 syslog-ng
> 28505 root 20 0 205m 11m 4024 S 6 1.3 0:21.16 X
> 28518 root 20 0 56292 5652 4492 S 1 0.6 0:01.80 fluxbox
> 1 root 20 0 3724 608 508 S 0 0.1 0:00.36 init
>
> So far I have no clue why C1E-idle in conjunction with virtual wire
> mode causes this strange behaviour.
>
> ... and I start to think about the root cause of all this.
>
> I've performed similar tests under X with the IRQ0/INT0 configuration and
> I did not see above symptoms.
So lets fall back to the IRQ0/INT0 configuration on this box.
This basically restores the dont-use-the-lapic-timer exception mechanism
that was unconditional on this box prior commit 8750bf5 ("x86: add C1E
aware idle function").
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2008-07-08 16:12:26 +02:00
/*
* HP laptops which use a DSDT reporting as HP / SB400 / 10000 ,
* which includes some code which overrides all temperature
* trip points to 16 C if the INTIN2 input of the I / O APIC
* is enabled . This input is incorrectly designated the
* ISA IRQ 0 via an interrupt source override even though
* it is wired to the output of the master 8259 A and INTIN0
* is not connected at all . Force ignoring BIOS IRQ0 pin2
* override in that cases .
*/
2008-10-06 11:59:29 +02:00
{
. callback = dmi_ignore_irq0_timer_override ,
. ident = " HP nx6115 laptop " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Hewlett-Packard " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " HP Compaq nx6115 " ) ,
} ,
} ,
x86: fix C1E && nx6325 stability problem
The problems are that, with the ACPI vs timer overring issue _fixed_,
after using the box for some time (between several seconds and 1 hour, at
random) processes get very high CPU loads (once I've got X using 107% of
the CPU, for example) and the system becomes unresponsive, as though there
were interrupts lost or something similar.
Andreas Herrman reproduced similar problems:
> Ok, now I've reproduced the stability problem.
> - Using tip/master,
> - reverting e38502eb8aa82314d5ab0eba45f50e6790dadd88 and
> - applying your patch from this posting
> http://marc.info/?l=linux-kernel&m=121539354224562&w=4
>
> Starting X, firefox, gimp, tuxpaint and doing some drawing in tuxpaint
> results in a slow system. Drawing is almost not possible anymore --
> Selections of new colors, cursors etc. is performed with huge delay
> if it's performed at all.
>
> BTW, the code sets up timer IRQ as Virtual Wire IRQ:
>
> Jul 8 14:57:58 kodscha IO-APIC (apicid-pin) 2-22, 2-23 not connected.
> Jul 8 14:57:58 kodscha ..TIMER: vector=0x30 apic1=0 pin1=2 apic2=-1 pin2=-1
> Jul 8 14:57:58 kodscha ...trying to set up timer as Virtual Wire IRQ... works.
>
> and both INT0 and INT2 of IOAPIC are masked:
>
> Jul 8 14:57:58 kodscha NR Dst Mask Trig IRR Pol Stat Dmod Deli Vect:
> Jul 8 14:57:58 kodscha 00 000 1 0 0 0 0 0 0 00
> Jul 8 14:57:58 kodscha 01 003 0 0 0 0 0 1 1 31
> Jul 8 14:57:58 kodscha 02 003 1 0 0 0 0 0 0 30
>
> I've also seen strange CPU utilization -- with syslog-ng:
>
> top - 15:33:06 up 35 min, 4 users, load average: 1.70, 0.68, 0.37
> Tasks: 64 total, 4 running, 60 sleeping, 0 stopped, 0 zombie
> Cpu0 : 0.0%us,100.0%sy, 0.0%ni, 0.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
> Cpu1 : 6.4%us, 87.2%sy, 0.0%ni, 5.8%id, 0.0%wa, 0.6%hi, 0.0%si, 0.0%st
> Mem: 895384k total, 283568k used, 611816k free, 35492k buffers
> Swap: 1959920k total, 0k used, 1959920k free, 163044k cached
>
> PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
> 4632 root 20 0 17216 800 580 S 104 0.1 0:34.22 syslog-ng
> 28505 root 20 0 205m 11m 4024 S 6 1.3 0:21.16 X
> 28518 root 20 0 56292 5652 4492 S 1 0.6 0:01.80 fluxbox
> 1 root 20 0 3724 608 508 S 0 0.1 0:00.36 init
>
> So far I have no clue why C1E-idle in conjunction with virtual wire
> mode causes this strange behaviour.
>
> ... and I start to think about the root cause of all this.
>
> I've performed similar tests under X with the IRQ0/INT0 configuration and
> I did not see above symptoms.
So lets fall back to the IRQ0/INT0 configuration on this box.
This basically restores the dont-use-the-lapic-timer exception mechanism
that was unconditional on this box prior commit 8750bf5 ("x86: add C1E
aware idle function").
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2008-07-08 16:12:26 +02:00
{
. callback = dmi_ignore_irq0_timer_override ,
. ident = " HP NX6125 laptop " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Hewlett-Packard " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " HP Compaq nx6125 " ) ,
} ,
} ,
{
. callback = dmi_ignore_irq0_timer_override ,
. ident = " HP NX6325 laptop " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Hewlett-Packard " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " HP Compaq nx6325 " ) ,
} ,
} ,
2008-10-06 11:59:29 +02:00
{
. callback = dmi_ignore_irq0_timer_override ,
. ident = " HP 6715b laptop " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Hewlett-Packard " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " HP Compaq 6715b " ) ,
} ,
} ,
2005-08-05 00:44:28 -04:00
{ }
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
dmi_check_system ( acpi_dmi_table ) ;
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 ;
}
}
2008-02-19 03:21:06 -08:00
return 0 ;
}
int __init early_acpi_boot_init ( void )
{
/*
* If acpi_disabled , bail out
* One exception : acpi = ht continues far enough to enumerate LAPICs
*/
if ( acpi_disabled & & ! acpi_ht )
return 1 ;
/*
* Process the Multiple APIC Description Table ( MADT ) , if present
*/
early_acpi_process_madt ( ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
int __init acpi_boot_init ( void )
{
2008-10-22 13:08:31 +02:00
/* those are executed after early-quirks are executed */
dmi_check_system ( acpi_dmi_table_late ) ;
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
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 ;
}
2008-12-17 16:55:18 +08:00
/* acpi=rsdt use RSDT instead of XSDT */
else if ( strcmp ( arg , " rsdt " ) = = 0 ) {
acpi_rsdt_forced = 1 ;
}
2006-09-26 10:52:32 +02:00
/* "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 ) ;
2008-06-20 16:11:20 -07:00
int __init acpi_mps_check ( void )
{
# if defined(CONFIG_X86_LOCAL_APIC) && !defined(CONFIG_X86_MPPARSE)
/* mptable code is not built-in*/
if ( acpi_disabled | | acpi_noirq ) {
printk ( KERN_WARNING " MPS support code is not built-in. \n "
" Using acpi=off or acpi=noirq or pci=noacpi "
" may have problem \n " ) ;
return 1 ;
}
# endif
return 0 ;
}
2006-09-26 10:52:32 +02:00
# 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 ;
}